mod big_float;
mod small_float;
mod xmpfr;
pub use self::big_float::{Constant, Float, ParseFloatError, Round, Special,
ValidFloat, exp_max, exp_min, prec_max, prec_min};
pub use self::small_float::SmallFloat;
#[cfg(test)]
mod tests {
use float::{Float, Special};
use gmp_mpfr_sys::{gmp, mpfr};
use integer::Integer;
use ops::{Assign, Pow};
#[cfg(feature = "rational")]
use rational::Rational;
use std::{f32, f64, i32, u32};
use std::mem;
use std::str::FromStr;
fn same(a: Float, b: Float) -> bool {
if a.is_nan() && b.is_nan() {
return true;
}
if a == b {
return true;
}
if a.prec() == b.prec() {
return false;
}
a == Float::from((b, a.prec()))
}
#[test]
fn check_ref_op() {
let lhs = Float::from((12.25, 53));
let rhs = Float::from((-1.375, 53));
let pu = 30_u32;
let pi = -15_i32;
let ps = 31.625_f32;
let pd = -1.5_f64;
assert_eq!(Float::from((-&lhs, 53)), -lhs.clone());
assert_eq!(Float::from((&lhs + &rhs, 53)), lhs.clone() + &rhs);
assert_eq!(Float::from((&lhs - &rhs, 53)), lhs.clone() - &rhs);
assert_eq!(Float::from((&lhs * &rhs, 53)), lhs.clone() * &rhs);
assert_eq!(Float::from((&lhs / &rhs, 53)), lhs.clone() / &rhs);
assert_eq!(Float::from(((&lhs).pow(&rhs), 53)), lhs.clone().pow(&rhs));
assert_eq!(Float::from((&lhs + pu, 53)), lhs.clone() + pu);
assert_eq!(Float::from((&lhs - pu, 53)), lhs.clone() - pu);
assert_eq!(Float::from((&lhs * pu, 53)), lhs.clone() * pu);
assert_eq!(Float::from((&lhs / pu, 53)), lhs.clone() / pu);
assert_eq!(Float::from((&lhs << pu, 53)), lhs.clone() << pu);
assert_eq!(Float::from((&lhs >> pu, 53)), lhs.clone() >> pu);
assert_eq!(Float::from(((&lhs).pow(pu), 53)), lhs.clone().pow(pu));
assert_eq!(Float::from((pu + &lhs, 53)), pu + lhs.clone());
assert_eq!(Float::from((pu - &lhs, 53)), pu - lhs.clone());
assert_eq!(Float::from((pu * &lhs, 53)), pu * lhs.clone());
assert_eq!(Float::from((pu / &lhs, 53)), pu / lhs.clone());
assert_eq!(
Float::from((Pow::pow(pu, &lhs), 53)),
Pow::pow(pu, lhs.clone())
);
assert_eq!(Float::from((&lhs + pi, 53)), lhs.clone() + pi);
assert_eq!(Float::from((&lhs - pi, 53)), lhs.clone() - pi);
assert_eq!(Float::from((&lhs * pi, 53)), lhs.clone() * pi);
assert_eq!(Float::from((&lhs / pi, 53)), lhs.clone() / pi);
assert_eq!(Float::from((&lhs << pi, 53)), lhs.clone() << pi);
assert_eq!(Float::from((&lhs >> pi, 53)), lhs.clone() >> pi);
assert_eq!(Float::from(((&lhs).pow(pi), 53)), lhs.clone().pow(pi));
assert_eq!(Float::from((pi + &lhs, 53)), pi + lhs.clone());
assert_eq!(Float::from((pi - &lhs, 53)), pi - lhs.clone());
assert_eq!(Float::from((pi * &lhs, 53)), pi * lhs.clone());
assert_eq!(Float::from((pi / &lhs, 53)), pi / lhs.clone());
assert_eq!(Float::from((&lhs + ps, 53)), lhs.clone() + ps);
assert_eq!(Float::from((&lhs - ps, 53)), lhs.clone() - ps);
assert_eq!(Float::from((&lhs * ps, 53)), lhs.clone() * ps);
assert_eq!(Float::from((&lhs / ps, 53)), lhs.clone() / ps);
assert_eq!(Float::from((ps + &lhs, 53)), ps + lhs.clone());
assert_eq!(Float::from((ps - &lhs, 53)), ps - lhs.clone());
assert_eq!(Float::from((ps * &lhs, 53)), ps * lhs.clone());
assert_eq!(Float::from((ps / &lhs, 53)), ps / lhs.clone());
assert_eq!(Float::from((&lhs + pd, 53)), lhs.clone() + pd);
assert_eq!(Float::from((&lhs - pd, 53)), lhs.clone() - pd);
assert_eq!(Float::from((&lhs * pd, 53)), lhs.clone() * pd);
assert_eq!(Float::from((&lhs / pd, 53)), lhs.clone() / pd);
assert_eq!(Float::from((pd + &lhs, 53)), pd + lhs.clone());
assert_eq!(Float::from((pd - &lhs, 53)), pd - lhs.clone());
assert_eq!(Float::from((pd * &lhs, 53)), pd * lhs.clone());
assert_eq!(Float::from((pd / &lhs, 53)), pd / lhs.clone());
}
#[test]
fn check_arith_others() {
let work_prec = 20;
let check_prec = 100;
let f = [
Float::from((Special::Zero, work_prec)),
Float::from((Special::MinusZero, work_prec)),
Float::from((Special::Infinity, work_prec)),
Float::from((Special::MinusInfinity, work_prec)),
Float::from((Special::Nan, work_prec)),
Float::from((1, work_prec)),
Float::from((-1, work_prec)),
Float::from((999999e100, work_prec)),
Float::from((999999e-100, work_prec)),
Float::from((-999999e100, work_prec)),
Float::from((-999999e-100, work_prec)),
];
let z = [
Integer::from(0),
Integer::from(1),
Integer::from(-1),
Integer::from_str("-1000000000000").unwrap(),
Integer::from_str("1000000000000").unwrap(),
];
#[cfg(feature = "rational")]
let q = [
Rational::from(0),
Rational::from(1),
Rational::from(-1),
Rational::from_str("-1000000000000/33333333333").unwrap(),
Rational::from_str("1000000000000/33333333333").unwrap(),
];
let u = [0, 1, 1000, u32::MAX];
let s = [i32::MIN, -1000, -1, 0, 1, 1000, i32::MAX];
let double = [
f64::INFINITY,
f64::MAX,
f64::MIN_POSITIVE,
0.0,
-0.0,
-f64::MIN_POSITIVE,
f64::MIN,
f64::NEG_INFINITY,
f64::NAN,
1.0,
2.0,
12.0e43,
];
let single = [
f32::INFINITY,
f32::MAX,
f32::MIN_POSITIVE,
0.0,
-0.0,
-f32::MIN_POSITIVE,
f32::MIN,
f32::NEG_INFINITY,
f32::NAN,
1.0,
2.0,
12.0e30,
];
for zz in &z {
let zf = Float::from((zz, check_prec));
for ff in &f {
assert!(same(ff.clone() + zz, ff.clone() + &zf));
assert!(same(ff.clone() - zz, ff.clone() - &zf));
assert!(same(ff.clone() * zz, ff.clone() * &zf));
assert!(same(ff.clone() / zz, ff.clone() / &zf));
assert!(same(zz.clone() + ff.clone(), zf.clone() + ff));
assert!(same(zz.clone() - ff.clone(), zf.clone() - ff));
assert!(same(zz.clone() * ff.clone(), zf.clone() * ff));
assert!(same(zz.clone() / ff.clone(), zf.clone() / ff));
}
}
#[cfg(feature = "rational")]
for qq in &q {
let qf = Float::from((qq, check_prec));
for ff in &f {
assert!(same(ff.clone() + qq, ff.clone() + &qf));
assert!(same(ff.clone() - qq, ff.clone() - &qf));
assert!(same(ff.clone() * qq, ff.clone() * &qf));
assert!(same(ff.clone() / qq, ff.clone() / &qf));
assert!(same(qq.clone() + ff.clone(), qf.clone() + ff));
assert!(same(qq.clone() - ff.clone(), qf.clone() - ff));
assert!(same(qq.clone() * ff.clone(), qf.clone() * ff));
assert!(same(qq.clone() / ff.clone(), qf.clone() / ff));
}
}
for uu in &u {
let uf = Float::from((*uu, check_prec));
for ff in &f {
assert!(same(ff.clone() + *uu, ff.clone() + &uf));
assert!(same(ff.clone() - *uu, ff.clone() - &uf));
assert!(same(ff.clone() * *uu, ff.clone() * &uf));
assert!(same(ff.clone() / *uu, ff.clone() / &uf));
assert!(same(*uu + ff.clone(), uf.clone() + ff));
assert!(same(*uu - ff.clone(), uf.clone() - ff));
assert!(same(*uu * ff.clone(), uf.clone() * ff));
assert!(same(*uu / ff.clone(), uf.clone() / ff));
}
}
for ss in &s {
let sf = Float::from((*ss, check_prec));
for ff in &f {
assert!(same(ff.clone() + *ss, ff.clone() + &sf));
assert!(same(ff.clone() - *ss, ff.clone() - &sf));
assert!(same(ff.clone() * *ss, ff.clone() * &sf));
assert!(same(ff.clone() / *ss, ff.clone() / &sf));
assert!(same(*ss + ff.clone(), sf.clone() + ff));
assert!(same(*ss - ff.clone(), sf.clone() - ff));
assert!(same(*ss * ff.clone(), sf.clone() * ff));
assert!(same(*ss / ff.clone(), sf.clone() / ff));
}
}
for oo in &double {
let of = Float::from((*oo, check_prec));
for ff in &f {
assert!(same(ff.clone() + *oo, ff.clone() + &of));
assert!(same(ff.clone() - *oo, ff.clone() - &of));
assert!(same(ff.clone() * *oo, ff.clone() * &of));
assert!(same(ff.clone() / *oo, ff.clone() / &of));
assert!(same(*oo + ff.clone(), of.clone() + ff));
assert!(same(*oo - ff.clone(), of.clone() - ff));
assert!(same(*oo * ff.clone(), of.clone() * ff));
assert!(same(*oo / ff.clone(), of.clone() / ff));
}
}
for oo in &single {
let of = Float::from((*oo, check_prec));
for ff in &f {
assert!(same(ff.clone() + *oo, ff.clone() + &of));
assert!(same(ff.clone() - *oo, ff.clone() - &of));
assert!(same(ff.clone() * *oo, ff.clone() * &of));
assert!(same(ff.clone() / *oo, ff.clone() / &of));
assert!(same(*oo + ff.clone(), of.clone() + ff));
assert!(same(*oo - ff.clone(), of.clone() - ff));
assert!(same(*oo * ff.clone(), of.clone() * ff));
assert!(same(*oo / ff.clone(), of.clone() / ff));
}
}
}
#[test]
fn check_from_str() {
assert!(Float::from_str_radix("-@nan@", 2, 53).unwrap().is_nan());
assert!(Float::from_str("-0", 53).unwrap().get_sign());
assert!(!Float::from_str("+0", 53).unwrap().get_sign());
assert!(Float::from_str("1e1000", 53).unwrap().is_finite());
let huge_hex = "1@99999999999999999999999999999999";
assert!(
Float::from_str_radix(huge_hex, 16, 53)
.unwrap()
.is_infinite()
);
let bad_strings = [
("inf", 16),
("1e", 10),
("e10", 10),
(".e10", 10),
("1e1.", 10),
("1e+-1", 10),
("1e-+1", 10),
("+-1", 10),
("-+1", 10),
("infinit", 10),
("1@1a", 16),
("9e0", 9),
];
for &(s, radix) in bad_strings.into_iter() {
assert!(Float::valid_str_radix(s, radix).is_err());
}
let good_strings = [
("INF", 10, f64::INFINITY),
("-@iNf@", 16, f64::NEG_INFINITY),
("+0e99", 2, 0.0),
("-9.9e1", 10, -99.0),
("-.99e+2", 10, -99.0),
("+99.e+0", 10, 99.0),
("-99@-1", 10, -9.9f64),
("-abc.def@3", 16, -0xabcdef as f64),
("1e1023", 2, 2.0f64.powi(1023)),
];
for &(s, radix, f) in good_strings.into_iter() {
assert_eq!(Float::from_str_radix(s, radix, 53).unwrap(), f);
}
}
#[test]
fn check_formatting() {
let mut f = Float::from((Special::Zero, 53));
assert_eq!(format!("{}", f), "0.0");
assert_eq!(format!("{:?}", f), "0.0");
assert_eq!(format!("{:+?}", f), "+0.0");
f.assign(Special::MinusZero);
assert_eq!(format!("{}", f), "0.0");
assert_eq!(format!("{:?}", f), "-0.0");
assert_eq!(format!("{:+?}", f), "-0.0");
f.assign(-27);
assert_eq!(format!("{:.2}", f), "-2.7e1");
assert_eq!(format!("{:.4?}", f), "-2.700e1");
assert_eq!(format!("{:.4e}", f), "-2.700e1");
assert_eq!(format!("{:.4E}", f), "-2.700E1");
assert_eq!(format!("{:.8b}", f), "-1.1011000e4");
assert_eq!(format!("{:.3b}", f), "-1.11e4");
assert_eq!(format!("{:#.8b}", f), "-0b1.1011000e4");
assert_eq!(format!("{:.2o}", f), "-3.3e1");
assert_eq!(format!("{:#.2o}", f), "-0o3.3e1");
assert_eq!(format!("{:.2x}", f), "-1.b@1");
assert_eq!(format!("{:.2X}", f), "-1.B@1");
assert_eq!(format!("{:12.1x}", f), " -1.b@1");
assert_eq!(format!("{:012.3X}", f), "-000001.B0@1");
assert_eq!(format!("{:#012.2x}", f), "-0x00001.b@1");
assert_eq!(format!("{:#12.2X}", f), " -0x1.B@1");
}
#[test]
fn check_assumptions() {
assert_eq!(gmp::NAIL_BITS, 0);
assert_eq!(gmp::NUMB_BITS, gmp::LIMB_BITS);
assert_eq!(gmp::NUMB_BITS as usize, 8 * mem::size_of::<gmp::limb_t>());
assert_eq!(unsafe { mpfr::custom_get_size(64) }, 8);
}
}