use std::time::{Duration, Instant};
use puremp::{Decimal, Float, Int, Rational, RoundingMode};
fn bench<F, R>(label: &str, iters: u32, f: F)
where
F: Fn() -> R,
{
let mut best = Duration::MAX;
let _ = f(); for _ in 0..5 {
let start = Instant::now();
for _ in 0..iters {
std::hint::black_box(f());
}
best = best.min(start.elapsed() / iters);
}
println!("{label:<36} {best:?}/iter");
}
fn factorial(n: u64) -> Int {
(2..=n).fold(Int::one(), |acc, k| acc.mul(&Int::from_i64(k as i64)))
}
fn main() {
let n = RoundingMode::Nearest;
println!("== multiplication ==");
for &bits in &[1_000u32, 10_000, 100_000] {
let a = Int::from_i64(7).pow(bits / 3);
let b = Int::from_i64(5).pow(bits / 3);
let iters = if bits <= 10_000 { 500 } else { 20 };
bench(&format!("mul ~{}k-bit", bits / 1000), iters, || a.mul(&b));
}
println!("== division (Knuth-D / Burnikel–Ziegler) ==");
for &bits in &[1_000u32, 10_000, 100_000] {
let d = Int::from_i64(7).pow(bits / 3);
let num = d
.mul(&Int::from_i64(5).pow(bits / 3))
.add(&Int::from_i64(123));
let iters = if bits <= 10_000 { 300 } else { 10 };
bench(
&format!("div ~{}k / {}k", bits / 1000, bits / 2000),
iters,
|| num.div_rem(&d),
);
}
println!("== gcd / modpow ==");
let g1 = Int::from_i64(7).pow(5000); let g2 = Int::from_i64(11).pow(4000); bench("gcd ~14k-bit coprime", 200, || g1.gcd(&g2));
let modulus = Int::from_i64(3).pow(1000); let base = Int::from_i64(5).pow(500);
let exp = Int::from_i64(7).pow(400);
bench("modpow ~1.5k-bit", 50, || base.modpow(&exp, &modulus));
println!("== roots / base-10 I/O ==");
let big = factorial(20_000);
println!(" (factorial(20000) = {} bits)", big.magnitude().bit_len());
bench("isqrt ~257k-bit", 20, || big.magnitude().isqrt());
bench("to_string ~257k-bit", 10, || big.to_string().len());
let decimal = big.to_string();
bench("from_string ~257k-bit", 10, || {
decimal.parse::<Int>().unwrap()
});
println!("== rational ==");
let r = Rational::new(Int::from_i64(355), Int::from_i64(113));
bench("rational add+reduce", 5000, || r.add(&r).mul(&r));
println!("== float @ 1000 bits ==");
let two = Float::from_int(&Int::from_i64(2), 1000, n);
bench("sqrt(2)", 500, || two.sqrt(1000, n));
bench("pi", 20, || Float::pi(1000, n));
bench("exp(1)", 20, || Float::e(1000, n));
println!("== derived types ==");
let da = Decimal::new(Int::from_i64(31415926535), -10);
let db = Decimal::new(Int::from_i64(27182818284), -10);
bench("decimal mul (exact)", 20_000, || da.mul(&db));
bench("decimal div @ 50 digits", 5_000, || {
da.div(&db, 50, puremp::Rounding::HalfEven)
});
#[cfg(feature = "poly")]
{
use puremp::Poly;
let p: Poly<Rational> = Poly::new((0..=60).map(|i| Rational::from(i as i64 + 1)).collect());
let q: Poly<Rational> = Poly::new((0..=60).map(|i| Rational::from(i as i64 + 2)).collect());
bench("poly mul (deg 60, Q)", 200, || p.mul(&q));
}
#[cfg(feature = "matrix")]
{
use puremp::Matrix;
let m: Matrix<Rational> = Matrix::new(
8,
8,
(0..64)
.map(|i| Rational::from(((i * 7 + 3) % 11) as i64 + 1))
.collect(),
);
bench("matrix det 8x8 (Q)", 500, || m.determinant());
}
#[cfg(feature = "algebraic")]
{
use puremp::Algebraic;
let poly = |cs: &[i64]| puremp::Poly::new(cs.iter().map(|&c| Rational::from(c)).collect());
let r2 = Algebraic::new(poly(&[-2, 0, 1]), Rational::from(0), Rational::from(2));
let r3 = Algebraic::new(poly(&[-3, 0, 1]), Rational::from(0), Rational::from(2));
bench("algebraic sqrt2+sqrt3 (deg 4)", 200, || r2.add(&r3));
}
}