#![allow(non_snake_case)]
use crate::fixed_point::domains::symbolic::rational::RationalNumber;
#[allow(unused_imports)]
use crate::fixed_point::domains::binary_fixed::I256;
#[allow(unused_imports)]
use crate::fixed_point::domains::binary_fixed::I512;
#[cfg(feature = "rebuild-tables")]
include!(concat!(env!("OUT_DIR"), "/mathematical_constants.rs"));
#[cfg(not(feature = "rebuild-tables"))]
include!("../../../../generated_tables/mathematical_constants.rs");
pub struct SymbolicConstants;
impl SymbolicConstants {
pub fn pi_high_precision() -> RationalNumber {
let (num_words, den_words) = MathematicalConstants::PI();
let num = I512::from_words(num_words);
let den = I512::from_words(den_words);
RationalNumber::from_i512_pair(num, den)
}
pub fn e_high_precision() -> RationalNumber {
let (num_words, den_words) = MathematicalConstants::E();
let num = I512::from_words(num_words);
let den = I512::from_words(den_words);
RationalNumber::from_i512_pair(num, den)
}
pub fn sqrt_2_high_precision() -> RationalNumber {
let (num_words, den_words) = MathematicalConstants::SQRT_2();
let num = I512::from_words(num_words);
let den = I512::from_words(den_words);
RationalNumber::from_i512_pair(num, den)
}
pub fn ln_2_high_precision() -> RationalNumber {
let (num_words, den_words) = MathematicalConstants::LN_2();
let num = I512::from_words(num_words);
let den = I512::from_words(den_words);
RationalNumber::from_i512_pair(num, den)
}
pub fn golden_ratio_high_precision() -> RationalNumber {
let (num_words, den_words) = MathematicalConstants::GOLDEN_RATIO();
let num = I512::from_words(num_words);
let den = I512::from_words(den_words);
RationalNumber::from_i512_pair(num, den)
}
pub fn sqrt_3_high_precision() -> RationalNumber {
let (num_words, den_words) = MathematicalConstants::SQRT_3();
let num = I512::from_words(num_words);
let den = I512::from_words(den_words);
RationalNumber::from_i512_pair(num, den)
}
pub fn euler_gamma_high_precision() -> RationalNumber {
let (num_words, den_words) = MathematicalConstants::EULER_GAMMA();
RationalNumber::from_i512_pair(I512::from_words(num_words), I512::from_words(den_words))
}
pub fn ln_10() -> RationalNumber {
let (num_words, den_words) = MathematicalConstants::LN_10();
RationalNumber::from_i512_pair(I512::from_words(num_words), I512::from_words(den_words))
}
}
#[cfg(test)]
mod precision_tests {
use super::*;
use num_bigint::BigInt;
fn big(words: [u64; 8]) -> BigInt {
let mut v = BigInt::from(0);
for w in words.iter().rev() { v = (v << 64usize) + BigInt::from(*w); }
v
}
#[test]
fn constants_carry_380_bits() {
let cases: [(&str, ([u64; 8], [u64; 8]), &str); 10] = [
("PI", MathematicalConstants::PI(), "3141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647"),
("E", MathematicalConstants::E(), "2718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921"),
("SQRT_2", MathematicalConstants::SQRT_2(), "1414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641572735013846230912297024"),
("LN_2", MathematicalConstants::LN_2(), "693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687542001481020570685733"),
("PHI", MathematicalConstants::PHI(), "1618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137484754088075386891752"),
("LN_10", MathematicalConstants::LN_10(), "2302585092994045684017991454684364207601101488628772976033327900967572609677352480235997205089598298341967784042286248633"),
("SQRT_3", MathematicalConstants::SQRT_3(), "1732050807568877293527446341505872366942805253810380628055806979451933016908800037081146186757248575675626141415406703029"),
("SQRT_5", MathematicalConstants::SQRT_5(), "2236067977499789696409173668731276235440618359611525724270897245410520925637804899414414408378782274969508176150773783504"),
("EULER_GAMMA", MathematicalConstants::EULER_GAMMA(), "577215664901532860606512090082402431042159335939923598805767234884867726777664670936947063291746749514631447249807082480"),
("E_SQUARED", MathematicalConstants::E_SQUARED(), "7389056098930650227230427460575007813180315570551847324087127822522573796079057763384312485079121794773753161265478866123"),
];
let scale = BigInt::from(10).pow(120u32);
for (name, (n, d), digits) in cases {
let (n, d) = (big(n), big(d));
let dd: BigInt = digits.parse().unwrap();
let diff = &n * &scale - &dd * &d;
let diff = if diff < BigInt::from(0) { -diff } else { diff };
let bound = (&d * &scale >> 380usize) + &d;
assert!(diff <= bound, "{name}: rational farther than 2^-380 from its value");
}
}
}