Is there a math library similar to python mpmath in rust language?

want to build some mathematical tools, but rust doesn't seem to be able to support floating point numbers larger than f64. the f128 implementation of the new standard library is just garbage to the point of being offensive. so I want to find a math library similar to python mpmath.

import time
import mpmath

# Define a function to calculate π using the Bellard formula
def bellard_pi(p):
    mpmath.mp.dps = 130  # Set decimal precision to 130 digits
    pi = mpmath.mpf(0)   # Initialize π as 0 using mpmath high-precision float
    sixteen_power_k = mpmath.mpf(1)  # Initialize 16^k
    for k in range(p):  # Iterate over p terms
        # Calculate the current term using mpmath operations and reduced intermediate growth
        term = (mpmath.mpf(4) / (mpmath.mpf(8) * k + mpmath.mpf(1)) -
                mpmath.mpf(2) / (mpmath.mpf(8) * k + mpmath.mpf(4)) -
                mpmath.mpf(1) / (mpmath.mpf(8) * k + mpmath.mpf(5)) -
                mpmath.mpf(1) / (mpmath.mpf(8) * k + mpmath.mpf(6)))
        pi += term * sixteen_power_k  # Add the current term to π
        sixteen_power_k /= mpmath.mpf(16)  # Update 16^k for the next iteration
    return pi  # Return the calculated π value

# Measure the time taken for each method
start_time = time.time()  # Record start time
bellard_pi_value = bellard_pi(256)  # Calculate π using 256 terms of Bellard formula
bellard_time = time.time() - start_time  # Calculate time taken

# Print results
print("\nBellard Formula:")
print(f"Value: {bellard_pi_value}")  # Output the calculated π value
print(f"Time: {bellard_time:.6f} seconds")  # Output the time taken

# Calculate relative errors
bellard_error = abs(bellard_pi_value - mpmath.pi) / mpmath.pi * 100  # Relative error for Bellard formula

# Print relative error results
print("\nRelative Errors:")
print(f"Bellard Formula: {mpmath.nstr(bellard_error, 6)}%")  # Output relative error

It would be ideal if it could be implemented as intuitively as Bellard's formula.

The f128 primitive type in the standard library is still work in progress. From the docs:

If you have ideas and spare time on your hands, I'm sure you're welcome to help out: Tracking Issue for `f16` and `f128` float types · Issue #116909 · rust-lang/rust · GitHub

1 Like

Arbitrary precision arithmetic is probably the keyword you are looking for. Stroll on this crates.io page to pick whatever you want.

For example,

use bigdecimal::BigDecimal;
use std::time::Instant;

fn bellard_pi(terms: usize) -> BigDecimal {
    let mut pi = BigDecimal::from(0);
    let mut sixteen_power_k = BigDecimal::from(1);

    for k in 0..terms {
        // Calculate each term of the Bellard formula
        let term = BigDecimal::from(4) / (BigDecimal::from(8 * k as u64 + 1)) -
                    BigDecimal::from(2) / (BigDecimal::from(8 * k as u64 + 4)) -
                    BigDecimal::from(1) / (BigDecimal::from(8 * k as u64 + 5)) -
                    BigDecimal::from(1) / (BigDecimal::from(8 * k as u64 + 6));

        pi += term * &sixteen_power_k; // Add the current term to π
        sixteen_power_k = sixteen_power_k / BigDecimal::from(16); // Update 16^k for next iteration
    }

    pi // Return the calculated π value
}

fn main() {
    let start_time = Instant::now(); // Record start time
    let bellard_pi_value = bellard_pi(256); // Calculate π using 256 terms of Bellard formula
    let bellard_time = start_time.elapsed(); // Calculate time taken
    
    // Print results
    println!("\nBellard Formula:");
    println!("Value: {}", bellard_pi_value); // Output the calculated π value
    println!("Time: {:?}", bellard_time); // Output the time taken
}

and run it with RUST_BIGDECIMAL_DEFAULT_PRECISION=1000 cargo run

1 Like

If I have time off from work, I'll come and help.

At present, the simplest and most comprehensive implementation of F128 floating point numbers is the Python implementation. I think this is a reasonable reference direction.

Currently I am testing the robustness of BigDecimal and Malachite, thank you for your response.

rug is a wrapper around the standard GNU libraries, so it's complete but full GPL.

dashu implements a bunch of big number representations, including floats in dashu-float. These implement the popular "vocabulary" crate num-traits so if you have an implementation over those you can port to any other representation.

I took a stab, but I got a value of pi of 11... I think I took a wrong turn somewhere :sweat_smile:

2 Likes

A simple implementation of f64 floating point.