use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use num_bigint::{BigInt, Sign};
use num_rational::BigRational;
use num_traits::{One, ToPrimitive, Signed, Zero};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum DeploymentProfile {
Embedded, Balanced, Scientific, Custom,
}
#[derive(Debug, Clone)]
struct PrecisionConfig {
target_decimal_places: u8,
profile_name: &'static str,
table_format: &'static str, }
impl PrecisionConfig {
fn for_profile(profile: DeploymentProfile) -> Self {
match profile {
DeploymentProfile::Embedded => PrecisionConfig {
target_decimal_places: 19,
profile_name: "embedded",
table_format: "Q64.64",
},
DeploymentProfile::Balanced => PrecisionConfig {
target_decimal_places: 38,
profile_name: "balanced",
table_format: "Q128.128",
},
DeploymentProfile::Scientific => PrecisionConfig {
target_decimal_places: 77,
profile_name: "scientific",
table_format: "Q256.256",
},
DeploymentProfile::Custom => {
let custom_precision = env::var("GMATH_MAX_DECIMAL_PRECISION")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(38);
let table_format = if custom_precision <= 19 {
"Q64.64"
} else if custom_precision <= 38 {
"Q128.128"
} else {
"Q256.256"
};
PrecisionConfig {
target_decimal_places: custom_precision,
profile_name: "custom",
table_format,
}
}
}
}
}
fn detect_deployment_profile() -> DeploymentProfile {
if let Ok(profile_str) = env::var("GMATH_PROFILE") {
match profile_str.to_lowercase().as_str() {
"embedded" => return DeploymentProfile::Embedded,
"balanced" => return DeploymentProfile::Balanced,
"scientific" => return DeploymentProfile::Scientific,
_ => {}
}
}
if env::var("CARGO_FEATURE_EMBEDDED_MINIMAL").is_ok() || env::var("CARGO_FEATURE_EMBEDDED").is_ok() {
DeploymentProfile::Embedded
} else if env::var("CARGO_FEATURE_SCIENTIFIC").is_ok() {
DeploymentProfile::Scientific
} else if env::var("CARGO_FEATURE_BALANCED").is_ok() {
DeploymentProfile::Balanced
} else if env::var("CARGO_FEATURE_FAST").is_ok() {
DeploymentProfile::Custom
} else {
DeploymentProfile::Embedded
}
}
#[allow(dead_code)]
mod hardcoded_constants {
pub mod strings {
pub const PI: &str = "3.141592653589793238462643383279502884197169399375105820974944592307816406286208";
pub const E: &str = "2.718281828459045235360287471352662497757247093699959574966967627724076630353547";
pub const SQRT_2: &str = "1.414213562373095048801688724209698078569671875376948073176679737990732478462107";
pub const LN_2: &str = "0.693147180559945309417232121458176568075500134360255254120680009493393621969694";
pub const PHI: &str = "1.618033988749894848204586834365638117720309179805762862135448622705260462818902";
pub const LN_10: &str = "2.302585092994045684017991454684364207601101488628772976033327900967572609677352";
pub const SQRT_3: &str = "1.732050807568877293527446341505872366942805253810380628055806979451933016908800";
pub const SQRT_5: &str = "2.236067977499789696409173668731276235440618359611525724270897245410520925637804";
}
#[allow(dead_code)]
pub mod tier_19d {
pub const PI: (i128, i128) = (21053343141, 6701487259);
pub const E: (i128, i128) = (28875761731, 10622799089);
pub const SQRT_2: (i128, i128) = (10812186007, 7645370045);
pub const LN_2: (i128, i128) = (6847196937, 9878417065);
pub const PHI: (i128, i128) = (12586269025, 7778742049);
pub const LN_10: (i128, i128) = (42528320816, 18469815055);
pub const SQRT_3: (i128, i128) = (9863382151, 5694626340);
pub const SQRT_5: (i128, i128) = (22768774562, 10182505537);
}
#[allow(dead_code)]
pub mod tier_38d {
pub const PI_NUM: [u64; 4] = [0x76db573ddce0c076, 0xe3a, 0, 0];
pub const PI_DEN: [u64; 4] = [0xf93771bb7b1ce51, 0x486, 0, 0];
pub const E_NUM: [u64; 4] = [0xc8ebe3d0a1e4891f, 0x8dc, 0, 0];
pub const E_DEN: [u64; 4] = [0x818dc41bf9f74000, 0x343, 0, 0];
pub const SQRT_2_NUM: [u64; 4] = [0x846aef57c4c05e91, 0x22c, 0, 0];
pub const SQRT_2_DEN: [u64; 4] = [0xcd30cce8c6c6699c, 0x188, 0, 0];
pub const LN_2_NUM: [u64; 4] = [0x3e1fa2f117bf2801, 0x30e, 0, 0];
pub const LN_2_DEN: [u64; 4] = [0xd65a36b85a8c24d6, 0x466, 0, 0];
pub const PHI_NUM: [u64; 4] = [0x6f4e7b57a99c6400, 0x2ce, 0, 0];
pub const PHI_DEN: [u64; 4] = [0xcb5f35a76976c43, 0x1bb, 0, 0];
pub const LN_10_NUM: [u64; 4] = [0x9dcd3c524c5deccb, 0xc3c, 0, 0];
pub const LN_10_DEN: [u64; 4] = [0xe9e66e8ba0ce32a9, 0x550, 0, 0];
pub const SQRT_3_NUM: [u64; 4] = [0x1bf0a94e65f38dda, 0x2d4, 0, 0];
pub const SQRT_3_DEN: [u64; 4] = [0xfd33edda88aff58f, 0x19f, 0, 0];
pub const SQRT_5_NUM: [u64; 4] = [0xbc29d2d0ca001001, 0x322, 0, 0];
pub const SQRT_5_DEN: [u64; 4] = [0xd3ac2c2e0a61ec0, 0x16, 0, 0];
}
pub mod tier_77d {
pub const PI_NUM_STR: &str = "4170167120753626267426951858176848373908";
pub const PI_DEN_STR: &str = "1327405421574472826819306015318500841729";
pub const E_NUM_STR: &str = "3224546177070375504839670260260400797251";
pub const E_DEN_STR: &str = "1186244245652160441069426743288856160849";
pub const SQRT_2_NUM_STR: &str = "94741125149636933417873079920900017937";
pub const SQRT_2_DEN_STR: &str = "66992092050551637663438906713182313772";
pub const LN_2_NUM_STR: &str = "245136811127310559099810329887594754993";
pub const LN_2_DEN_STR: &str = "353657661752705407042003521780857290376";
pub const PHI_NUM_STR: &str = "573147844013817084101";
pub const PHI_DEN_STR: &str = "354224848179261915075";
pub const LN_10_NUM_STR: &str = "3453684117652085635286271321032656666369";
pub const LN_10_DEN_STR: &str = "1499915954533201960943129396032093884739";
pub const SQRT_3_NUM_STR: &str = "19785515999613069781581367687";
pub const SQRT_3_DEN_STR: &str = "11423172988432253331946397284";
pub const SQRT_5_NUM_STR: &str = "1576282345991202924472633606870413747838";
pub const SQRT_5_DEN_STR: &str = "704934895473834571656017795987798259457";
}
}
fn simplify_rational(num: &BigInt, den: &BigInt) -> (BigInt, BigInt) {
use num_integer::Integer;
let gcd = num.gcd(den);
(num / &gcd, den / &gcd)
}
fn bigint_to_u64_array_8(n: &BigInt) -> [u64; 8] {
let (sign, bytes) = n.to_bytes_le();
let mut result = [0u64; 8];
if sign == Sign::Minus {
panic!("Cannot convert negative BigInt to unsigned array");
}
for (i, chunk) in bytes.chunks(8).enumerate() {
if i >= 8 { break; }
let mut word_bytes = [0u8; 8];
word_bytes[..chunk.len()].copy_from_slice(chunk);
result[i] = u64::from_le_bytes(word_bytes);
}
result
}
fn generate_mathematical_constants(out_dir: &str, config: &PrecisionConfig) {
let dest_path = Path::new(out_dir).join("mathematical_constants.rs");
let mut file = File::create(&dest_path).unwrap();
writeln!(file, "// Mathematical Constants for gMath Library").unwrap();
writeln!(file, "// Profile: {}, Precision: {} decimal places",
config.profile_name, config.target_decimal_places).unwrap();
writeln!(file, "// Generated by build.rs - DO NOT EDIT").unwrap();
writeln!(file, "//").unwrap();
writeln!(file, "// Constants computed via continued fraction convergents").unwrap();
writeln!(file, "// Denominators are UNIQUE (not 10^N decimal scaling)").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// String literals for pattern detection in g_math gmath(\"3.14...\") wrapper").unwrap();
writeln!(file, "pub mod pattern_strings {{").unwrap();
writeln!(file, " pub const PI: &str = \"{}\";", hardcoded_constants::strings::PI).unwrap();
writeln!(file, " pub const E: &str = \"{}\";", hardcoded_constants::strings::E).unwrap();
writeln!(file, " pub const SQRT_2: &str = \"{}\";", hardcoded_constants::strings::SQRT_2).unwrap();
writeln!(file, " pub const LN_2: &str = \"{}\";", hardcoded_constants::strings::LN_2).unwrap();
writeln!(file, " pub const PHI: &str = \"{}\";", hardcoded_constants::strings::PHI).unwrap();
writeln!(file, " pub const LN_10: &str = \"{}\";", hardcoded_constants::strings::LN_10).unwrap();
writeln!(file, " pub const SQRT_3: &str = \"{}\";", hardcoded_constants::strings::SQRT_3).unwrap();
writeln!(file, " pub const SQRT_5: &str = \"{}\";", hardcoded_constants::strings::SQRT_5).unwrap();
writeln!(file, "}}").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Mathematical constants accessor interface (replaces SRICConstantsDatabase)").unwrap();
writeln!(file, "pub struct MathematicalConstants;").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "impl MathematicalConstants {{").unwrap();
let constants = [
("PI", hardcoded_constants::tier_77d::PI_NUM_STR, hardcoded_constants::tier_77d::PI_DEN_STR),
("E", hardcoded_constants::tier_77d::E_NUM_STR, hardcoded_constants::tier_77d::E_DEN_STR),
("SQRT_2", hardcoded_constants::tier_77d::SQRT_2_NUM_STR, hardcoded_constants::tier_77d::SQRT_2_DEN_STR),
("LN_2", hardcoded_constants::tier_77d::LN_2_NUM_STR, hardcoded_constants::tier_77d::LN_2_DEN_STR),
("PHI", hardcoded_constants::tier_77d::PHI_NUM_STR, hardcoded_constants::tier_77d::PHI_DEN_STR),
("LN_10", hardcoded_constants::tier_77d::LN_10_NUM_STR, hardcoded_constants::tier_77d::LN_10_DEN_STR),
("SQRT_3", hardcoded_constants::tier_77d::SQRT_3_NUM_STR, hardcoded_constants::tier_77d::SQRT_3_DEN_STR),
("SQRT_5", hardcoded_constants::tier_77d::SQRT_5_NUM_STR, hardcoded_constants::tier_77d::SQRT_5_DEN_STR),
];
for (name, num_str, den_str) in constants {
let num = num_str.parse::<BigInt>().unwrap();
let den = den_str.parse::<BigInt>().unwrap();
let num_arr = bigint_to_u64_array_8(&num);
let den_arr = bigint_to_u64_array_8(&den);
writeln!(file, " pub fn {}() -> ([u64; 8], [u64; 8]) {{", name).unwrap();
writeln!(file, " ({:?}, {:?})", num_arr, den_arr).unwrap();
writeln!(file, " }}").unwrap();
writeln!(file, "").unwrap();
}
writeln!(file, " pub fn GOLDEN_RATIO() -> ([u64; 8], [u64; 8]) {{").unwrap();
writeln!(file, " Self::PHI()").unwrap();
writeln!(file, " }}").unwrap();
writeln!(file, "").unwrap();
let pi_num_77 = hardcoded_constants::tier_77d::PI_NUM_STR.parse::<BigInt>().unwrap();
let pi_den_77 = hardcoded_constants::tier_77d::PI_DEN_STR.parse::<BigInt>().unwrap();
writeln!(file, " pub fn PI_OVER_2() -> ([u64; 8], [u64; 8]) {{").unwrap();
let (num_2, den_2) = simplify_rational(&pi_num_77, &(pi_den_77.clone() * BigInt::from(2)));
writeln!(file, " ({:?}, {:?})", bigint_to_u64_array_8(&num_2), bigint_to_u64_array_8(&den_2)).unwrap();
writeln!(file, " }}").unwrap();
writeln!(file, "").unwrap();
writeln!(file, " pub fn PI_OVER_4() -> ([u64; 8], [u64; 8]) {{").unwrap();
let (num_4, den_4) = simplify_rational(&pi_num_77, &(pi_den_77.clone() * BigInt::from(4)));
writeln!(file, " ({:?}, {:?})", bigint_to_u64_array_8(&num_4), bigint_to_u64_array_8(&den_4)).unwrap();
writeln!(file, " }}").unwrap();
writeln!(file, "").unwrap();
writeln!(file, " pub fn PI_OVER_6() -> ([u64; 8], [u64; 8]) {{").unwrap();
let (num_6, den_6) = simplify_rational(&pi_num_77, &(pi_den_77 * BigInt::from(6)));
writeln!(file, " ({:?}, {:?})", bigint_to_u64_array_8(&num_6), bigint_to_u64_array_8(&den_6)).unwrap();
writeln!(file, " }}").unwrap();
writeln!(file, "").unwrap();
writeln!(file, " pub fn ONE_OVER_E() -> ([u64; 8], [u64; 8]) {{").unwrap();
let e_num = hardcoded_constants::tier_77d::E_NUM_STR.parse::<BigInt>().unwrap();
let e_den = hardcoded_constants::tier_77d::E_DEN_STR.parse::<BigInt>().unwrap();
writeln!(file, " ({:?}, {:?})", bigint_to_u64_array_8(&e_den), bigint_to_u64_array_8(&e_num)).unwrap();
writeln!(file, " }}").unwrap();
writeln!(file, "").unwrap();
writeln!(file, " pub fn E_SQUARED() -> ([u64; 8], [u64; 8]) {{").unwrap();
writeln!(file, " Self::E() // Computed at runtime").unwrap();
writeln!(file, " }}").unwrap();
writeln!(file, "").unwrap();
writeln!(file, " /// Extract i128 from [u64; 8] array (embedded profile: 19 decimals)").unwrap();
writeln!(file, " /// Takes the first 2 u64s (16 bytes = 128 bits) from the array").unwrap();
writeln!(file, " #[inline]").unwrap();
writeln!(file, " pub fn extract_i128_from_u64_8(arr: [u64; 8]) -> i128 {{").unwrap();
writeln!(file, " let low = arr[0] as i128;").unwrap();
writeln!(file, " let high = arr[1] as i128;").unwrap();
writeln!(file, " low | (high << 64)").unwrap();
writeln!(file, " }}").unwrap();
writeln!(file, "").unwrap();
writeln!(file, " /// Extract [u64; 4] from [u64; 8] array (balanced profile: 38 decimals)").unwrap();
writeln!(file, " /// Takes the first 4 u64s (32 bytes = 256 bits) from the array").unwrap();
writeln!(file, " #[inline]").unwrap();
writeln!(file, " pub fn extract_u64_4_from_u64_8(arr: [u64; 8]) -> [u64; 4] {{").unwrap();
writeln!(file, " [arr[0], arr[1], arr[2], arr[3]]").unwrap();
writeln!(file, " }}").unwrap();
writeln!(file, "}}").unwrap();
println!("cargo:warning=✅ Generated mathematical_constants.rs ({} decimals)",
config.target_decimal_places);
}
#[allow(dead_code)]
fn get_rational_constant(name: &str, config: &PrecisionConfig) -> BigRational {
match config.target_decimal_places {
1..=19 => {
let (num, den) = match name {
"pi" => hardcoded_constants::tier_19d::PI,
"e" => hardcoded_constants::tier_19d::E,
"sqrt_2" => hardcoded_constants::tier_19d::SQRT_2,
"ln_2" => hardcoded_constants::tier_19d::LN_2,
"phi" => hardcoded_constants::tier_19d::PHI,
"ln_10" => hardcoded_constants::tier_19d::LN_10,
"sqrt_3" => hardcoded_constants::tier_19d::SQRT_3,
"sqrt_5" => hardcoded_constants::tier_19d::SQRT_5,
_ => panic!("Unknown constant: {}", name),
};
BigRational::new(BigInt::from(num), BigInt::from(den))
},
20..=38 => {
let (num_arr, den_arr) = match name {
"pi" => (hardcoded_constants::tier_38d::PI_NUM, hardcoded_constants::tier_38d::PI_DEN),
"e" => (hardcoded_constants::tier_38d::E_NUM, hardcoded_constants::tier_38d::E_DEN),
"sqrt_2" => (hardcoded_constants::tier_38d::SQRT_2_NUM, hardcoded_constants::tier_38d::SQRT_2_DEN),
"ln_2" => (hardcoded_constants::tier_38d::LN_2_NUM, hardcoded_constants::tier_38d::LN_2_DEN),
"phi" => (hardcoded_constants::tier_38d::PHI_NUM, hardcoded_constants::tier_38d::PHI_DEN),
"ln_10" => (hardcoded_constants::tier_38d::LN_10_NUM, hardcoded_constants::tier_38d::LN_10_DEN),
"sqrt_3" => (hardcoded_constants::tier_38d::SQRT_3_NUM, hardcoded_constants::tier_38d::SQRT_3_DEN),
"sqrt_5" => (hardcoded_constants::tier_38d::SQRT_5_NUM, hardcoded_constants::tier_38d::SQRT_5_DEN),
_ => panic!("Unknown constant: {}", name),
};
let num = u64_array_to_bigint(&num_arr);
let den = u64_array_to_bigint(&den_arr);
BigRational::new(num, den)
},
_ => {
let (num_str, den_str) = match name {
"pi" => (hardcoded_constants::tier_77d::PI_NUM_STR, hardcoded_constants::tier_77d::PI_DEN_STR),
"e" => (hardcoded_constants::tier_77d::E_NUM_STR, hardcoded_constants::tier_77d::E_DEN_STR),
"sqrt_2" => (hardcoded_constants::tier_77d::SQRT_2_NUM_STR, hardcoded_constants::tier_77d::SQRT_2_DEN_STR),
"ln_2" => (hardcoded_constants::tier_77d::LN_2_NUM_STR, hardcoded_constants::tier_77d::LN_2_DEN_STR),
"phi" => (hardcoded_constants::tier_77d::PHI_NUM_STR, hardcoded_constants::tier_77d::PHI_DEN_STR),
"ln_10" => (hardcoded_constants::tier_77d::LN_10_NUM_STR, hardcoded_constants::tier_77d::LN_10_DEN_STR),
"sqrt_3" => (hardcoded_constants::tier_77d::SQRT_3_NUM_STR, hardcoded_constants::tier_77d::SQRT_3_DEN_STR),
"sqrt_5" => (hardcoded_constants::tier_77d::SQRT_5_NUM_STR, hardcoded_constants::tier_77d::SQRT_5_DEN_STR),
_ => panic!("Unknown constant: {}", name),
};
let num: BigInt = num_str.parse().unwrap();
let den: BigInt = den_str.parse().unwrap();
BigRational::new(num, den)
}
}
}
#[allow(dead_code)]
fn u64_array_to_bigint(arr: &[u64; 4]) -> BigInt {
let mut bytes = Vec::with_capacity(32);
for &word in arr.iter() {
bytes.extend_from_slice(&word.to_le_bytes());
}
BigInt::from_bytes_le(Sign::Plus, &bytes)
}
fn exp_rational(x: &BigRational, terms: usize) -> BigRational {
if *x < BigRational::zero() {
let pos_x = -x;
let exp_pos = exp_rational_positive(&pos_x, terms);
return BigRational::one() / exp_pos;
}
exp_rational_positive(x, terms)
}
fn exp_rational_positive(x: &BigRational, terms: usize) -> BigRational {
let mut result = BigRational::one();
let mut term = BigRational::one();
let precision_threshold = if terms >= 600 {
900 } else if terms >= 500 {
600 } else if terms >= 400 {
500 } else {
300 };
for n in 1..terms {
term = term * x / BigInt::from(n);
result = result + &term;
let term_bits = term.numer().abs().bits() as i64 - term.denom().bits() as i64;
let result_bits = result.numer().abs().bits() as i64 - result.denom().bits() as i64;
if term_bits < result_bits - precision_threshold {
break;
}
}
result
}
fn compute_pi_rational(precision_bits: usize) -> BigRational {
fn atan_rational(x: &BigRational, precision_bits: usize) -> BigRational {
let x_sq = x * x;
let mut power = x.clone(); let mut result = x.clone(); let target_bits = -(precision_bits as i64 + 20);
let mut k = 1u64;
loop {
power = &power * &x_sq; let denom = BigRational::new(BigInt::from(1), BigInt::from(2 * k + 1));
let term = &power * &denom;
if k % 2 == 1 {
result = result - &term; } else {
result = result + &term; }
let power_bits = power.numer().bits() as i64 - power.denom().bits() as i64;
if power_bits < target_bits {
break;
}
k += 1;
}
result
}
let one = BigInt::from(1);
let x1 = BigRational::new(one.clone(), BigInt::from(5)); let x2 = BigRational::new(one.clone(), BigInt::from(239));
let atan_1_5 = atan_rational(&x1, precision_bits);
let atan_1_239 = atan_rational(&x2, precision_bits);
let sixteen = BigRational::from(BigInt::from(16));
let four = BigRational::from(BigInt::from(4));
&sixteen * &atan_1_5 - &four * &atan_1_239
}
fn rational_to_q64_64(r: &BigRational) -> (i128, i64) {
let scale_64: BigInt = BigInt::from(1i128 << 64);
let scaled = r * BigRational::from(scale_64.clone());
let main = scaled.numer() / scaled.denom();
let main_i128 = main.to_i128().unwrap_or(0);
let main_rational = BigRational::from(main);
let remainder = scaled - main_rational;
let comp_scale = BigInt::from(1i64 << 32);
let compensation_scaled = remainder * BigRational::from(comp_scale);
let compensation = (compensation_scaled.numer() / compensation_scaled.denom())
.to_i64()
.unwrap_or(0);
(main_i128, compensation)
}
fn bigint_to_i256(n: &BigInt) -> [u64; 4] {
let bytes = n.to_signed_bytes_le();
let mut words = [0u64; 4];
for (i, chunk) in bytes.chunks(8).enumerate() {
if i >= 4 { break; }
let mut word = 0u64;
for (j, &byte) in chunk.iter().enumerate() {
word |= (byte as u64) << (j * 8);
}
words[i] = word;
}
if n.sign() == Sign::Minus && bytes.len() < 32 {
let start_word = (bytes.len() + 7) / 8;
for word in words.iter_mut().skip(start_word) {
*word = u64::MAX;
}
}
words
}
fn bigint_to_i512(n: &BigInt) -> [u64; 8] {
let bytes = n.to_signed_bytes_le();
let mut words = [0u64; 8];
for (i, chunk) in bytes.chunks(8).enumerate() {
if i >= 8 { break; }
let mut word = 0u64;
for (j, &byte) in chunk.iter().enumerate() {
word |= (byte as u64) << (j * 8);
}
words[i] = word;
}
if n.sign() == Sign::Minus && bytes.len() < 64 {
let start_word = (bytes.len() + 7) / 8;
for word in words.iter_mut().skip(start_word) {
*word = u64::MAX;
}
}
words
}
fn bigint_to_i1024(n: &BigInt) -> [u64; 16] {
let bytes = n.to_signed_bytes_le();
let mut words = [0u64; 16];
for (i, chunk) in bytes.chunks(8).enumerate() {
if i >= 16 { break; }
let mut word = 0u64;
for (j, &byte) in chunk.iter().enumerate() {
word |= (byte as u64) << (j * 8);
}
words[i] = word;
}
if n.sign() == Sign::Minus && bytes.len() < 128 {
let start_word = (bytes.len() + 7) / 8;
for word in words.iter_mut().skip(start_word) {
*word = u64::MAX;
}
}
words
}
fn rational_to_q128_128(r: &BigRational) -> ([u64; 4], i128) {
let scale_128: BigInt = BigInt::from(1) << 128;
let scaled = r * BigRational::from(scale_128.clone());
let main = scaled.numer() / scaled.denom();
let main_i256 = bigint_to_i256(&main);
let main_rational = BigRational::from(main);
let remainder = scaled - main_rational;
let comp_scale = BigInt::from(1i128 << 64);
let compensation_scaled = remainder * BigRational::from(comp_scale);
let compensation = (compensation_scaled.numer() / compensation_scaled.denom())
.to_i128()
.unwrap_or(0);
(main_i256, compensation)
}
fn rational_to_q256_256(r: &BigRational) -> ([u64; 8], [u64; 4]) {
let scale_256: BigInt = BigInt::from(1) << 256;
let scaled = r * BigRational::from(scale_256.clone());
let main = scaled.numer() / scaled.denom();
let main_i512 = bigint_to_i512(&main);
let main_rational = BigRational::from(main);
let remainder = scaled - main_rational;
let comp_scale = BigInt::from(1) << 256;
let compensation_scaled = remainder * BigRational::from(comp_scale);
let compensation_bigint = compensation_scaled.numer() / compensation_scaled.denom();
let compensation = bigint_to_i256(&compensation_bigint);
(main_i512, compensation)
}
fn rational_to_q512_512(r: &BigRational) -> ([u64; 16], [u64; 8]) {
let scale_512: BigInt = BigInt::from(1) << 512;
let scaled = r * BigRational::from(scale_512.clone());
let main = scaled.numer() / scaled.denom();
let main_i1024 = bigint_to_i1024(&main);
let main_rational = BigRational::from(main);
let remainder = scaled - main_rational;
let comp_scale = BigInt::from(1) << 256;
let compensation_scaled = remainder * BigRational::from(comp_scale);
let compensation_bigint = compensation_scaled.numer() / compensation_scaled.denom();
let compensation = bigint_to_i512(&compensation_bigint);
(main_i1024, compensation)
}
fn generate_profile_aware_tables(out_dir: &str, config: &PrecisionConfig) {
println!("cargo:warning=🔧 UGOD Multi-Tier: Generating ALL transcendental table sets");
println!("cargo:warning=📊 Profile '{}' will use {} tables as PRIMARY",
config.profile_name, config.table_format);
println!("cargo:warning= ├─ Q64.64 tables (Tier 3: 19 decimals)...");
generate_q64_64_tables(out_dir, config);
println!("cargo:warning= ├─ Q128.128 tables (Tier 4: 38 decimals)...");
generate_q128_128_tables(out_dir, config);
println!("cargo:warning= ├─ Q256.256 tables (Tier 5: 77 decimals)...");
generate_q256_256_tables(out_dir, config);
println!("cargo:warning= └─ Q512.512 tables (Tier 6: 154 decimals)...");
generate_q512_512_tables(out_dir, config);
println!("cargo:warning=✅ All table sets generated successfully");
}
fn generate_q64_64_tables(out_dir: &str, _config: &PrecisionConfig) {
let dest_path = Path::new(out_dir).join("q64_64_tables.rs");
let mut file = File::create(&dest_path).unwrap();
writeln!(file, "// Q64.64 Transcendental Lookup Tables").unwrap();
writeln!(file, "// Generated from hardcoded rational constants - ZERO float arithmetic").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Integer exponential table: e^n for n ∈ [-40, 40] (Tier 3: Q64.64)").unwrap();
writeln!(file, "pub static EXP_INTEGER_TABLE_TIER_3: [(i128, i64); 81] = [").unwrap();
for n in -40..=40 {
let x = BigRational::from(BigInt::from(n));
let exp_x = exp_rational(&x, 300);
let (main, comp) = rational_to_q64_64(&exp_x);
writeln!(file, " ({}, {}), // e^{}", main, comp, n).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Primary exponential table: e^(k/2^10) for k ∈ [0, 1023] (Tier 3: Q64.64)").unwrap();
writeln!(file, "pub static EXP_PRIMARY_TABLE_TIER_3: [(i128, i64); 1024] = [").unwrap();
for k in 0..1024 {
let x = BigRational::new(BigInt::from(k), BigInt::from(1i128 << 10));
let exp_x = exp_rational(&x, 100);
let (main, comp) = rational_to_q64_64(&exp_x);
writeln!(file, " ({}, {}), // e^({}/2^10)", main, comp, k).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Secondary exponential table: e^(j/2^20) for j ∈ [0, 1023] (Tier 3: Q64.64)").unwrap();
writeln!(file, "pub static EXP_SECONDARY_TABLE_TIER_3: [(i128, i64); 1024] = [").unwrap();
for j in 0..1024 {
let x = BigRational::new(BigInt::from(j), BigInt::from(1i128 << 20));
let exp_x = exp_rational(&x, 100);
let (main, comp) = rational_to_q64_64(&exp_x);
writeln!(file, " ({}, {}), // e^({}/2^20)", main, comp, j).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Tertiary exponential table: e^(m/2^30) for m ∈ [0, 1023] (Tier 3: Q64.64)").unwrap();
writeln!(file, "pub static EXP_TERTIARY_TABLE_TIER_3: [(i128, i64); 1024] = [").unwrap();
for m in 0..1024 {
let x = BigRational::new(BigInt::from(m), BigInt::from(1i128 << 30));
let exp_x = exp_rational(&x, 100);
let (main, comp) = rational_to_q64_64(&exp_x);
writeln!(file, " ({}, {}), // e^({}/2^30)", main, comp, m).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
println!("cargo:warning=✅ Generated Q64.64 exponential tables (4 × 1024 entries)");
}
fn generate_q128_128_tables(out_dir: &str, _config: &PrecisionConfig) {
let dest_path = Path::new(out_dir).join("q128_128_tables.rs");
let mut file = File::create(&dest_path).unwrap();
writeln!(file, "// Q128.128 Transcendental Lookup Tables").unwrap();
writeln!(file, "// Generated from BigRational - 38 decimal precision").unwrap();
writeln!(file, "// Profile: Balanced | Storage: I256 | Compensation: i128").unwrap();
writeln!(file, "// ZERO float arithmetic - pure rational → fixed-point conversion").unwrap();
writeln!(file, "// Note: I256 type is imported by the including module").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Integer exponential table: e^n for n ∈ [-40, 40] (Tier 4: Q128.128)").unwrap();
writeln!(file, "/// Format: (I256 main, i128 compensation)").unwrap();
writeln!(file, "pub static EXP_INTEGER_TABLE_TIER_4: [(I256, i128); 81] = [").unwrap();
for n in -40..=40 {
let x = BigRational::from(BigInt::from(n));
let exp_x = exp_rational(&x, 400);
let (main, comp) = rational_to_q128_128(&exp_x);
writeln!(file, " (I256::from_words({:?}), {}), // e^{}", main, comp, n).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Primary exponential table: e^(k/2^30) for k ∈ [0, 1023] (Tier 4: Q128.128)").unwrap();
writeln!(file, "pub static EXP_PRIMARY_TABLE_TIER_4: [(I256, i128); 1024] = [").unwrap();
for k in 0..1024 {
let x = BigRational::new(BigInt::from(k), BigInt::from(1024));
let exp_x = exp_rational(&x, 100);
let (main, comp) = rational_to_q128_128(&exp_x);
writeln!(file, " (I256::from_words({:?}), {}), // e^({}/1024)", main, comp, k).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Secondary exponential table: e^(j/2^20) for j ∈ [0, 1023] (Tier 4: Q128.128)").unwrap();
writeln!(file, "pub static EXP_SECONDARY_TABLE_TIER_4: [(I256, i128); 1024] = [").unwrap();
for j in 0..1024 {
let x = BigRational::new(BigInt::from(j), BigInt::from(1024 * 1024));
let exp_x = exp_rational(&x, 100);
let (main, comp) = rational_to_q128_128(&exp_x);
writeln!(file, " (I256::from_words({:?}), {}), // e^({}/1024/1024)", main, comp, j).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Tertiary exponential table: e^(m/2^40) for m ∈ [0, 1023] (Tier 4: Q128.128)").unwrap();
writeln!(file, "pub static EXP_TERTIARY_TABLE_TIER_4: [(I256, i128); 1024] = [").unwrap();
for m in 0..1024 {
let x = BigRational::new(BigInt::from(m), BigInt::from(1024 * 1024 * 1024));
let exp_x = exp_rational(&x, 100);
let (main, comp) = rational_to_q128_128(&exp_x);
writeln!(file, " (I256::from_words({:?}), {}), // e^({}/1024/1024/1024)", main, comp, m).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "// Reciprocal and factorial tables (reserved)").unwrap();
writeln!(file, "pub static RECIPROCAL_PRIMARY_TABLE_TIER_4: [(I256, i128); 1024] = [(I256::from_words([0, 0, 0, 0]), 0); 1024];").unwrap();
writeln!(file, "pub static RECIPROCAL_SECONDARY_TABLE_TIER_4: [(I256, i128); 1024] = [(I256::from_words([0, 0, 0, 0]), 0); 1024];").unwrap();
writeln!(file, "pub static RECIPROCAL_EXACT_TABLE_TIER_4: [(I256, i128); 256] = [(I256::from_words([0, 0, 0, 0]), 0); 256];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "pub static FACTORIAL_RECIPROCALS_TIER_4: [(I256, i128); 50] = [").unwrap();
for i in 0..50 {
let factorial = (1..=i).fold(BigInt::one(), |acc, x| acc * BigInt::from(x));
let reciprocal = BigRational::new(BigInt::one(), factorial);
let (main, comp) = rational_to_q128_128(&reciprocal);
writeln!(file, " (I256::from_words({:?}), {}), // 1/{}!", main, comp, i).unwrap();
}
writeln!(file, "];").unwrap();
println!("cargo:warning=✅ Generated Q128.128 tables: 3,169 entries, 38-decimal precision");
}
fn generate_q256_256_tables(out_dir: &str, _config: &PrecisionConfig) {
let dest_path = Path::new(out_dir).join("q256_256_tables.rs");
let mut file = File::create(&dest_path).unwrap();
writeln!(file, "// Q256.256 Transcendental Lookup Tables").unwrap();
writeln!(file, "// Generated from BigRational - 77 decimal precision").unwrap();
writeln!(file, "// Profile: Scientific | Storage: I512 | Compensation: I256").unwrap();
writeln!(file, "// ZERO float arithmetic - pure rational → fixed-point conversion").unwrap();
writeln!(file, "// Note: I512 and I256 types are imported by the including module").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Integer exponential table: e^n for n ∈ [-40, 40]").unwrap();
writeln!(file, "/// Format: (I512 main, I256 compensation)").unwrap();
writeln!(file, "pub static EXP_INTEGER_TABLE_TIER_5: [(I512, I256); 81] = [").unwrap();
for n in -40..=40 {
let x = BigRational::from(BigInt::from(n));
let exp_x = exp_rational(&x, 500);
let (main, comp) = rational_to_q256_256(&exp_x);
writeln!(file, " (I512::from_words({:?}), I256::from_words({:?})), // e^{}", main, comp, n).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Primary exponential table: e^(k/2^30) for k ∈ [0, 1023]").unwrap();
writeln!(file, "pub static EXP_PRIMARY_TABLE_TIER_5: [(I512, I256); 1024] = [").unwrap();
for k in 0..1024 {
let x = BigRational::new(BigInt::from(k), BigInt::from(1024));
let exp_x = exp_rational(&x, 200);
let (main, comp) = rational_to_q256_256(&exp_x);
writeln!(file, " (I512::from_words({:?}), I256::from_words({:?})), // e^({}/1024)", main, comp, k).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Secondary exponential table: e^(j/2^20) for j ∈ [0, 1023]").unwrap();
writeln!(file, "pub static EXP_SECONDARY_TABLE_TIER_5: [(I512, I256); 1024] = [").unwrap();
for j in 0..1024 {
let x = BigRational::new(BigInt::from(j), BigInt::from(1i128 << 20));
let exp_x = exp_rational(&x, 200);
let (main, comp) = rational_to_q256_256(&exp_x);
writeln!(file, " (I512::from_words({:?}), I256::from_words({:?})), // e^({}/2^20)", main, comp, j).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Tertiary exponential table: e^(m/2^30) for m ∈ [0, 1023]").unwrap();
writeln!(file, "pub static EXP_TERTIARY_TABLE_TIER_5: [(I512, I256); 1024] = [").unwrap();
for m in 0..1024 {
let x = BigRational::new(BigInt::from(m), BigInt::from(1024 * 1024 * 1024)); let exp_x = exp_rational(&x, 200);
let (main, comp) = rational_to_q256_256(&exp_x);
writeln!(file, " (I512::from_words({:?}), I256::from_words({:?})), // e^({}/2^30)", main, comp, m).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "// Reciprocal and factorial tables (reserved)").unwrap();
writeln!(file, "pub static RECIPROCAL_PRIMARY_TABLE_TIER_5: [(I512, I256); 1024] = [(I512::from_words([0, 0, 0, 0, 0, 0, 0, 0]), I256::from_words([0, 0, 0, 0])); 1024];").unwrap();
writeln!(file, "pub static RECIPROCAL_SECONDARY_TABLE_TIER_5: [(I512, I256); 1024] = [(I512::from_words([0, 0, 0, 0, 0, 0, 0, 0]), I256::from_words([0, 0, 0, 0])); 1024];").unwrap();
writeln!(file, "pub static RECIPROCAL_EXACT_TABLE_TIER_5: [(I512, I256); 256] = [(I512::from_words([0, 0, 0, 0, 0, 0, 0, 0]), I256::from_words([0, 0, 0, 0])); 256];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "pub static FACTORIAL_RECIPROCALS_TIER_5: [(I512, I256); 50] = [").unwrap();
for i in 0..50 {
let factorial = (1..=i).fold(BigInt::one(), |acc, x| acc * BigInt::from(x));
let reciprocal = BigRational::new(BigInt::one(), factorial);
let (main, comp) = rational_to_q256_256(&reciprocal);
writeln!(file, " (I512::from_words({:?}), I256::from_words({:?})), // 1/{}!", main, comp, i).unwrap();
}
writeln!(file, "];").unwrap();
println!("cargo:warning=✅ Generated Q256.256 tables: 3,169 entries, 77-decimal precision");
}
fn generate_q512_512_tables(out_dir: &str, _config: &PrecisionConfig) {
let dest_path = Path::new(out_dir).join("q512_512_tables.rs");
let mut file = File::create(&dest_path).unwrap();
writeln!(file, "// Q512.512 Transcendental Lookup Tables (Tier 6)").unwrap();
writeln!(file, "// Generated from BigRational - 154 decimal precision").unwrap();
writeln!(file, "// Profile: Scientific Tier N+1 | Storage: I1024 | Compensation: I512").unwrap();
writeln!(file, "// ZERO float arithmetic - pure rational → fixed-point conversion").unwrap();
writeln!(file, "// Note: I1024 and I512 types are imported by the including module").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Integer exponential table: e^n for n ∈ [-40, 40]").unwrap();
writeln!(file, "/// Format: (I1024 main, I512 compensation)").unwrap();
writeln!(file, "pub static EXP_INTEGER_TABLE_TIER_6: [(I1024, I512); 81] = [").unwrap();
for n in -40..=40 {
let x = BigRational::from(BigInt::from(n));
let exp_x = exp_rational(&x, 600);
let (main, comp) = rational_to_q512_512(&exp_x);
writeln!(file, " (I1024::from_words({:?}), I512::from_words({:?})), // e^{}", main, comp, n).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Primary exponential table: e^(k/2^30) for k ∈ [0, 1023]").unwrap();
writeln!(file, "pub static EXP_PRIMARY_TABLE_TIER_6: [(I1024, I512); 1024] = [").unwrap();
for k in 0..1024 {
let x = BigRational::new(BigInt::from(k), BigInt::from(1024));
let exp_x = exp_rational(&x, 300);
let (main, comp) = rational_to_q512_512(&exp_x);
writeln!(file, " (I1024::from_words({:?}), I512::from_words({:?})), // e^({}/1024)", main, comp, k).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Secondary exponential table: e^(j/2^20) for j ∈ [0, 1023]").unwrap();
writeln!(file, "pub static EXP_SECONDARY_TABLE_TIER_6: [(I1024, I512); 1024] = [").unwrap();
for j in 0..1024 {
let x = BigRational::new(BigInt::from(j), BigInt::from(1i128 << 20));
let exp_x = exp_rational(&x, 300);
let (main, comp) = rational_to_q512_512(&exp_x);
writeln!(file, " (I1024::from_words({:?}), I512::from_words({:?})), // e^({}/2^20)", main, comp, j).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Tertiary exponential table: e^(m/2^40) for m ∈ [0, 1023]").unwrap();
writeln!(file, "pub static EXP_TERTIARY_TABLE_TIER_6: [(I1024, I512); 1024] = [").unwrap();
for m in 0..1024 {
let x = BigRational::new(BigInt::from(m), BigInt::from(1024 * 1024 * 1024)); let exp_x = exp_rational(&x, 300);
let (main, comp) = rational_to_q512_512(&exp_x);
writeln!(file, " (I1024::from_words({:?}), I512::from_words({:?})), // e^({}/2^30)", main, comp, m).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "// Reciprocal tables (reserved)").unwrap();
writeln!(file, "pub static RECIPROCAL_PRIMARY_TABLE_TIER_6: [(I1024, I512); 1024] = [(I1024::from_words([0; 16]), I512::from_words([0; 8])); 1024];").unwrap();
writeln!(file, "pub static RECIPROCAL_SECONDARY_TABLE_TIER_6: [(I1024, I512); 1024] = [(I1024::from_words([0; 16]), I512::from_words([0; 8])); 1024];").unwrap();
writeln!(file, "pub static RECIPROCAL_EXACT_TABLE_TIER_6: [(I1024, I512); 256] = [(I1024::from_words([0; 16]), I512::from_words([0; 8])); 256];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Factorial reciprocals: 1/n! for n ∈ [0, 49] (Q512.512 format)").unwrap();
writeln!(file, "/// CRITICAL: Used in taylor_series_q512_512 for sub-ULP precision").unwrap();
writeln!(file, "pub static FACTORIAL_RECIPROCALS_TIER_6: [(I1024, I512); 50] = [").unwrap();
for i in 0..50 {
let factorial = (1..=i).fold(BigInt::one(), |acc, x| acc * BigInt::from(x));
let reciprocal = BigRational::new(BigInt::one(), factorial);
let (main, comp) = rational_to_q512_512(&reciprocal);
writeln!(file, " (I1024::from_words({:?}), I512::from_words({:?})), // 1/{}!", main, comp, i).unwrap();
}
writeln!(file, "];").unwrap();
println!("cargo:warning=✅ Generated Q512.512 tables: 3,169 entries, 154-decimal precision");
}
fn ln_1_plus_y_rational(y: &BigRational, precision_bits: usize) -> BigRational {
if *y == BigRational::zero() {
return BigRational::zero();
}
let y_bits = y.numer().bits() as i64 - y.denom().bits() as i64;
if y_bits < -50 {
let y2 = y * y;
let half = BigRational::new(BigInt::from(1), BigInt::from(2));
return y - &y2 * ½
}
if y_bits < -6 {
return ln_1_plus_y_taylor(y, precision_bits);
}
let two = BigRational::from(BigInt::from(2));
let z = y / (y + &two);
let mut result = z.clone();
let mut z_power = z.clone();
let z_squared = &z * &z;
let max_terms = precision_bits / 2 + 20; let target_bits = -(precision_bits as i64 + 20);
for n in 1..max_terms {
z_power = &z_power * &z_squared;
let coeff = BigRational::new(BigInt::from(1), BigInt::from(2 * n + 1));
result = result + &coeff * &z_power;
let term_bits = z_power.numer().bits() as i64 - z_power.denom().bits() as i64;
if term_bits < target_bits {
break;
}
}
&result * &two }
fn ln_1_plus_y_taylor(y: &BigRational, precision_bits: usize) -> BigRational {
let mut result = y.clone();
let mut y_power = y.clone();
let max_terms = 50 + precision_bits / 4; let target_bits = -(precision_bits as i64 + 20);
for n in 2..=max_terms {
y_power = &y_power * y;
let term = &y_power / BigRational::from(BigInt::from(n));
if n % 2 == 0 {
result = result - term;
} else {
result = result + term;
}
let term_bits = y_power.numer().bits() as i64 - y_power.denom().bits() as i64;
if term_bits < target_bits {
break;
}
}
result
}
fn ln_2_rational(precision_bits: usize) -> BigRational {
let one_third = BigRational::new(BigInt::from(1), BigInt::from(3));
let mut result = BigRational::zero();
let mut power = one_third.clone();
let max_terms = precision_bits / 3 + 10;
let target_bits = -(precision_bits as i64 + 10);
for n in 0..max_terms {
let coeff = BigRational::new(BigInt::from(1), BigInt::from(2 * n + 1));
result = result + &coeff * &power;
power = &power * &one_third * &one_third;
let power_bits = power.numer().bits() as i64 - power.denom().bits() as i64;
if power_bits < target_bits {
break;
}
}
result * BigRational::from(BigInt::from(2))
}
fn generate_ln_tables(out_dir: &str, _config: &PrecisionConfig) {
println!("cargo:warning=🔧 Generating ln() lookup tables (optimized)");
generate_ln_q64_64_tables(out_dir);
generate_ln_q128_128_tables(out_dir);
generate_ln_q256_256_tables(out_dir);
generate_ln_q512_512_tables(out_dir);
println!("cargo:warning=✅ All ln() table sets generated successfully");
}
fn generate_ln_q64_64_tables(out_dir: &str) {
let dest_path = Path::new(out_dir).join("ln_q64_64_tables.rs");
let mut file = File::create(&dest_path).unwrap();
writeln!(file, "// Q64.64 Natural Logarithm Lookup Tables").unwrap();
writeln!(file, "// Generated from BigRational - ZERO float arithmetic").unwrap();
writeln!(file, "").unwrap();
let ln2 = ln_2_rational(80);
let (ln2_main, ln2_comp) = rational_to_q64_64(&ln2);
writeln!(file, "/// ln(2) constant (Tier 3: Q64.64)").unwrap();
writeln!(file, "pub static LN_2_CONSTANT_TIER_3: (i128, i64) = ({}, {});", ln2_main, ln2_comp).unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Primary ln table: ln(1 + k/1024) for k ∈ [0, 1023] (Tier 3: Q64.64)").unwrap();
writeln!(file, "pub static LN_PRIMARY_TABLE_TIER_3: [(i128, i64); 1024] = [").unwrap();
for k in 0..1024 {
let y = BigRational::new(BigInt::from(k), BigInt::from(1024));
let ln_val = ln_1_plus_y_rational(&y, 80);
let (main, comp) = rational_to_q64_64(&ln_val);
writeln!(file, " ({}, {}), // ln(1 + {}/1024)", main, comp, k).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Secondary ln table: ln(1 + j/2^20) for j ∈ [0, 1023] (Tier 3: Q64.64)").unwrap();
writeln!(file, "pub static LN_SECONDARY_TABLE_TIER_3: [(i128, i64); 1024] = [").unwrap();
for j in 0..1024 {
let y = BigRational::new(BigInt::from(j), BigInt::from(1i128 << 20));
let ln_val = ln_1_plus_y_rational(&y, 80);
let (main, comp) = rational_to_q64_64(&ln_val);
writeln!(file, " ({}, {}), // ln(1 + {}/2^20)", main, comp, j).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Tertiary ln table: ln(1 + m/2^30) for m ∈ [0, 1023] (Tier 3: Q64.64)").unwrap();
writeln!(file, "pub static LN_TERTIARY_TABLE_TIER_3: [(i128, i64); 1024] = [").unwrap();
for m in 0..1024 {
let y = BigRational::new(BigInt::from(m), BigInt::from(1i128 << 30));
let ln_val = ln_1_plus_y_rational(&y, 80);
let (main, comp) = rational_to_q64_64(&ln_val);
writeln!(file, " ({}, {}), // ln(1 + {}/2^30)", main, comp, m).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Quaternary ln table: ln(1 + p/2^40) for p ∈ [0, 1023] (Tier 3: Q64.64)").unwrap();
writeln!(file, "pub static LN_QUATERNARY_TABLE_TIER_3: [(i128, i64); 1024] = [").unwrap();
for p in 0..1024 {
let y = BigRational::new(BigInt::from(p), BigInt::from(1i128 << 40));
let ln_val = ln_1_plus_y_rational(&y, 80);
let (main, comp) = rational_to_q64_64(&ln_val);
writeln!(file, " ({}, {}), // ln(1 + {}/2^40)", main, comp, p).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Taylor coefficients for ln(1+y): 1/n (Tier 3: Q64.64)").unwrap();
writeln!(file, "/// Signs are applied in the Taylor series code, not in the table.").unwrap();
writeln!(file, "pub static LN_TAYLOR_COEFFICIENTS_TIER_3: [(i128, i64); 51] = [").unwrap();
writeln!(file, " (0, 0), // placeholder for n=0").unwrap();
for n in 1..=50 {
let coef = BigRational::new(BigInt::from(1), BigInt::from(n));
let (main, comp) = rational_to_q64_64(&coef);
writeln!(file, " ({}, {}), // 1/{}", main, comp, n).unwrap();
}
writeln!(file, "];").unwrap();
println!("cargo:warning=✅ Generated Q64.64 ln tables");
}
fn generate_ln_q128_128_tables(out_dir: &str) {
let dest_path = Path::new(out_dir).join("ln_q128_128_tables.rs");
let mut file = File::create(&dest_path).unwrap();
writeln!(file, "// Q128.128 Natural Logarithm Lookup Tables").unwrap();
writeln!(file, "// Generated from BigRational - 38 decimal precision").unwrap();
writeln!(file, "").unwrap();
let ln2 = ln_2_rational(150);
let (ln2_main, ln2_comp) = rational_to_q128_128(&ln2);
writeln!(file, "/// ln(2) constant (Tier 4: Q128.128)").unwrap();
writeln!(file, "pub static LN_2_CONSTANT_TIER_4: (I256, i128) = (I256::from_words({:?}), {});", ln2_main, ln2_comp).unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Primary ln table: ln(1 + k/1024) for k ∈ [0, 1023] (Tier 4: Q128.128)").unwrap();
writeln!(file, "pub static LN_PRIMARY_TABLE_TIER_4: [(I256, i128); 1024] = [").unwrap();
for k in 0..1024 {
let y = BigRational::new(BigInt::from(k), BigInt::from(1024));
let ln_val = ln_1_plus_y_rational(&y, 150);
let (main, comp) = rational_to_q128_128(&ln_val);
writeln!(file, " (I256::from_words({:?}), {}), // ln(1 + {}/1024)", main, comp, k).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Secondary ln table: ln(1 + j/2^20) for j ∈ [0, 1023] (Tier 4: Q128.128)").unwrap();
writeln!(file, "pub static LN_SECONDARY_TABLE_TIER_4: [(I256, i128); 1024] = [").unwrap();
for j in 0..1024 {
let y = BigRational::new(BigInt::from(j), BigInt::from(1i128 << 20));
let ln_val = ln_1_plus_y_rational(&y, 150);
let (main, comp) = rational_to_q128_128(&ln_val);
writeln!(file, " (I256::from_words({:?}), {}), // ln(1 + {}/2^20)", main, comp, j).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Tertiary ln table: ln(1 + m/2^30) for m ∈ [0, 1023] (Tier 4: Q128.128)").unwrap();
writeln!(file, "pub static LN_TERTIARY_TABLE_TIER_4: [(I256, i128); 1024] = [").unwrap();
for m in 0..1024 {
let y = BigRational::new(BigInt::from(m), BigInt::from(1i128 << 30));
let ln_val = ln_1_plus_y_rational(&y, 150);
let (main, comp) = rational_to_q128_128(&ln_val);
writeln!(file, " (I256::from_words({:?}), {}), // ln(1 + {}/2^30)", main, comp, m).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Quaternary ln table: ln(1 + p/2^40) for p ∈ [0, 1023] (Tier 4: Q128.128)").unwrap();
writeln!(file, "pub static LN_QUATERNARY_TABLE_TIER_4: [(I256, i128); 1024] = [").unwrap();
for p in 0..1024 {
let y = BigRational::new(BigInt::from(p), BigInt::from(1i128 << 40));
let ln_val = ln_1_plus_y_rational(&y, 150);
let (main, comp) = rational_to_q128_128(&ln_val);
writeln!(file, " (I256::from_words({:?}), {}), // ln(1 + {}/2^40)", main, comp, p).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Taylor coefficients for ln(1+y): 1/n (Tier 4: Q128.128)").unwrap();
writeln!(file, "/// Signs are applied in the Taylor series code, not in the table.").unwrap();
writeln!(file, "pub static LN_TAYLOR_COEFFICIENTS_TIER_4: [(I256, i128); 51] = [").unwrap();
writeln!(file, " (I256::from_words([0, 0, 0, 0]), 0), // placeholder for n=0").unwrap();
for n in 1..=50 {
let coef = BigRational::new(BigInt::from(1), BigInt::from(n));
let (main, comp) = rational_to_q128_128(&coef);
writeln!(file, " (I256::from_words({:?}), {}), // 1/{}", main, comp, n).unwrap();
}
writeln!(file, "];").unwrap();
println!("cargo:warning=✅ Generated Q128.128 ln tables");
}
fn generate_ln_q256_256_tables(out_dir: &str) {
let dest_path = Path::new(out_dir).join("ln_q256_256_tables.rs");
let mut file = File::create(&dest_path).unwrap();
writeln!(file, "// Q256.256 Natural Logarithm Lookup Tables").unwrap();
writeln!(file, "// Generated from BigRational - 77 decimal precision").unwrap();
writeln!(file, "").unwrap();
let ln2 = ln_2_rational(280);
let (ln2_main, ln2_comp) = rational_to_q256_256(&ln2);
writeln!(file, "/// ln(2) constant (Tier 5: Q256.256)").unwrap();
writeln!(file, "pub static LN_2_CONSTANT_TIER_5: (I512, I256) = (I512::from_words({:?}), I256::from_words({:?}));", ln2_main, ln2_comp).unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Primary ln table: ln(1 + k/1024) for k ∈ [0, 1023] (Tier 5: Q256.256)").unwrap();
writeln!(file, "pub static LN_PRIMARY_TABLE_TIER_5: [(I512, I256); 1024] = [").unwrap();
for k in 0..1024 {
let y = BigRational::new(BigInt::from(k), BigInt::from(1024));
let ln_val = ln_1_plus_y_rational(&y, 280);
let (main, comp) = rational_to_q256_256(&ln_val);
writeln!(file, " (I512::from_words({:?}), I256::from_words({:?})), // ln(1 + {}/1024)", main, comp, k).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Secondary ln table: ln(1 + j/2^20) for j ∈ [0, 1023] (Tier 5: Q256.256)").unwrap();
writeln!(file, "pub static LN_SECONDARY_TABLE_TIER_5: [(I512, I256); 1024] = [").unwrap();
for j in 0..1024 {
let y = BigRational::new(BigInt::from(j), BigInt::from(1i128 << 20));
let ln_val = ln_1_plus_y_rational(&y, 280);
let (main, comp) = rational_to_q256_256(&ln_val);
writeln!(file, " (I512::from_words({:?}), I256::from_words({:?})), // ln(1 + {}/2^20)", main, comp, j).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Tertiary ln table: ln(1 + m/2^30) for m ∈ [0, 1023] (Tier 5: Q256.256)").unwrap();
writeln!(file, "pub static LN_TERTIARY_TABLE_TIER_5: [(I512, I256); 1024] = [").unwrap();
for m in 0..1024 {
let y = BigRational::new(BigInt::from(m), BigInt::from(1i128 << 30));
let ln_val = ln_1_plus_y_rational(&y, 280);
let (main, comp) = rational_to_q256_256(&ln_val);
writeln!(file, " (I512::from_words({:?}), I256::from_words({:?})), // ln(1 + {}/2^30)", main, comp, m).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Quaternary ln table: ln(1 + p/2^40) for p ∈ [0, 1023] (Tier 5: Q256.256)").unwrap();
writeln!(file, "pub static LN_QUATERNARY_TABLE_TIER_5: [(I512, I256); 1024] = [").unwrap();
for p in 0..1024 {
let y = BigRational::new(BigInt::from(p), BigInt::from(1i128 << 40));
let ln_val = ln_1_plus_y_rational(&y, 280);
let (main, comp) = rational_to_q256_256(&ln_val);
writeln!(file, " (I512::from_words({:?}), I256::from_words({:?})), // ln(1 + {}/2^40)", main, comp, p).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Taylor coefficients for ln(1+y): 1/n (Tier 5: Q256.256)").unwrap();
writeln!(file, "/// Signs are applied in the Taylor series code, not in the table.").unwrap();
writeln!(file, "pub static LN_TAYLOR_COEFFICIENTS_TIER_5: [(I512, I256); 51] = [").unwrap();
writeln!(file, " (I512::from_words([0, 0, 0, 0, 0, 0, 0, 0]), I256::from_words([0, 0, 0, 0])), // placeholder for n=0").unwrap();
for n in 1..=50 {
let coef = BigRational::new(BigInt::from(1), BigInt::from(n));
let (main, comp) = rational_to_q256_256(&coef);
writeln!(file, " (I512::from_words({:?}), I256::from_words({:?})), // 1/{}", main, comp, n).unwrap();
}
writeln!(file, "];").unwrap();
println!("cargo:warning=✅ Generated Q256.256 ln tables");
}
fn generate_ln_q512_512_tables(out_dir: &str) {
let dest_path = Path::new(out_dir).join("ln_q512_512_tables.rs");
let mut file = File::create(&dest_path).unwrap();
writeln!(file, "// Q512.512 Natural Logarithm Lookup Tables").unwrap();
writeln!(file, "// Generated from BigRational - 154 decimal precision").unwrap();
writeln!(file, "").unwrap();
let ln2 = ln_2_rational(550);
let (ln2_main, ln2_comp) = rational_to_q512_512(&ln2);
writeln!(file, "/// ln(2) constant (Tier 6: Q512.512)").unwrap();
writeln!(file, "pub static LN_2_CONSTANT_TIER_6: (I1024, I512) = (I1024::from_words({:?}), I512::from_words({:?}));", ln2_main, ln2_comp).unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Primary ln table: ln(1 + k/1024) for k ∈ [0, 1023] (Tier 6: Q512.512)").unwrap();
writeln!(file, "pub static LN_PRIMARY_TABLE_TIER_6: [(I1024, I512); 1024] = [").unwrap();
for k in 0..1024 {
let y = BigRational::new(BigInt::from(k), BigInt::from(1024));
let ln_val = ln_1_plus_y_rational(&y, 550);
let (main, comp) = rational_to_q512_512(&ln_val);
writeln!(file, " (I1024::from_words({:?}), I512::from_words({:?})), // ln(1 + {}/1024)", main, comp, k).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Secondary ln table: ln(1 + j/2^20) for j ∈ [0, 1023] (Tier 6: Q512.512)").unwrap();
writeln!(file, "pub static LN_SECONDARY_TABLE_TIER_6: [(I1024, I512); 1024] = [").unwrap();
for j in 0..1024 {
let y = BigRational::new(BigInt::from(j), BigInt::from(1i128 << 20));
let ln_val = ln_1_plus_y_rational(&y, 550);
let (main, comp) = rational_to_q512_512(&ln_val);
writeln!(file, " (I1024::from_words({:?}), I512::from_words({:?})), // ln(1 + {}/2^20)", main, comp, j).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Tertiary ln table: ln(1 + m/2^30) for m ∈ [0, 1023] (Tier 6: Q512.512)").unwrap();
writeln!(file, "pub static LN_TERTIARY_TABLE_TIER_6: [(I1024, I512); 1024] = [").unwrap();
for m in 0..1024 {
let y = BigRational::new(BigInt::from(m), BigInt::from(1i128 << 30));
let ln_val = ln_1_plus_y_rational(&y, 550);
let (main, comp) = rational_to_q512_512(&ln_val);
writeln!(file, " (I1024::from_words({:?}), I512::from_words({:?})), // ln(1 + {}/2^30)", main, comp, m).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Quaternary ln table: ln(1 + p/2^40) for p ∈ [0, 1023] (Tier 6: Q512.512)").unwrap();
writeln!(file, "pub static LN_QUATERNARY_TABLE_TIER_6: [(I1024, I512); 1024] = [").unwrap();
for p in 0..1024 {
let y = BigRational::new(BigInt::from(p), BigInt::from(1i128 << 40));
let ln_val = ln_1_plus_y_rational(&y, 550);
let (main, comp) = rational_to_q512_512(&ln_val);
writeln!(file, " (I1024::from_words({:?}), I512::from_words({:?})), // ln(1 + {}/2^40)", main, comp, p).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Taylor coefficients for ln(1+y): 1/n (Tier 6: Q512.512)").unwrap();
writeln!(file, "/// Signs are applied in the Taylor series code, not in the table.").unwrap();
writeln!(file, "pub static LN_TAYLOR_COEFFICIENTS_TIER_6: [(I1024, I512); 51] = [").unwrap();
writeln!(file, " (I1024::from_words([0; 16]), I512::from_words([0; 8])), // placeholder for n=0").unwrap();
for n in 1..=50 {
let coef = BigRational::new(BigInt::from(1), BigInt::from(n));
let (main, comp) = rational_to_q512_512(&coef);
writeln!(file, " (I1024::from_words({:?}), I512::from_words({:?})), // 1/{}", main, comp, n).unwrap();
}
writeln!(file, "];").unwrap();
println!("cargo:warning=✅ Generated Q512.512 ln tables");
}
const MAX_PRIMES: usize = 100_000;
const PRIME_LIMIT: u64 = 10_000;
fn generate_prime_table_sieve(out_dir: &str) -> Vec<u64> {
println!("cargo:warning=🔍 Sieve of Eratosthenes: generating primes up to {}", PRIME_LIMIT);
let primes = sieve_of_eratosthenes(PRIME_LIMIT);
let dest_path = Path::new(out_dir).join("prime_table.rs");
let mut file = File::create(&dest_path).unwrap();
writeln!(file, "// Generated Prime Table - Pattern Generation Foundation").unwrap();
writeln!(file, "// Generated by sieve of Eratosthenes algorithm").unwrap();
writeln!(file, "// Primes up to {} (first {} primes)", PRIME_LIMIT, primes.len()).unwrap();
writeln!(file, "// DO NOT MODIFY - Generated by build.rs").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "/// Compile-time generated prime table").unwrap();
writeln!(file, "pub const PRIME_TABLE: &[u64] = &[").unwrap();
for (i, &prime) in primes.iter().enumerate() {
if i % 10 == 0 {
write!(file, " ").unwrap();
}
write!(file, "{}", prime).unwrap();
if i < primes.len() - 1 {
write!(file, ", ").unwrap();
}
if i % 10 == 9 || i == primes.len() - 1 {
writeln!(file).unwrap();
}
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "pub const PRIME_COUNT: usize = {};", primes.len()).unwrap();
writeln!(file, "pub const MAX_PRIME: u64 = {};", primes.last().unwrap_or(&0)).unwrap();
primes
}
fn sieve_of_eratosthenes(limit: u64) -> Vec<u64> {
if limit < 2 {
return Vec::new();
}
let capacity_estimate = (limit as usize).max(100) / 10;
let mut primes = Vec::with_capacity(capacity_estimate);
if limit >= 2 { primes.push(2); }
if limit >= 3 { primes.push(3); }
if limit >= 5 { primes.push(5); }
if limit < 7 {
return primes.into_iter().take(MAX_PRIMES).collect();
}
let wheel = [1, 7, 11, 13, 17, 19, 23, 29];
let wheel_size = 30;
let sieve_limit = ((limit - 7) / wheel_size + 1) * wheel.len() as u64;
let mut is_prime = vec![true; sieve_limit as usize];
let sqrt_limit = {
let mut low = 0u64;
let mut high = limit;
while low < high {
let mid = (low + high + 1) / 2;
if mid <= limit / mid {
low = mid;
} else {
high = mid - 1;
}
}
low
};
for base in (0..).map(|k| k * wheel_size).take_while(|&b| b <= sqrt_limit) {
for &offset in &wheel {
let candidate = base + offset;
if candidate < 7 { continue; }
if candidate > sqrt_limit { break; }
let idx = wheel_index(candidate);
if idx < is_prime.len() && is_prime[idx] {
let mut multiple = candidate * candidate;
while multiple <= limit {
let mult_idx = wheel_index(multiple);
if mult_idx < is_prime.len() {
is_prime[mult_idx] = false;
}
multiple += candidate;
}
}
}
}
for base in (0..).map(|k| k * wheel_size).take_while(|&b| b <= limit) {
for &offset in &wheel {
let candidate = base + offset;
if candidate >= 7 && candidate <= limit {
let idx = wheel_index(candidate);
if idx < is_prime.len() && is_prime[idx] {
primes.push(candidate);
if primes.len() >= MAX_PRIMES {
return primes;
}
}
}
}
}
primes
}
fn wheel_index(n: u64) -> usize {
let wheel = [1, 7, 11, 13, 17, 19, 23, 29];
let base = (n / 30) * 8;
let offset = n % 30;
for (i, &w) in wheel.iter().enumerate() {
if w == offset {
return (base + i as u64) as usize;
}
}
((n - 7) / 30 * 8) as usize
}
fn generate_trig_constants(out_dir: &str, _config: &PrecisionConfig) {
let dest_path = Path::new(out_dir).join("trig_constants.rs");
let mut file = File::create(&dest_path).unwrap();
writeln!(file, "// Trigonometric Constants - Generated by build.rs").unwrap();
writeln!(file, "// ZERO float arithmetic - Pure BigRational → Q-format conversion").unwrap();
writeln!(file, "").unwrap();
let pi = compute_pi_rational(580);
let two = BigRational::from(BigInt::from(2));
let four = BigRational::from(BigInt::from(4));
let pi_half = &pi / &two;
let pi_quarter = &pi / &four;
let two_over_pi = &two / π
writeln!(file, "// Q64.64 trigonometric constants (i128)").unwrap();
let (pi_q64, _) = rational_to_q64_64(&pi);
let (pi_half_q64, _) = rational_to_q64_64(&pi_half);
let (pi_quarter_q64, _) = rational_to_q64_64(&pi_quarter);
let (two_over_pi_q64, _) = rational_to_q64_64(&two_over_pi);
writeln!(file, "pub const PI_Q64: i128 = {};", pi_q64).unwrap();
writeln!(file, "pub const PI_HALF_Q64: i128 = {};", pi_half_q64).unwrap();
writeln!(file, "pub const PI_QUARTER_Q64: i128 = {};", pi_quarter_q64).unwrap();
writeln!(file, "pub const TWO_OVER_PI_Q64: i128 = {};", two_over_pi_q64).unwrap();
writeln!(file, "").unwrap();
writeln!(file, "// Q128.128 trigonometric constants (I256 words)").unwrap();
let (pi_q128, _) = rational_to_q128_128(&pi);
let (pi_half_q128, _) = rational_to_q128_128(&pi_half);
let (pi_quarter_q128, _) = rational_to_q128_128(&pi_quarter);
let (two_over_pi_q128, _) = rational_to_q128_128(&two_over_pi);
writeln!(file, "pub const PI_Q128: [u64; 4] = {:?};", pi_q128).unwrap();
writeln!(file, "pub const PI_HALF_Q128: [u64; 4] = {:?};", pi_half_q128).unwrap();
writeln!(file, "pub const PI_QUARTER_Q128: [u64; 4] = {:?};", pi_quarter_q128).unwrap();
writeln!(file, "pub const TWO_OVER_PI_Q128: [u64; 4] = {:?};", two_over_pi_q128).unwrap();
writeln!(file, "").unwrap();
writeln!(file, "// Q256.256 trigonometric constants (I512 words)").unwrap();
let (pi_q256, _) = rational_to_q256_256(&pi);
let (pi_half_q256, _) = rational_to_q256_256(&pi_half);
let (pi_quarter_q256, _) = rational_to_q256_256(&pi_quarter);
let (two_over_pi_q256, _) = rational_to_q256_256(&two_over_pi);
writeln!(file, "pub const PI_Q256: [u64; 8] = {:?};", pi_q256).unwrap();
writeln!(file, "pub const PI_HALF_Q256: [u64; 8] = {:?};", pi_half_q256).unwrap();
writeln!(file, "pub const PI_QUARTER_Q256: [u64; 8] = {:?};", pi_quarter_q256).unwrap();
writeln!(file, "pub const TWO_OVER_PI_Q256: [u64; 8] = {:?};", two_over_pi_q256).unwrap();
writeln!(file, "").unwrap();
writeln!(file, "// Q512.512 trigonometric constants (I1024 words) for tier N+1 computation").unwrap();
let (pi_q512, _) = rational_to_q512_512(&pi);
let (pi_half_q512, _) = rational_to_q512_512(&pi_half);
let (pi_quarter_q512, _) = rational_to_q512_512(&pi_quarter);
let (two_over_pi_q512, _) = rational_to_q512_512(&two_over_pi);
writeln!(file, "pub const PI_Q512: [u64; 16] = {:?};", pi_q512).unwrap();
writeln!(file, "pub const PI_HALF_Q512: [u64; 16] = {:?};", pi_half_q512).unwrap();
writeln!(file, "pub const PI_QUARTER_Q512: [u64; 16] = {:?};", pi_quarter_q512).unwrap();
writeln!(file, "pub const TWO_OVER_PI_Q512: [u64; 16] = {:?};", two_over_pi_q512).unwrap();
writeln!(file, "").unwrap();
let mut factorial: BigInt;
writeln!(file, "// Sin Taylor coefficients: 1/(2k+1)! for k=0,1,2,...").unwrap();
writeln!(file, "// sin(x) = Σ (-1)^k * SIN_COEFF[k] * x^(2k+1)").unwrap();
writeln!(file, "pub const SIN_COEFFS_Q64: [i128; 11] = [").unwrap();
factorial = BigInt::from(1); for k in 0..11 {
let n = 2 * k + 1; if k == 0 {
factorial = BigInt::from(1); } else {
factorial = &factorial * BigInt::from(2 * k) * BigInt::from(2 * k + 1);
}
let coeff = BigRational::new(BigInt::from(1), factorial.clone());
let (val, _) = rational_to_q64_64(&coeff);
writeln!(file, " {}, // 1/{}!", val, n).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "pub const SIN_COEFFS_Q128: [[u64; 4]; 21] = [").unwrap();
factorial = BigInt::from(1);
for k in 0..21 {
let n = 2 * k + 1;
if k == 0 {
factorial = BigInt::from(1);
} else {
factorial = &factorial * BigInt::from(2 * k) * BigInt::from(2 * k + 1);
}
let coeff = BigRational::new(BigInt::from(1), factorial.clone());
let (val, _) = rational_to_q128_128(&coeff);
writeln!(file, " {:?}, // 1/{}!", val, n).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "pub const SIN_COEFFS_Q256: [[u64; 8]; 41] = [").unwrap();
factorial = BigInt::from(1);
for k in 0..41 {
let n = 2 * k + 1;
if k == 0 {
factorial = BigInt::from(1);
} else {
factorial = &factorial * BigInt::from(2 * k) * BigInt::from(2 * k + 1);
}
let coeff = BigRational::new(BigInt::from(1), factorial.clone());
let (val, _) = rational_to_q256_256(&coeff);
writeln!(file, " {:?}, // 1/{}!", val, n).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "pub const SIN_COEFFS_Q512: [[u64; 16]; 65] = [").unwrap();
factorial = BigInt::from(1);
for k in 0..65 {
let n = 2 * k + 1;
if k == 0 {
factorial = BigInt::from(1);
} else {
factorial = &factorial * BigInt::from(2 * k) * BigInt::from(2 * k + 1);
}
let coeff = BigRational::new(BigInt::from(1), factorial.clone());
let (val, _) = rational_to_q512_512(&coeff);
writeln!(file, " {:?}, // 1/{}!", val, n).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "").unwrap();
writeln!(file, "// Cos Taylor coefficients: 1/(2k)! for k=0,1,2,...").unwrap();
writeln!(file, "// cos(x) = Σ (-1)^k * COS_COEFF[k] * x^(2k)").unwrap();
writeln!(file, "pub const COS_COEFFS_Q64: [i128; 11] = [").unwrap();
factorial = BigInt::from(1); for k in 0..11 {
let n = 2 * k; if k == 0 {
factorial = BigInt::from(1); } else {
factorial = &factorial * BigInt::from(2 * k - 1) * BigInt::from(2 * k);
}
let coeff = BigRational::new(BigInt::from(1), factorial.clone());
let (val, _) = rational_to_q64_64(&coeff);
writeln!(file, " {}, // 1/{}!", val, n).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "pub const COS_COEFFS_Q128: [[u64; 4]; 21] = [").unwrap();
factorial = BigInt::from(1);
for k in 0..21 {
let n = 2 * k;
if k == 0 {
factorial = BigInt::from(1);
} else {
factorial = &factorial * BigInt::from(2 * k - 1) * BigInt::from(2 * k);
}
let coeff = BigRational::new(BigInt::from(1), factorial.clone());
let (val, _) = rational_to_q128_128(&coeff);
writeln!(file, " {:?}, // 1/{}!", val, n).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "pub const COS_COEFFS_Q256: [[u64; 8]; 41] = [").unwrap();
factorial = BigInt::from(1);
for k in 0..41 {
let n = 2 * k;
if k == 0 {
factorial = BigInt::from(1);
} else {
factorial = &factorial * BigInt::from(2 * k - 1) * BigInt::from(2 * k);
}
let coeff = BigRational::new(BigInt::from(1), factorial.clone());
let (val, _) = rational_to_q256_256(&coeff);
writeln!(file, " {:?}, // 1/{}!", val, n).unwrap();
}
writeln!(file, "];").unwrap();
writeln!(file, "pub const COS_COEFFS_Q512: [[u64; 16]; 65] = [").unwrap();
factorial = BigInt::from(1);
for k in 0..65 {
let n = 2 * k;
if k == 0 {
factorial = BigInt::from(1);
} else {
factorial = &factorial * BigInt::from(2 * k - 1) * BigInt::from(2 * k);
}
let coeff = BigRational::new(BigInt::from(1), factorial.clone());
let (val, _) = rational_to_q512_512(&coeff);
writeln!(file, " {:?}, // 1/{}!", val, n).unwrap();
}
writeln!(file, "];").unwrap();
let sqrt2_num: BigInt = hardcoded_constants::tier_77d::SQRT_2_NUM_STR.parse().unwrap();
let sqrt2_den: BigInt = hardcoded_constants::tier_77d::SQRT_2_DEN_STR.parse().unwrap();
let sqrt2 = BigRational::new(sqrt2_num, sqrt2_den);
let one = BigRational::from(BigInt::from(1));
let tan_pi_8 = &sqrt2 - &one;
writeln!(file, "").unwrap();
writeln!(file, "// Atan constants").unwrap();
let (tan_pi8_q64, _) = rational_to_q64_64(&tan_pi_8);
let (tan_pi8_q128, _) = rational_to_q128_128(&tan_pi_8);
let (tan_pi8_q256, _) = rational_to_q256_256(&tan_pi_8);
let (tan_pi8_q512, _) = rational_to_q512_512(&tan_pi_8);
writeln!(file, "pub const TAN_PI_8_Q64: i128 = {};", tan_pi8_q64).unwrap();
writeln!(file, "pub const TAN_PI_8_Q128: [u64; 4] = {:?};", tan_pi8_q128).unwrap();
writeln!(file, "pub const TAN_PI_8_Q256: [u64; 8] = {:?};", tan_pi8_q256).unwrap();
writeln!(file, "pub const TAN_PI_8_Q512: [u64; 16] = {:?};", tan_pi8_q512).unwrap();
println!("cargo:warning=✅ Generated trigonometric constants (trig_constants.rs)");
}
fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-env-changed=GMATH_PROFILE");
println!("cargo:rerun-if-env-changed=GMATH_MAX_DECIMAL_PRECISION");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_EMBEDDED");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_EMBEDDED_MINIMAL");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_BALANCED");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_SCIENTIFIC");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_MULTI_PRECISION");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_FAST");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_REBUILD_TABLES");
println!("cargo::rustc-check-cfg=cfg(table_format, values(\"q64_64\", \"q128_128\", \"q256_256\"))");
let out_dir = env::var("OUT_DIR").unwrap();
let profile = detect_deployment_profile();
let config = PrecisionConfig::for_profile(profile);
match config.table_format {
"Q64.64" => println!("cargo:rustc-cfg=table_format=\"q64_64\""),
"Q128.128" => println!("cargo:rustc-cfg=table_format=\"q128_128\""),
"Q256.256" => println!("cargo:rustc-cfg=table_format=\"q256_256\""),
_ => println!("cargo:rustc-cfg=table_format=\"q64_64\""), }
if std::env::var("CARGO_FEATURE_REBUILD_TABLES").is_ok() {
println!("cargo:warning=🚀 gMath Build System - Regenerating Tables");
println!("cargo:warning=📊 Profile: {:?} | Precision: {} decimals | Format: {}",
profile, config.target_decimal_places, config.table_format);
generate_mathematical_constants(&out_dir, &config);
generate_profile_aware_tables(&out_dir, &config);
generate_ln_tables(&out_dir, &config);
generate_trig_constants(&out_dir, &config);
let _primes = generate_prime_table_sieve(&out_dir);
println!("cargo:warning=✅ Generated {} primes up to {}", _primes.len(), PRIME_LIMIT);
println!("cargo:warning=✅ Tables regenerated in OUT_DIR.");
println!("cargo:warning= To update repo: cp $OUT_DIR/*.rs src/generated_tables/");
}
}