mod arith;
mod cmp;
mod ord_float;
mod small_float;
mod traits;
pub use big_float::{ParseFloatError, ValidFloat};
pub use float::ord_float::OrdFloat;
pub use float::small_float::SmallFloat;
use gmp_mpfr_sys::mpfr;
use std::{i32, u32};
use std::mem;
#[inline]
pub fn exp_min() -> i32 {
let min = unsafe { mpfr::get_emin() };
if min > mpfr::exp_t::from(i32::MIN) {
min as i32
} else {
i32::MIN
}
}
#[inline]
pub fn exp_max() -> i32 {
let max = unsafe { mpfr::get_emax() };
if max < mpfr::exp_t::from(i32::MAX) {
max as i32
} else {
i32::MAX
}
}
#[inline]
pub fn prec_min() -> u32 {
mpfr::PREC_MIN as u32
}
#[inline]
pub fn prec_max() -> u32 {
let max = mpfr::PREC_MAX;
if mem::size_of::<mpfr::prec_t>() <= mem::size_of::<u32>()
|| max < u32::MAX as mpfr::prec_t
{
max as u32
} else {
u32::MAX
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Round {
Nearest,
Zero,
Up,
Down,
AwayFromZero,
}
impl Default for Round {
#[inline]
fn default() -> Round {
Round::Nearest
}
}
pub trait AssignRound<Rhs = Self> {
type Round;
type Ordering;
fn assign_round(&mut self, rhs: Rhs, round: Self::Round) -> Self::Ordering;
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Constant {
Log2,
Pi,
Euler,
Catalan,
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Special {
Zero,
NegZero,
Infinity,
NegInfinity,
Nan,
}
#[cfg(test)]
mod tests {
use {Assign, Float};
use float::Special;
use gmp_mpfr_sys::{gmp, mpfr};
use std::f64;
use std::mem;
#[test]
fn check_from_str() {
assert!(Float::from_str_radix("-@nan@", 2, 53).unwrap().is_nan());
assert!(Float::from_str("-0", 53).unwrap().is_sign_negative());
assert!(Float::from_str("+0", 53).unwrap().is_sign_positive());
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),
("9", 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::with_val(53, Special::Zero);
assert_eq!(format!("{}", f), "0.0");
assert_eq!(format!("{:?}", f), "0.0");
assert_eq!(format!("{:+?}", f), "+0.0");
f.assign(Special::NegZero);
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);
}
}