### BigInt usage example: multiply and power Source: https://docs.rs/arpfloat/latest/src/arpfloat/bigint.rs.html Shows how to create BigInt values from u64, multiply them, raise to a power, and print the decimal representation. ```rust use arpfloat::BigInt; let x = BigInt::from_u64(1995); let y = BigInt::from_u64(90210); let z = x * y; let z = z.powi(10); // Prints: 3564312949426686000.... println!("{}", z.as_decimal()); ``` -------------------------------- ### Output of FP128 square root example Source: https://docs.rs/arpfloat/latest/index.html Expected output from the previous example, showing the square root of 5 in FP128 and FP64 precision. ```text fp128: 2.2360679774997896964091736687312763 fp64: 2.23606797749979 ``` -------------------------------- ### Example: Create Float with Semantics Source: https://docs.rs/arpfloat/latest/arpfloat/struct.Semantics.html Shows how to create a new Semantics with 10 exponent bits, 100 precision bits, and Positive rounding mode, then create the number 1.0 and verify its double value. ```rust use arpfloat::{Float, RoundingMode, Semantics}; // Create a new floating point semantics. let sem = Semantics::new(10, 100, RoundingMode::Positive); // Create the number 1.0 with the new semantics. let x = Float::one(sem, false); // Check that the value is correct when casting to `double`. assert_eq!(x.as_f64(), 1.0); ``` -------------------------------- ### Output of continued fraction example Source: https://docs.rs/arpfloat/latest/index.html Expected output from the continued fraction example, showing the value of ln(2) and its successive fraction approximations. ```text ln(2) = .6931471805599453094172321214581765680755001343..... 0/1 1/1 2/3 7/10 9/13 61/88 192/277 253/365 445/642 1143/1649 1588/2291 2731/3940 .... ``` -------------------------------- ### Rounding mode API example Source: https://docs.rs/arpfloat/latest/arpfloat Shows how to use the rounding mode API with `mul_with_rm` to multiply two FP128 numbers using the `NearestTiesToEven` rounding mode. ```rust use arpfloat::FP128; use arpfloat::RoundingMode::NearestTiesToEven; use arpfloat::Float; let x = Float::from_u64(FP128, 1<<53); let y = Float::from_f64(1000.0).cast(FP128); let val = Float::mul_with_rm(&x, &y, NearestTiesToEven); ``` -------------------------------- ### Module imports and Float impl start Source: https://docs.rs/arpfloat/latest/src/arpfloat/arithmetic.rs.html Imports the necessary modules and begins the implementation of arithmetic operations on the Float type. Includes the add_or_sub_normals function that handles addition and subtraction of normal numbers, following the APFloat implementation. ```rust //! This module contains the implementation of the basic arithmetic operations: //! Addition, Subtraction, Multiplication, Division. extern crate alloc; use crate::bigint::BigInt; use super::bigint::LossFraction; use super::float::{Category, Float, RoundingMode}; use core::cmp::Ordering; use core::ops::{ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign, }; impl Float { /// An inner function that performs the addition and subtraction of normal /// numbers (no NaN, Inf, Zeros). /// See Pg 247. Chapter 8. Algorithms for the Five Basic Operations. /// This implementation follows the APFloat implementation, that does not /// swap the operands. fn add_or_sub_normals( a: &Self, b: &Self, subtract: bool, ) -> (Self, LossFraction) { debug_assert_eq!(a.get_semantics(), b.get_semantics()); let sem = a.get_semantics(); let loss; let mut a = a.clone(); let mut b = b.clone(); // Align the input numbers on the same exponent. let bits = a.get_exp() - b.get_exp(); // Can transform (a-b) to (a + -b), either way, there are cases where // subtraction needs to happen. let subtract = subtract ^ (a.get_sign() ^ b.get_sign()); if subtract { // Align the input numbers. We shift LHS one bit to the left to // allow carry/borrow in case of underflow as result of subtraction. match bits.cmp(&0) { Ordering::Equal => { loss = LossFraction::ExactlyZero; } Ordering::Greater => { loss = b.shift_significand_right((bits - 1) as u64); a.shift_significand_left(1); } Ordering::Less => { loss = a.shift_significand_right((-bits - 1) as u64); b.shift_significand_left(1); } } let a_mantissa = a.get_mantissa(); let b_mantissa = b.get_mantissa(); let ab_mantissa; let mut sign = a.get_sign(); // Figure out the carry from the shifting operations that dropped // bits. let c = !loss.is_exactly_zero() as u64; let c = BigInt::from_u64(c); // Figure out which mantissa is larger, to make sure that we don't // overflow the subtraction. if a_mantissa < b_mantissa { // A < B ab_mantissa = b_mantissa - a_mantissa - c; sign = !sign; } else { // A >= B ab_mantissa = a_mantissa - b_mantissa - c; } ( Self::from_parts(sem, sign, a.get_exp(), ab_mantissa), loss.invert(), ) } else { // Handle the easy case of Add: let mut b = b.clone(); let mut a = a.clone(); if bits > 0 { loss = b.shift_significand_right(bits as u64); } else { loss = a.shift_significand_right(-bits as u64); } debug_assert!(a.get_exp() == b.get_exp()); let ab_mantissa = a.get_mantissa() + b.get_mantissa(); ( Self::from_parts(sem, a.get_sign(), a.get_exp(), ab_mantissa), loss, ) } } /// Computes a+b using the rounding mode `rm`. pub fn add_with_rm(a: &Self, b: &Self, rm: RoundingMode) -> Self { Self::add_sub(a, b, false, rm) } /// Computes a-b using the rounding mode `rm`. pub fn sub_with_rm(a: &Self, b: &Self, rm: RoundingMode) -> Self { Self::add_sub(a, b, true, rm) } fn add_sub(a: &Self, b: &Self, subtract: bool, rm: RoundingMode) -> Self { let sem = a.get_semantics(); // Table 8.2: Specification of addition for positive floating-point // data. Pg 247. match (a.get_category(), b.get_category()) { (Category::NaN, Category::Infinity) | (Category::NaN, Category::NaN) | (Category::NaN, Category::Normal) | (Category::NaN, Category::Zero) | (Category::Normal, Category::Zero) | (Category::Infinity, Category::Normal) | (Category::Infinity, Category::Zero) => a.clone(), (Category::Zero, Category::NaN) | (Category::Normal, Category::NaN) | (Category::Infinity, Category::NaN) => { ``` -------------------------------- ### string Source: https://docs.rs/arpfloat/latest/src/arpfloat/string.rs.html string ```string string ``` -------------------------------- ### Test Pentium FDIV bug Source: https://docs.rs/arpfloat/latest/src/arpfloat/arithmetic.rs.html Tests that the division of two specific large numbers produces a result starting with '1.333820449136241002', referencing the Pentium FDIV bug. Uses FP128 precision. ```rust #[cfg(feature = "std")] #[test] fn test_famous_pentium4_bug() { use crate::std::string::ToString; // https://en.wikipedia.org/wiki/Pentium_FDIV_bug use crate::FP128; let a = Float::from_u64(FP128, 4_195_835); let b = Float::from_u64(FP128, 3_145_727); let res = a / b; let result = res.to_string(); assert!(result.starts_with("1.333820449136241002")); } ``` -------------------------------- ### string Source: https://docs.rs/arpfloat/latest/src/arpfloat/string.rs.html string ```rust fn convert_to_string(&self) -> String { // In order to print decimal digits we need a minimum number of mantissa // bits for the conversion. Small floats (such as BF16) don't have // enough bits, so we cast to a larger number. if self.get_semantics().get_mantissa_len() < 16 { use crate::FP32; return self.cast(FP32).to_string(); } let result = if self.get_sign() { "-" } else { "" }; let mut result: String = result.to_string(); let body: String = match self.get_category() { super::float::Category::Infinity => "Inf".to_string(), super::float::Category::NaN => "NaN".to_string(), super::float::Category::Normal => self.convert_normal_to_string(), super::float::Category::Zero => "0.0".to_string(), }; result.push_str(&body); result } ``` -------------------------------- ### string Source: https://docs.rs/arpfloat/latest/src/arpfloat/string.rs.html string ```rust impl Display for Float { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{}", self.convert_to_string()) } } ``` -------------------------------- ### string Source: https://docs.rs/arpfloat/latest/src/arpfloat/string.rs.html string ```rust impl RoundingMode { pub fn as_string(&self) -> &str { match self { RoundingMode::None => "None", RoundingMode::NearestTiesToEven => "NearestTiesToEven", RoundingMode::NearestTiesToAway => "NearestTiesToAway", RoundingMode::Zero => "Zero", RoundingMode::Positive => "Positive", RoundingMode::Negative => "Negative", } } } ``` -------------------------------- ### string Source: https://docs.rs/arpfloat/latest/src/arpfloat/string.rs.html string ```rust impl Display for Semantics { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, "(exponent:{} precision:{} rm:{})", self.get_exponent_len(), self.get_precision(), self.get_rounding_mode().as_string() ) } } ``` -------------------------------- ### string Source: https://docs.rs/arpfloat/latest/src/arpfloat/string.rs.html string ```rust #[cfg(feature = "std")] mod from { use core::fmt::{Debug, Display}; use std::error::Error; use crate::{BigInt, Float, Semantics, FP64}; impl Float { /// Try to construct a Float instance with semantics 'sem' from the /// string 'value'. Note that the operation of conversion might lose /// precision. If you care about precision you might want to use a /// higher precision float and downcast. pub fn try_from_str( value: &str, sem: Semantics, ) -> Result { // Handle the empty case. if value.is_empty() { return Err(ParseError(ParseErrorKind::InputEmpty)); } // Handle the plus or minus in front of the number. let chars = value.as_bytes(); let (sign, skip) = if chars[0] == b'-' || chars[0] == b'+' { (chars[0] == b'-', 1) } else { (false, 0) }; let value = &value[skip..]; // Handle Nan. if value.eq_ignore_ascii_case("nan") { return Ok(Self::nan(sem, sign)); } // Handle Inf. if value.eq_ignore_ascii_case("inf") { return Ok(Self::inf(sem, sign)); } // Start handling the non trivial cases. let l_r = value.split_once('.'); // Handle cases where we have no `.` and as such no mantissa. if l_r.is_none() { // No period. Just parse the integer. let ((num, _), exp_num) = parse_with_exp(value)?; let mut num = Float::from_bigint(sem, num); // Shift the number according to the exponent (in decimal). if let Some(exp) = exp_num { if exp >= 0 { num *= Float::from_bigint( sem, BigInt::from_u64(10).powi(exp as u64), ); } else { num /= Float::from_bigint( sem, BigInt::from_u64(10).powi((-exp) as u64), ); } } num.set_sign(sign); return Ok(num); } } } } ``` -------------------------------- ### string Source: https://docs.rs/arpfloat/latest/src/arpfloat/string.rs.html string ```rust impl Display for BigInt { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{}", self.as_binary()) } } ``` -------------------------------- ### grow and shrink methods Source: https://docs.rs/arpfloat/latest/src/arpfloat/bigint.rs.html grow ensures at least 'size' words exist by pushing zeros. shrink removes leading zero words while keeping at least two words. ```rust /// Ensure that there are at least 'size' words in the bigint. pub fn grow(&mut self, size: usize) { for _ in self.len()..size { self.parts.push(0); } } /// Remove the leading zero words from the bigint. fn shrink(&mut self) { while self.len() > 2 && self.parts[self.len() - 1] == 0 { self.parts.pop(); } } ``` -------------------------------- ### Convert floating point numbers to Continued Fractions Source: https://docs.rs/arpfloat/latest/index.html Demonstrates converting the natural logarithm of 2 to a continued fraction approximation using the as_fraction method. ```rust use arpfloat::{Float, FP256, RoundingMode}; let ln = Float::ln2(FP256); println!("ln(2) = {}", ln); for i in 1..20 { let (p,q) = ln.as_fraction(i); println!("{}/{}", p.as_decimal(), q.as_decimal()); } ``` -------------------------------- ### from_i64 Source: https://docs.rs/arpfloat/latest/arpfloat/struct.Float.html Loads a signed 64-bit integer into a Float. ```APIDOC ## from_i64 ### Description Load the integer `val` into the float. Notice that the number may overflow or rounded. ### Method N/A (Rust function) ### Parameters - **sem** (`Semantics`) - Required - The semantics of the float. - **val** (`i64`) - Required - The integer value to load. ### Returns - **Self** - The resulting Float. ``` -------------------------------- ### as_fraction method implementation Source: https://docs.rs/arpfloat/latest/src/arpfloat/operations/frac.rs.html Implements Float::as_fraction, which converts a Float to a continued fraction (a0 + 1/(a1 + ...)) using n iterations. Returns (0, 0) for Inf and NaN, and (0, 1) for zero. The algorithm is based on 'Elementary Functions: Algorithms and Implementation' section 9.3.1. ```rust //! This module contains the implementation of methods that compute continued //! fraction. use crate::{bigint::BigInt, Float}; impl Float { /// Convert the number to a Continued Fraction of two integers. /// The fraction is computed using 'n' iterations of the form: /// a0 + 1/(a1 + 1/(a2 + 1/( ... ))). /// This method discards the sign, and returns (0, 0) for Inf and NaN. pub fn as_fraction(&self, n: usize) -> (BigInt, BigInt) { if self.is_zero() { return (BigInt::zero(), BigInt::one()); // Zero. } else if self.is_inf() || self.is_nan() { return (BigInt::zero(), BigInt::zero()); // Invalid. } // Algorithm from: // Elementary Functions: Algorithms and Implementation // 9.3.1 A few basic notions on continued fractions - Page 180. extern crate alloc; use alloc::vec::Vec; let sem = self.get_semantics(); let rm = sem.get_rounding_mode(); let one = Self::one(sem, false); let mut real = self.clone(); let mut a: Vec = Vec::new(); for _ in 0..n.max(2) { let int = real.trunc(); a.push(int.convert_normal_to_integer(rm)); real = &one / (real - int); } let one = BigInt::one(); let mut p = (&one + &(&a[0] * &a[1]), a[0].clone()); let mut q = (a[1].clone(), one); if n < 2 { return (p.1, q.1); } for elem in a.iter().skip(2) { p = (&p.1 + &(elem * &p.0), p.0); q = (&q.1 + &(elem * &q.0), q.0); } (p.0, q.0) } } ``` -------------------------------- ### Log and exponential functions implementation Source: https://docs.rs/arpfloat/latest/src/arpfloat/operations/exp.rs.html This code defines the log and exp functions for the Float type, including Taylor series and range reduction methods. It handles special cases and uses a loop for convergence. ```rust //! This module contains the implementation of log- and exp-related methods. //! use crate::RoundingMode; use crate::float::Float; impl Float { /// Computes the taylor series, centered around 1, and valid in [0..2]. /// z = (x - 1)/(x + 1) /// log(x) = 2 (z + z^3/3 + z^5/5 + z^7/7 ... ) fn log_taylor(x: &Self) -> Self { use RoundingMode::None as rm; let sem = x.get_semantics(); let one = Self::one(sem, false); let up = Float::sub_with_rm(x, &one, rm); let down = Float::add_with_rm(x, &one, rm); let z = Float::div_with_rm(&up, &down, rm); let z2 = z.sqr(); let mut top = z; let mut sum = Self::zero(sem, false); let mut prev = Self::one(sem, true); for i in 0..50 { if prev == sum { break; // Stop if we are not making progress. } prev = sum.clone(); let bottom = &Self::from_u64(sem, i * 2 + 1); let elem = Float::div_with_rm(&top, bottom, rm); sum = Float::add_with_rm(&sum, &elem, rm); // Prepare the next iteration. top = Float::mul_with_rm(&top, &z2, rm); } sum.scale(1, RoundingMode::Zero) } /// Reduce the range of 'x' with the identity: /// ln(x) = ln(sqrt(x)^2) = 2 * ln(sqrt(x)) and /// ln(x) = -ln(1/x) fn log_range_reduce(x: &Self) -> Self { use RoundingMode::NearestTiesToEven as even; let sem = x.get_semantics(); let up = Self::from_f64(1.001).cast(sem); let one = Self::from_u64(sem, 1); if x > &up { let sx = x.sqrt(); return Self::log_range_reduce(&sx).scale(1, even); } if x < &one { let re = Float::div_with_rm(&one, x, RoundingMode::None); return Self::log_range_reduce(&re).neg(); } Self::log_taylor(x) } /// Computes logarithm of 'x'. pub fn log(&self) -> Self { use RoundingMode::None as rm; let sem = self.get_semantics(); //Fast Logarithm function for Arbitrary Precision number, // by Henrik Vestermark. // Handle all of the special cases: if !self.is_normal() || self.is_negative() { return Self::nan(sem, self.get_sign()); } let orig_sem = self.get_semantics(); let sem = orig_sem.grow_log(10).increase_exponent(10); let x = &self.cast_with_rm(sem, rm); Self::log_range_reduce(x).cast_with_rm(orig_sem, rm) } } #[test] fn test_log() { use crate::FP128; let x = Float::from_f64(0.1).cast(FP128).log(); assert_eq!(x.as_f64(), -2.3025850929940455); for x in [ 0.1, 0.5, 2.3, 4.5, 9.8, 11.2, 15.2, 91.2, 102.2, 192.4, 1024.2, 90210.2, ] { let lhs = Float::from_f64(x).cast(FP128).log().as_f64(); let rhs = x.ln(); assert_eq!(lhs, rhs); } } impl Float { /// Computes the taylor series: /// exp(x) = 1 + x/1! + x^2/2! + x^3/3! ... fn exp_taylor(x: &Self) -> Self { let sem = x.get_semantics(); use crate::bigint::BigInt; let mut top = Self::one(sem, false); let mut bottom = BigInt::one(); let mut sum = Self::zero(sem, false); let mut prev = Self::one(sem, true); for k in 1..50 { if prev == sum { break; // Stop if we are not making progress. } prev = sum.clone(); let elem = &top / &Self::from_bigint(sem, bottom.clone()); sum += elem; // Prepare the next iteration. bottom *= BigInt::from_u64(k); top = &top * x; } sum } /// Reduce the range of 'x' with the identity: /// e^x = (e^(x/2))^2 fn exp_range_reduce(x: &Self) -> Self { let sem = x.get_semantics(); let one = Self::from_u64(sem, 1); if x > &one { let sx = x.scale(-3, RoundingMode::Zero); let esx = Self::exp_range_reduce(&sx); return esx.sqr().sqr().sqr(); } Self::exp_taylor(x) } /// Computes exponential function `e^self`. pub fn exp(&self) -> Self { let sem = self.get_semantics(); // Handle all of the special cases: if self.is_zero() { return Self::one(sem, false); } else if !self.is_normal() { return Self::nan(sem, self.get_sign()); } ``` -------------------------------- ### arpfloat utils.rs: mask, Lfsr, and mul_part helpers Source: https://docs.rs/arpfloat/latest/src/arpfloat/utils.rs.html The complete source of arpfloat's utils.rs module, containing helper functions and test helpers. It defines mask(), get_special_test_values(), the Lfsr struct with its Iterator implementation, and the mul_part() function, along with tests for each. The Lfsr is used as a random number generator for tests, and mul_part() splits a 64-bit multiplication into low and high parts. ```rust //! This file contains simple helper functions and test helpers. /// Returns a mask full of 1s, of `b` bits. pub fn mask(b: usize) -> usize { (1 << (b)) - 1 } #[test] fn test_masking() { assert_eq!(mask(0), 0x0); assert_eq!(mask(1), 0x1); assert_eq!(mask(8), 255); } #[cfg(feature = "std")] #[allow(dead_code)] /// Returns list of interesting values that various tests use to catch edge cases. pub fn get_special_test_values() -> [f64; 22] { [ -f64::NAN, f64::NAN, f64::INFINITY, f64::NEG_INFINITY, f64::EPSILON, -f64::EPSILON, 0.000000000000000000000000000000000000001, f64::MIN, f64::MAX, std::f64::consts::PI, std::f64::consts::LN_2, std::f64::consts::SQRT_2, std::f64::consts::E, 0.0, -0.0, 10., -10., -0.00001, 0.1, 355. / 113., -1.0, -1.1, ] } // Linear-feedback shift register. We use this as a random number generator for // tests. pub struct Lfsr { state: u32, } impl Default for Lfsr { fn default() -> Self { Self::new() } } impl Lfsr { /// Generate a new LFSR number generator. pub fn new() -> Lfsr { Lfsr { state: 0x13371337 } } /// Generate a new LFSR number generator that starts with a specific state. pub fn new_with_seed(seed: u32) -> Lfsr { Lfsr { state: 0x13371337 ^ seed, } } pub fn next(&mut self) { let a = (self.state >> 24) & 1; let b = (self.state >> 23) & 1; let c = (self.state >> 22) & 1; let d = (self.state >> 17) & 1; let n = a ^ b ^ c ^ d ^ 1; self.state <<= 1; self.state |= n; } fn get(&mut self) -> u32 { let mut res: u32 = 0; for _ in 0..32 { self.next(); res <<= 1; res ^= self.state & 0x1; } res } pub fn get64(&mut self) -> u64 { ((self.get() as u64) << 32) | self.get() as u64 } } // Implement `Iterator` for `Lfsr`. impl Iterator for Lfsr { type Item = u64; fn next(&mut self) -> Option { Some(self.get64()) } } #[test] fn test_lfsr_balance() { let mut lfsr = Lfsr::new(); // Count the number of items, and the number of 1s. let mut items = 0; let mut ones = 0; for _ in 0..10000 { let mut u = lfsr.get(); for _ in 0..32 { items += 1; ones += u & 1; u >>= 1; } } // Make sure that we have around 50% 1s and 50% zeros. assert!((ones as f64) < (0.55 * items as f64)); assert!((ones as f64) > (0.45 * items as f64)); } #[test] fn test_repetition() { let mut lfsr = Lfsr::new(); let first = lfsr.get(); let second = lfsr.get(); // Make sure that the items don't repeat themselves too frequently. for _ in 0..30000 { assert_ne!(first, lfsr.get()); assert_ne!(second, lfsr.get()); } } // Multiply a and b, and return the (low, high) parts. #[allow(dead_code)] fn mul_part(a: u64, b: u64) -> (u64, u64) { let half_bits = u64::BITS / 2; let half_mask = (1 << half_bits) - 1; let a_lo = a & half_mask; let a_hi = a >> half_bits; let b_lo = b & half_mask; let b_hi = b >> half_bits; let ab_hi = a_hi * b_hi; let ab_mid = a_hi * b_lo; let ba_mid = b_hi * a_lo; let ab_low = a_lo * b_lo; let carry = ((ab_mid & half_mask) + (ba_mid & half_mask) + (ab_low >> half_bits)) >> half_bits; let low = (ab_mid << half_bits) .overflowing_add(ba_mid << half_bits) .0 .overflowing_add(ab_low) .0; let high = (ab_hi + (ab_mid >> half_bits) + (ba_mid >> half_bits)) + carry; (low, high) } #[test] fn test_mul_parts() { use super::utils::Lfsr; let mut lfsr = Lfsr::new(); for _ in 0..500 { let v0 = lfsr.get64(); let v1 = lfsr.get64(); let res = mul_part(v0, v1); let full = v0 as u128 * v1 as u128; assert_eq!(full as u64, res.0); assert_eq!((full >> 64) as u64, res.1); } } ``` -------------------------------- ### Implement arithmetic operations on Float (powi, sqr, sqrt, abs, max, min) Source: https://docs.rs/arpfloat/latest/src/arpfloat/operations/functions.rs.html This snippet contains the full implementation of arithmetic operations for the Float type, including powi, sqr, sqrt, abs, max, and min. It uses the Newton-Raphson method for sqrt and handles special values like zero, NaN, infinity, and negative numbers. The powi method uses a binary exponentiation algorithm. ```rust //! This module contains the implementation of several arithmetic operations. use crate::RoundingMode; use crate::float::Float; impl Float { /// Return this number raised to the power of 'n'. pub fn powi(&self, mut n: u64) -> Self { let sem = self.get_semantics().increase_precision(2); let mut elem = Self::one(sem, false); // This algorithm is similar to binary conversion. Each bit in 'n' // represents a power-of-two number, like 1,2,4,8 ... We know how to // generate numbers to the power of an even number by squaring the // number log2 times. So, we just multiply all of the numbers together // to get the result. This is like converting a binary number to integer // except that instead of adding we multiply the values. let mut val = self.cast(sem); while n > 0 { if n & 1 == 1 { elem *= &val; } val *= &val.clone(); n >>= 1; } elem.cast(self.get_semantics()) } /// Calculates the power of two. pub fn sqr(&self) -> Self { self.powi(2) } /// Calculates the square root of the number. pub fn sqrt(&self) -> Self { let sem = self.get_semantics(); if self.is_zero() { return self.clone(); // (+/-) zero } else if self.is_nan() || self.is_negative() { return Self::nan(sem, self.get_sign()); // (-/+)Nan, -Number. } else if self.is_inf() { return self.clone(); // Inf+. } let target = self.clone(); let two = Self::from_u64(sem, 2); // Start the search at max(2, x). let mut x = if target < two { two } else { target.clone() }; let mut prev = x.clone(); // Use the Newton Raphson method. loop { x += &target / &x; x = x.scale(-1, RoundingMode::NearestTiesToEven); // Stop when value did not change or regressed. if prev < x || x == prev { return x; } prev = x.clone(); } } /// Returns the absolute value of this float. pub fn abs(&self) -> Self { let mut x = self.clone(); x.set_sign(false); x } /// Returns the greater of self and `other`. pub fn max(&self, other: &Self) -> Self { if self.is_nan() { return other.clone(); } else if other.is_nan() { return self.clone(); } else if self.get_sign() != other.get_sign() { return if self.get_sign() { other.clone() } else { self.clone() }; // Handle (+-)0. } if self > other { self.clone() } else { other.clone() } } /// Returns the smaller of self and `other`. pub fn min(&self, other: &Self) -> Self { if self.is_nan() { return other.clone(); } else if other.is_nan() { return self.clone(); } else if self.get_sign() != other.get_sign() { return if self.get_sign() { self.clone() } else { other.clone() }; // Handle (+-)0. } if self > other { other.clone() } else { self.clone() } } } ``` -------------------------------- ### from_u64 Source: https://docs.rs/arpfloat/latest/arpfloat/struct.Float.html Loads an unsigned 64-bit integer into a Float. ```APIDOC ## from_u64 ### Description Load the integer `val` into the float. Notice that the number may overflow, or rounded to the nearest even integer. ### Method N/A (Rust function) ### Parameters - **sem** (`Semantics`) - Required - The semantics of the float. - **val** (`u64`) - Required - The integer value to load. ### Returns - **Self** - The resulting Float. ``` -------------------------------- ### Float::pi, Float::e, and Float::ln2 implementations with tests Source: https://docs.rs/arpfloat/latest/src/arpfloat/operations/constants.rs.html The source code for the constants module, including the pi, e, and ln2 methods and their unit tests. The pi method uses Brent's algorithm, e uses Euler's continued fraction, and ln2 uses a series. Tests are gated behind the 'std' feature and compare results with standard library constants. ```rust //! This module contains the implementation of methods that compute mathematical //! constants. //! use crate::RoundingMode; use crate::{Float, Semantics}; impl Float { /// Computes pi. pub fn pi(sem: Semantics) -> Self { // Algorithm description in Pg 246: // Fast Multiple-Precision Evaluation of Elementary Functions // by Richard P. Brent. // Increase the precision, because the arithmetic operations below // require rounding, so if we want to get the accurate results we need // to operate with increased precision. let orig_sem = sem; let sem = sem.grow_log(4); use RoundingMode::NearestTiesToEven as rm; let one = Self::from_i64(sem, 1); let two = Self::from_i64(sem, 2); let four = Self::from_i64(sem, 4); let mut a = one.clone(); let mut b = one.clone() / two.sqrt(); let mut t = one.clone() / four; let mut x = one; while a != b { let y = a.clone(); a = (&a + &b).scale(-1, rm); b = (&b * &y).sqrt(); t -= &x * (&a - &y).sqr(); x = x.scale(1, rm); } (a.sqr() / t).cast(orig_sem) } /// Computes e. pub fn e(sem: Semantics) -> Self { let orig_sem = sem; let sem = sem.increase_precision(1); let one = Self::one(sem, false); let mut term = one.clone(); // Use Euler's continued fraction, which is a simple series. let iterations: i64 = (sem.get_exponent_len() * 2) as i64; for i in (1..iterations).rev() { let v = Self::from_i64(sem, i); term = &v + &v / &term; } (one / term + 2).cast(orig_sem) } /// Compute log(2). pub fn ln2(sem: Semantics) -> Self { use RoundingMode::None as rm; let sem2 = sem.increase_precision(8); // Represent log(2) using the sum 1/k*2^k let one = Self::one(sem2, false); let mut sum = Self::zero(sem2, false); let mut prev = Self::inf(sem2, true); for k in 1..500 { let k2 = Self::from_u64(sem2, 1).scale(k, rm); let k = Self::from_u64(sem2, k as u64); let kk2 = &Float::mul_with_rm(&k, &k2, rm); let term = Float::div_with_rm(&one, kk2, rm); sum = Float::add_with_rm(&sum, &term, rm); if prev == sum { break; } prev = sum.clone(); } sum.cast(sem) } } #[cfg(feature = "std")] #[test] fn test_pi() { use crate::FP32; use crate::FP64; assert_eq!(Float::pi(FP64).as_f64(), std::f64::consts::PI); assert_eq!(Float::pi(FP32).as_f32(), std::f32::consts::PI); } #[cfg(feature = "std")] #[test] fn test_e() { use crate::FP32; use crate::FP64; assert_eq!(Float::e(FP64).as_f64(), std::f64::consts::E); assert_eq!(Float::e(FP32).as_f32(), std::f32::consts::E); } #[cfg(feature = "std")] #[test] fn test_ln2() { use crate::FP64; assert_eq!(Float::ln2(FP64).as_f64(), std::f64::consts::LN_2); } ``` -------------------------------- ### Scale method implementation Source: https://docs.rs/arpfloat/latest/src/arpfloat/operations/functions.rs.html Implementation of the scale method on Float, which adds or subtracts to the exponent, scaling by 2^exp. It handles non-normal numbers by returning a clone and uses the specified rounding mode. ```rust impl Float { /// Similar to 'scalbln'. Adds or subtracts to the exponent of the number, /// and scaling it by 2^exp. pub fn scale(&self, scale: i64, rm: RoundingMode) -> Self { use crate::bigint::LossFraction; if !self.is_normal() { return self.clone(); } let mut r = Self::from_parts( self.get_semantics(), self.get_sign(), self.get_exp() + scale, self.get_mantissa(), ); r.normalize(rm, LossFraction::ExactlyZero); r } ``` -------------------------------- ### Test loading and storing all f32 values Source: https://docs.rs/arpfloat/latest/src/arpfloat/cast.rs.html Iterates over all possible f32 bit patterns (except NaN) and verifies that loading and storing preserves the value. ```rust // Try to load and store normals and denormals. for i in 0..(1u64 << 16) { let in_f = f32::from_bits((i << 10) as u32); let fp_f = Float::from_f32(in_f); let out_f = fp_f.as_f32(); assert_eq!(in_f.is_nan(), out_f.is_nan()); assert_eq!(in_f.is_infinite(), out_f.is_infinite()); assert!(in_f.is_nan() || (in_f.to_bits() == out_f.to_bits())); } ``` -------------------------------- ### Test casting from i64 to f64 for FP16 Source: https://docs.rs/arpfloat/latest/src/arpfloat/cast.rs.html Verifies that casting various i64 values to FP16 and then to f64 produces expected results, including saturation to infinity for large values. ```rust assert_eq!(Float::from_i64(FP16, 0).as_f64(), 0.); assert_eq!(Float::from_i64(FP16, 65500).as_f64(), 65504.0); assert_eq!(Float::from_i64(FP16, 65504).as_f64(), 65504.0); assert_eq!(Float::from_i64(FP16, 65519).as_f64(), 65504.0); assert_eq!(Float::from_i64(FP16, 65520).as_f64(), f64::INFINITY); assert_eq!(Float::from_i64(FP16, 65536).as_f64(), f64::INFINITY); ``` -------------------------------- ### from_f32 Source: https://docs.rs/arpfloat/latest/arpfloat/struct.Float.html Loads a native f32 value into a Float. ```APIDOC ## from_f32 ### Description Loads and converts a native fp32 value. Notice that the number may overflow or rounded (see cast and cast_with_rm). ### Method N/A (Rust function) ### Parameters - **float** (`f32`) - Required - The f32 value to load. ### Returns - **Self** - The resulting Float. ``` -------------------------------- ### Test for Simple Division (test_div_simple) Source: https://docs.rs/arpfloat/latest/src/arpfloat/arithmetic.rs.html Tests division of two f64 values by converting them to Float, performing division with rounding to nearest ties to even, and asserting the result matches the f64 division. ```rust #[test] fn test_div_simple() { let a: f64 = 1.0; let b: f64 = 7.0; let af = Float::from_f64(a); let bf = Float::from_f64(b); let cf = Float::div_with_rm(&af, &bf, RoundingMode::NearestTiesToEven); let r0 = cf.as_f64(); let r1: f64 = a / b; assert_eq!(r0, r1); } ```