use super::small_float::SmallFloat;
use super::xmpfr;
use gmp_mpfr_sys::mpfr::{self, mpfr_t};
use inner::{Inner, InnerMut};
use integer::Integer;
use ops::{AddRound, Assign, AssignRound, DivFromAssign, DivRound, FromRound,
MulRound, NegAssign, Pow, PowAssign, PowFromAssign, PowRound,
SubFromAssign, SubRound};
use rand::RandState;
#[cfg(feature = "rational")]
use rational::Rational;
use std::{i32, u32};
use std::ascii::AsciiExt;
use std::cmp::Ordering;
use std::error::Error;
use std::ffi::CStr;
use std::fmt::{self, Binary, Debug, Display, Formatter, LowerExp, LowerHex,
Octal, UpperExp, UpperHex};
use std::mem;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Shl,
ShlAssign, Shr, ShrAssign, Sub, SubAssign};
use std::os::raw::{c_char, c_int, c_long, c_ulong};
use std::ptr;
pub fn exp_min() -> i32 {
let min = unsafe { mpfr::get_emin() };
if mem::size_of::<mpfr::exp_t>() <= mem::size_of::<i32>() ||
min > i32::MIN as mpfr::exp_t
{
min as i32
} else {
i32::MIN
}
}
pub fn exp_max() -> i32 {
let max = unsafe { mpfr::get_emax() };
if mem::size_of::<mpfr::exp_t>() <= mem::size_of::<i32>() ||
max < i32::MAX as mpfr::exp_t
{
max as i32
} else {
i32::MAX
}
}
pub fn prec_min() -> u32 {
mpfr::PREC_MIN as u32
}
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, PartialEq, Eq)]
pub enum Round {
Nearest,
Zero,
Up,
Down,
AwayFromZero,
}
impl Default for Round {
fn default() -> Round {
Round::Nearest
}
}
fn rraw(round: Round) -> mpfr::rnd_t {
match round {
Round::Nearest => mpfr::rnd_t::RNDN,
Round::Zero => mpfr::rnd_t::RNDZ,
Round::Up => mpfr::rnd_t::RNDU,
Round::Down => mpfr::rnd_t::RNDD,
Round::AwayFromZero => mpfr::rnd_t::RNDA,
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Constant {
Log2,
Pi,
Euler,
Catalan,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Special {
Zero,
MinusZero,
Infinity,
MinusInfinity,
Nan,
}
fn ordering1(ord: c_int) -> Ordering {
ord.cmp(&0)
}
fn ordering2(ord: c_int) -> (Ordering, Ordering) {
let first = match ord & 3 {
2 => -1,
0 => 0,
1 => 1,
_ => unreachable!(),
};
let second = match ord >> 2 {
2 => -1,
0 => 0,
1 => 1,
_ => unreachable!(),
};
(ordering1(first), ordering1(second))
}
pub struct Float {
inner: mpfr_t,
}
impl Clone for Float {
fn clone(&self) -> Float {
let mut ret = Float::new(self.prec());
ret.assign(self);
ret
}
fn clone_from(&mut self, source: &Float) {
self.set_prec(source.prec());
self.assign(source);
}
}
impl Drop for Float {
fn drop(&mut self) {
unsafe {
mpfr::clear(self.inner_mut());
}
}
}
macro_rules! math_op1_float {
{
$func:path;
$(#[$attr:meta])*
fn $method:ident($($param:ident: $T:ty),*);
$(#[$attr_round:meta])*
fn $method_round:ident;
$(#[$attr_ref:meta])*
fn $method_ref:ident -> $Ref:ident;
} => {
math_op1_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$(#[$attr])*
fn $method($($param: $T),*);
$(#[$attr_round])*
fn $method_round;
$(#[$attr_ref])*
fn $method_ref -> $Ref;
}
}
}
macro_rules! ref_math_op1_float {
{
$func:path;
$(#[$attr_ref:meta])*
struct $Ref:ident { $($param:ident: $T:ty),* }
} => {
ref_math_op1_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$(#[$attr_ref])*
struct $Ref { $($param: $T),* }
}
}
}
macro_rules! math_op1_2_float {
{
$func:path;
$(#[$attr:meta])*
fn $method:ident($rop:ident $(, $param:ident: $T:ty),*);
$(#[$attr_round:meta])*
fn $method_round:ident;
$(#[$attr_ref:meta])*
fn $method_ref:ident -> $Ref:ident;
} => {
math_op1_2_round! {
Float, Round => (Ordering, Ordering);
$func, rraw => ordering2;
$(#[$attr])*
fn $method($rop $(, $param: $T)*);
$(#[$attr_round])*
fn $method_round;
$(#[$attr_ref])*
fn $method_ref -> $Ref;
}
}
}
macro_rules! ref_math_op1_2_float {
{
$func:path;
$(#[$attr_ref:meta])*
struct $Ref:ident { $($param:ident: $T:ty),* }
} => {
ref_math_op1_2_round! {
Float, Round => (Ordering, Ordering);
$func, rraw => ordering2;
$(#[$attr_ref])*
struct $Ref { $($param: $T),* }
}
}
}
macro_rules! math_op2_float {
{
$func:path;
$(#[$attr:meta])*
fn $method:ident($op:ident $(, $param:ident: $T:ty),*);
$(#[$attr_round:meta])*
fn $method_round:ident;
$(#[$attr_ref:meta])*
fn $method_ref:ident -> $Ref:ident;
} => {
math_op2_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$(#[$attr])*
fn $method($op $(, $param: $T)*);
$(#[$attr_round])*
fn $method_round;
$(#[$attr_ref])*
fn $method_ref -> $Ref;
}
}
}
macro_rules! ref_math_op2_float {
{
$func:path;
$(#[$attr_ref:meta])*
struct $Ref:ident { $op:ident $(, $param:ident: $T:ty),* }
} => {
ref_math_op2_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$(#[$attr_ref])*
struct $Ref { $op $(, $param: $T)* }
}
}
}
impl Float {
pub fn new(prec: u32) -> Float {
assert!(
prec >= prec_min() && prec <= prec_max(),
"precision out of range"
);
unsafe {
let mut inner: mpfr_t = mem::uninitialized();
mpfr::init2(&mut inner, prec as mpfr::prec_t);
mpfr::set_zero(&mut inner, 0);
Float { inner: inner }
}
}
pub fn prec(&self) -> u32 {
unsafe { mpfr::get_prec(self.inner()) as u32 }
}
pub fn set_prec(&mut self, prec: u32) {
self.set_prec_round(prec, Round::Nearest);
}
pub fn set_prec_round(&mut self, prec: u32, round: Round) -> Ordering {
assert!(
prec >= prec_min() && prec <= prec_max(),
"precision out of range"
);
let mpfr_ret = unsafe {
mpfr::prec_round(
self.inner_mut(),
prec as mpfr::prec_t,
rraw(round),
)
};
mpfr_ret.cmp(&0)
}
pub fn from_str(src: &str, prec: u32) -> Result<Float, ParseFloatError> {
let mut f = Float::new(prec);
f.assign_str(src)?;
Ok(f)
}
pub fn from_str_round(
src: &str,
prec: u32,
round: Round,
) -> Result<(Float, Ordering), ParseFloatError> {
let mut f = Float::new(prec);
let ord = f.assign_str_round(src, round)?;
Ok((f, ord))
}
pub fn from_str_radix(
src: &str,
radix: i32,
prec: u32,
) -> Result<Float, ParseFloatError> {
let mut f = Float::new(prec);
f.assign_str_radix(src, radix)?;
Ok(f)
}
pub fn from_str_radix_round(
src: &str,
radix: i32,
prec: u32,
round: Round,
) -> Result<(Float, Ordering), ParseFloatError> {
let mut f = Float::new(prec);
let ord = f.assign_str_radix_round(src, radix, round)?;
Ok((f, ord))
}
pub fn valid_str_radix(
src: &str,
radix: i32,
) -> Result<ValidFloat, ParseFloatError> {
use self::ParseFloatError as Error;
use self::ParseErrorKind as Kind;
let mut v = ValidFloat {
poss: ValidPoss::Special(Special::Nan),
radix: radix,
exp_plus: None,
};
assert!(radix >= 2 && radix <= 36, "radix out of range");
let bytes = src.as_bytes();
let inf10: &[&[u8]] = &[b"inf", b"+inf", b"infinity", b"+infinity"];
let inf: &[&[u8]] =
&[b"@inf@", b"+@inf@", b"@infinity@", b"+@infinity@"];
if (radix <= 10 && lcase_in(bytes, inf10)) || lcase_in(bytes, inf) {
v.poss = ValidPoss::Special(Special::Infinity);
return Ok(v);
}
let neg_inf10: &[&[u8]] = &[b"-inf", b"-infinity"];
let neg_inf: &[&[u8]] = &[b"-@inf@", b"-@infinity@"];
if (radix <= 10 && lcase_in(bytes, neg_inf10)) ||
lcase_in(bytes, neg_inf)
{
v.poss = ValidPoss::Special(Special::MinusInfinity);
return Ok(v);
}
let nan10: &[&[u8]] = &[b"nan", b"+nan", b"-nan"];
let nan: &[&[u8]] = &[b"@nan@", b"+@nan@", b"-@nan@"];
if (radix <= 10 && lcase_in(bytes, nan10)) || lcase_in(bytes, nan) {
v.poss = ValidPoss::Special(Special::Nan);
return Ok(v);
}
let mut iter = bytes.iter();
let starts_with_plus = bytes.starts_with(&[b'+']);
let starts_with_minus = bytes.starts_with(&[b'-']);
if starts_with_plus || starts_with_minus {
iter.next();
}
let mut got_digit = false;
let mut got_point = false;
let mut exp = false;
let mut fresh_exp = false;
for (i, b) in iter.enumerate() {
if fresh_exp {
fresh_exp = false;
if *b == b'-' {
continue;
}
if *b == b'+' {
v.exp_plus = if starts_with_minus {
Some(i + 1)
} else {
Some(i)
};
continue;
}
}
if *b == b'.' {
if exp {
return Err(Error { kind: Kind::PointInExp });
}
if got_point {
return Err(Error { kind: Kind::TooManyPoints });
}
got_point = true;
continue;
}
if (radix <= 10 && (*b == b'e' || *b == b'E')) || *b == b'@' {
if exp {
return Err(Error { kind: Kind::TooManyExp });
}
if !got_digit {
return Err(Error { kind: Kind::SignifNoDigits });
}
got_digit = false;
exp = true;
fresh_exp = true;
continue;
}
let digit = match *b {
b'0'...b'9' => *b - b'0',
b'a'...b'z' => *b - b'a' + 10,
b'A'...b'Z' => *b - b'A' + 10,
_ => Err(Error { kind: Kind::InvalidDigit })?,
};
if (!exp && digit >= radix as u8) || (exp && digit >= 10) {
return Err(Error { kind: Kind::InvalidDigit });
}
got_digit = true;
}
if !got_digit && exp {
return Err(Error { kind: Kind::ExpNoDigits });
} else if !got_digit {
return Err(Error { kind: Kind::NoDigits });
}
v.poss = if starts_with_plus {
ValidPoss::Bytes(&bytes[1..])
} else {
ValidPoss::Bytes(bytes)
};
Ok(v)
}
pub fn to_integer(&self) -> Option<Integer> {
self.to_integer_round(Round::Nearest).map(|x| x.0)
}
pub fn to_integer_round(
&self,
round: Round,
) -> Option<(Integer, Ordering)> {
if !self.is_finite() {
return None;
}
let mut i = Integer::new();
let mpfr_ret =
unsafe { mpfr::get_z(i.inner_mut(), self.inner(), rraw(round)) };
Some((i, mpfr_ret.cmp(&0)))
}
pub fn to_integer_exp(&self) -> Option<(Integer, i32)> {
if !self.is_finite() {
return None;
}
let mut i = Integer::new();
let exp =
unsafe { mpfr::get_z_2exp(i.inner_mut(), self.inner()) as i32 };
Some((i, exp))
}
#[cfg(feature = "rational")]
pub fn to_rational(&self) -> Option<Rational> {
self.to_integer_exp().map(
|(num, exp)| Rational::from(num) << exp,
)
}
pub fn to_i32_saturating(&self) -> Option<i32> {
self.to_i32_saturating_round(Round::Nearest)
}
pub fn to_i32_saturating_round(&self, round: Round) -> Option<i32> {
if self.is_nan() {
return None;
}
let i = unsafe { mpfr::get_si(self.inner(), rraw(round)) };
if i >= i32::MAX as c_long {
Some(i32::MAX)
} else if i <= i32::MIN as c_long {
Some(i32::MIN)
} else {
Some(i as i32)
}
}
pub fn to_u32_saturating(&self) -> Option<u32> {
self.to_u32_saturating_round(Round::Nearest)
}
pub fn to_u32_saturating_round(&self, round: Round) -> Option<u32> {
if self.is_nan() {
return None;
}
let u = unsafe { mpfr::get_ui(self.inner(), rraw(round)) };
if u >= u32::MAX as c_ulong {
Some(u32::MAX)
} else {
Some(u as u32)
}
}
pub fn to_f32(&self) -> f32 {
self.to_f32_round(Round::Nearest)
}
pub fn to_f32_round(&self, round: Round) -> f32 {
self.to_f64_round(round) as f32
}
pub fn to_f64(&self) -> f64 {
self.to_f64_round(Round::Nearest)
}
pub fn to_f64_round(&self, round: Round) -> f64 {
unsafe { mpfr::get_d(self.inner(), rraw(round)) }
}
pub fn to_f32_exp(&self) -> (f32, i32) {
self.to_f32_exp_round(Round::Nearest)
}
pub fn to_f32_exp_round(&self, round: Round) -> (f32, i32) {
let sf = SmallFloat::from(0.0f32);
assert_eq!(sf.prec(), 24);
let mut_sf = unsafe {
let ptr: *mut Float = &*sf as *const Float as *mut Float;
&mut *ptr
};
let mut exp: c_long = 0;
let f = unsafe {
mpfr::set(mut_sf.inner_mut(), self.inner(), rraw(round));
mpfr::get_d_2exp(&mut exp, mut_sf.inner(), rraw(round))
};
assert_eq!(exp as i32 as c_long, exp, "overflow");
(f as f32, exp as i32)
}
pub fn to_f64_exp(&self) -> (f64, i32) {
self.to_f64_exp_round(Round::Nearest)
}
pub fn to_f64_exp_round(&self, round: Round) -> (f64, i32) {
let mut exp: c_long = 0;
let f =
unsafe { mpfr::get_d_2exp(&mut exp, self.inner(), rraw(round)) };
assert_eq!(exp as i32 as c_long, exp, "overflow");
(f, exp as i32)
}
pub fn to_string_radix(
&self,
radix: i32,
num_digits: Option<usize>,
) -> String {
self.to_string_radix_round(radix, num_digits, Round::Nearest)
}
pub fn to_string_radix_round(
&self,
radix: i32,
num_digits: Option<usize>,
round: Round,
) -> String {
make_string(self, radix, num_digits, round, false)
}
pub fn assign_str(&mut self, src: &str) -> Result<(), ParseFloatError> {
self.assign_str_radix(src, 10)
}
pub fn assign_str_round(
&mut self,
src: &str,
round: Round,
) -> Result<Ordering, ParseFloatError> {
self.assign_str_radix_round(src, 10, round)
}
pub fn assign_str_radix(
&mut self,
src: &str,
radix: i32,
) -> Result<(), ParseFloatError> {
self.assign_str_radix_round(src, radix, Round::Nearest)?;
Ok(())
}
pub fn assign_str_radix_round(
&mut self,
src: &str,
radix: i32,
round: Round,
) -> Result<Ordering, ParseFloatError> {
Ok(self.assign_round(
Float::valid_str_radix(src, radix)?,
round,
))
}
pub fn is_integer(&self) -> bool {
unsafe { mpfr::integer_p(self.inner()) != 0 }
}
pub fn is_nan(&self) -> bool {
unsafe { mpfr::nan_p(self.inner()) != 0 }
}
pub fn is_infinite(&self) -> bool {
unsafe { mpfr::inf_p(self.inner()) != 0 }
}
pub fn is_finite(&self) -> bool {
unsafe { mpfr::number_p(self.inner()) != 0 }
}
pub fn is_zero(&self) -> bool {
unsafe { mpfr::zero_p(self.inner()) != 0 }
}
pub fn is_normal(&self) -> bool {
unsafe { mpfr::regular_p(self.inner()) != 0 }
}
pub fn sign(&self) -> Option<Ordering> {
if self.is_nan() {
None
} else {
let mpfr_ret = unsafe { mpfr::sgn(self.inner()) };
Some(mpfr_ret.cmp(&0))
}
}
pub fn cmp_abs(&self, other: &Float) -> Option<Ordering> {
unsafe {
match mpfr::unordered_p(self.inner(), other.inner()) {
0 => Some(mpfr::cmpabs(self.inner(), other.inner()).cmp(&0)),
_ => None,
}
}
}
pub fn get_exp(&self) -> Option<i32> {
if self.is_normal() {
let e = unsafe { mpfr::get_exp(self.inner()) };
assert!(e <= i32::MAX as mpfr::exp_t, "overflow");
Some(e as i32)
} else {
None
}
}
pub fn get_sign(&self) -> bool {
unsafe { mpfr::signbit(self.inner()) != 0 }
}
pub fn subnormalize(&mut self) -> &mut Float {
self.subnormalize_round(Ordering::Equal, Round::Nearest);
self
}
pub fn subnormalize_round(
&mut self,
prev_rounding: Ordering,
round: Round,
) -> Ordering {
let prev = match prev_rounding {
Ordering::Less => -1,
Ordering::Equal => 0,
Ordering::Greater => 1,
};
let mpfr_ret =
unsafe { mpfr::subnormalize(self.inner_mut(), prev, rraw(round)) };
mpfr_ret.cmp(&0)
}
math_op1_float! {
mpfr::sqr;
fn square();
fn square_round;
fn square_ref -> SquareRef;
}
math_op1_float! {
mpfr::sqrt;
fn sqrt();
fn sqrt_round;
fn sqrt_ref -> SqrtRef;
}
pub fn assign_sqrt_u(&mut self, u: u32) {
self.assign_sqrt_u_round(u, Round::Nearest);
}
pub fn assign_sqrt_u_round(&mut self, u: u32, round: Round) -> Ordering {
let mpfr_ret =
unsafe { mpfr::sqrt_ui(self.inner_mut(), u.into(), rraw(round)) };
mpfr_ret.cmp(&0)
}
math_op1_float! {
mpfr::rec_sqrt;
fn recip_sqrt();
fn recip_sqrt_round;
fn recip_sqrt_ref -> RecipSqrtRef;
}
math_op1_float! {
mpfr::cbrt;
fn cbrt();
fn cbrt_round;
fn cbrt_ref -> CbrtRef;
}
math_op1_float! {
mpfr::root;
fn root(k: u32);
fn root_round;
fn root_ref -> RootRef;
}
math_op1_float! {
mpfr::abs;
fn abs();
fn abs_round;
fn abs_ref -> AbsRef;
}
math_op1_float! {
xmpfr::recip;
fn recip();
fn recip_round;
fn recip_ref -> RecipRef;
}
math_op2_float! {
mpfr::dim;
fn abs_diff(other);
fn abs_diff_round;
fn abs_diff_ref -> AbsDiffRef;
}
math_op1_float! {
mpfr::log;
fn ln();
fn ln_round;
fn ln_ref -> LnRef;
}
math_op1_float! {
mpfr::log2;
fn log2();
fn log2_round;
fn log2_ref -> Log2Ref;
}
math_op1_float! {
mpfr::log10;
fn log10();
fn log10_round;
fn log10_ref -> Log10Ref;
}
math_op1_float! {
mpfr::exp;
fn exp();
fn exp_round;
fn exp_ref -> ExpRef;
}
math_op1_float! {
mpfr::exp2;
fn exp2();
fn exp2_round;
fn exp2_ref -> Exp2Ref;
}
math_op1_float! {
mpfr::exp10;
fn exp10();
fn exp10_round;
fn exp10_ref -> Exp10Ref;
}
math_op1_float! {
mpfr::sin;
fn sin();
fn sin_round;
fn sin_ref -> SinRef;
}
math_op1_float! {
mpfr::cos;
fn cos();
fn cos_round;
fn cos_ref -> CosRef;
}
math_op1_float! {
mpfr::tan;
fn tan();
fn tan_round;
fn tan_ref -> TanRef;
}
math_op1_2_float! {
mpfr::sin_cos;
fn sin_cos(cos);
fn sin_cos_round;
fn sin_cos_ref -> SinCosRef;
}
math_op1_float! {
mpfr::sec;
fn sec();
fn sec_round;
fn sec_ref -> SecRef;
}
math_op1_float! {
mpfr::csc;
fn csc();
fn csc_round;
fn csc_ref -> CscRef;
}
math_op1_float! {
mpfr::cot;
fn cot();
fn cot_round;
fn cot_ref -> CotRef;
}
math_op1_float! {
mpfr::acos;
fn acos();
fn acos_round;
fn acos_ref -> AcosRef;
}
math_op1_float! {
mpfr::asin;
fn asin();
fn asin_round;
fn asin_ref -> AsinRef;
}
math_op1_float! {
mpfr::atan;
fn atan();
fn atan_round;
fn atan_ref -> AtanRef;
}
math_op2_float! {
mpfr::atan2;
fn atan2(other);
fn atan2_round;
fn atan2_ref -> Atan2Ref;
}
math_op1_float! {
mpfr::sinh;
fn sinh();
fn sinh_round;
fn sinh_ref -> SinhRef;
}
math_op1_float! {
mpfr::cosh;
fn cosh();
fn cosh_round;
fn cosh_ref -> CoshRef;
}
math_op1_float! {
mpfr::tanh;
fn tanh();
fn tanh_round;
fn tanh_ref -> TanhRef;
}
math_op1_2_float! {
mpfr::sinh_cosh;
fn sinh_cosh(cos);
fn sinh_cosh_round;
fn sinh_cosh_ref -> SinhCoshRef;
}
math_op1_float! {
mpfr::sech;
fn sech();
fn sech_round;
fn sech_ref -> SechRef;
}
math_op1_float! {
mpfr::csch;
fn csch();
fn csch_round;
fn csch_ref -> CschRef;
}
math_op1_float! {
mpfr::coth;
fn coth();
fn coth_round;
fn coth_ref -> CothRef;
}
math_op1_float! {
mpfr::acosh;
fn acosh();
fn acosh_round;
fn acosh_ref -> AcoshRef;
}
math_op1_float! {
mpfr::asinh;
fn asinh();
fn asinh_round;
fn asinh_ref -> AsinhRef;
}
math_op1_float! {
mpfr::atanh;
fn atanh();
fn atanh_round;
fn atanh_ref -> AtanhRef;
}
pub fn assign_factorial_u(&mut self, u: u32) {
self.assign_factorial_u_round(u, Round::Nearest);
}
pub fn assign_factorial_u_round(
&mut self,
u: u32,
round: Round,
) -> Ordering {
let mpfr_ret =
unsafe { mpfr::fac_ui(self.inner_mut(), u.into(), rraw(round)) };
mpfr_ret.cmp(&0)
}
math_op1_float! {
mpfr::log1p;
fn ln_1p();
fn ln_1p_round;
fn ln_1p_ref -> Ln1pRef;
}
math_op1_float! {
mpfr::expm1;
fn exp_m1();
fn exp_m1_round;
fn exp_m1_ref -> ExpM1Ref;
}
math_op1_float! {
mpfr::eint;
fn eint();
fn eint_round;
fn eint_ref -> EintRef;
}
math_op1_float! {
mpfr::li2;
fn li2();
fn li2_round;
fn li2_ref -> Li2Ref;
}
math_op1_float! {
mpfr::gamma;
fn gamma();
fn gamma_round;
fn gamma_ref -> GammaRef;
}
math_op1_float! {
mpfr::lngamma;
fn ln_gamma();
fn ln_gamma_round;
fn ln_gamma_ref -> LnGammaRef;
}
pub fn ln_abs_gamma(&mut self) -> Ordering {
self.ln_abs_gamma_round(Round::Nearest).0
}
pub fn ln_abs_gamma_round(&mut self, round: Round) -> (Ordering, Ordering) {
let mut sign: c_int = 0;
let sign_ptr = &mut sign as *mut c_int;
let mpfr_ret = unsafe {
mpfr::lgamma(self.inner_mut(), sign_ptr, self.inner(), rraw(round))
};
let sign_ord = if sign < 0 {
Ordering::Less
} else {
Ordering::Greater
};
(sign_ord, mpfr_ret.cmp(&0))
}
pub fn ln_abs_gamma_ref(&self) -> LnAbsGammaRef {
LnAbsGammaRef { ref_self: self }
}
math_op1_float! {
mpfr::digamma;
fn digamma();
fn digamma_round;
fn digamma_ref -> DigammaRef;
}
math_op1_float! {
mpfr::zeta;
fn zeta();
fn zeta_round;
fn zeta_ref -> ZetaRef;
}
pub fn assign_zeta_u(&mut self, u: u32) {
self.assign_zeta_u_round(u, Round::Nearest);
}
pub fn assign_zeta_u_round(&mut self, u: u32, round: Round) -> Ordering {
let mpfr_ret =
unsafe { mpfr::zeta_ui(self.inner_mut(), u.into(), rraw(round)) };
mpfr_ret.cmp(&0)
}
math_op1_float! {
mpfr::erf;
fn erf();
fn erf_round;
fn erf_ref -> ErfRef;
}
math_op1_float! {
mpfr::erfc;
fn erfc();
fn erfc_round;
fn erfc_ref -> ErfcRef;
}
math_op1_float! {
mpfr::j0;
fn j0();
fn j0_round;
fn j0_ref -> J0Ref;
}
math_op1_float! {
mpfr::j1;
fn j1();
fn j1_round;
fn j1_ref -> J1Ref;
}
math_op1_float! {
xmpfr::jn;
fn jn(n: i32);
fn jn_round;
fn jn_ref -> JnRef;
}
math_op1_float! {
mpfr::y0;
fn y0();
fn y0_round;
fn y0_ref -> Y0Ref;
}
math_op1_float! {
mpfr::y1;
fn y1();
fn y1_round;
fn y1_ref -> Y1Ref;
}
math_op1_float! {
xmpfr::yn;
fn yn(n: i32);
fn yn_round;
fn yn_ref -> YnRef;
}
math_op2_float! {
mpfr::agm;
fn agm(other);
fn agm_round;
fn agm_ref -> AgmRef;
}
math_op2_float! {
mpfr::hypot;
fn hypot(other);
fn hypot_round;
fn hypot_ref -> HypotRef;
}
math_op1_float! {
mpfr::ai;
fn ai();
fn ai_round;
fn ai_ref -> AiRef;
}
math_op1_float! {
mpfr::rint_ceil;
fn ceil();
fn ceil_round;
fn ceil_ref -> CeilRef;
}
math_op1_float! {
mpfr::rint_floor;
fn floor();
fn floor_round;
fn floor_ref -> FloorRef;
}
math_op1_float! {
mpfr::rint_round;
fn round();
fn round_round;
fn round_ref -> RoundRef;
}
math_op1_float! {
mpfr::rint_trunc;
fn trunc();
fn trunc_round;
fn trunc_ref -> TruncRef;
}
math_op1_float! {
mpfr::frac;
fn fract();
fn fract_round;
fn fract_ref -> FractRef;
}
math_op1_2_float! {
mpfr::modf;
fn trunc_fract(fract);
fn trunc_fract_round;
fn trunc_fract_ref -> TruncFractRef;
}
pub fn assign_random_bits(
&mut self,
rng: &mut RandState,
) -> Result<(), ()> {
let err = unsafe { mpfr::urandomb(self.inner_mut(), rng.inner_mut()) };
if err != 0 { Err(()) } else { Ok(()) }
}
pub fn assign_random_cont(&mut self, rng: &mut RandState) {
self.assign_random_cont_round(rng, Round::Nearest);
}
pub fn assign_random_cont_round(
&mut self,
rng: &mut RandState,
round: Round,
) -> Ordering {
let ret = unsafe {
mpfr::urandom(self.inner_mut(), rng.inner_mut(), rraw(round))
};
ordering1(ret)
}
pub fn assign_random_gaussian_round(
&mut self,
other: Option<&mut Float>,
rng: &mut RandState,
round: Round,
) -> (Ordering, Ordering) {
let second_ptr = match other {
Some(r) => unsafe { r.inner_mut() },
None => ptr::null_mut(),
};
let ret = unsafe {
mpfr::grandom(
self.inner_mut(),
second_ptr,
rng.inner_mut(),
rraw(round),
)
};
ordering2(ret)
}
}
impl<T> From<(T, u32)> for Float
where
Float: FromRound<T, u32, Round = Round>,
{
fn from((t, prec): (T, u32)) -> Float {
Float::from_round(t, prec, Round::Nearest).0
}
}
impl<T> FromRound<T, u32> for Float
where
Float: AssignRound<
T,
Round = Round,
Ordering = Ordering,
>,
{
type Round = Round;
type Ordering = Ordering;
fn from_round(t: T, prec: u32, round: Round) -> (Float, Ordering) {
let mut ret = Float::new(prec);
let ord = ret.assign_round(t, round);
(ret, ord)
}
}
impl Display for Float {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, false, "", false)
}
}
impl Debug for Float {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, false, "", true)
}
}
impl LowerExp for Float {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, false, "", false)
}
}
impl UpperExp for Float {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, true, "", false)
}
}
impl Binary for Float {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 2, false, "0b", false)
}
}
impl Octal for Float {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 8, false, "0o", false)
}
}
impl LowerHex for Float {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 16, false, "0x", false)
}
}
impl UpperHex for Float {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 16, true, "0x", false)
}
}
impl<T> Assign<T> for Float
where
Float: AssignRound<T, Round = Round, Ordering = Ordering>,
{
fn assign(&mut self, other: T) {
self.assign_round(other, Round::Nearest);
}
}
impl AssignRound<Constant> for Float {
type Round = Round;
type Ordering = Ordering;
fn assign_round(&mut self, other: Constant, round: Round) -> Ordering {
let mpfr_ret = unsafe {
match other {
Constant::Log2 => {
mpfr::const_log2(self.inner_mut(), rraw(round))
}
Constant::Pi => mpfr::const_pi(self.inner_mut(), rraw(round)),
Constant::Euler => {
mpfr::const_euler(self.inner_mut(), rraw(round))
}
Constant::Catalan => {
mpfr::const_catalan(self.inner_mut(), rraw(round))
}
}
};
mpfr_ret.cmp(&0)
}
}
impl AssignRound<Special> for Float {
type Round = Round;
type Ordering = Ordering;
fn assign_round(&mut self, other: Special, _round: Round) -> Ordering {
unsafe {
match other {
Special::Zero => mpfr::set_zero(self.inner_mut(), 0),
Special::MinusZero => mpfr::set_zero(self.inner_mut(), -1),
Special::Infinity => mpfr::set_inf(self.inner_mut(), 0),
Special::MinusInfinity => mpfr::set_inf(self.inner_mut(), -1),
Special::Nan => mpfr::set_nan(self.inner_mut()),
};
}
Ordering::Equal
}
}
macro_rules! assign {
{ $T:ty, $func:path } => {
impl<'a> AssignRound<&'a $T> for Float {
type Round = Round;
type Ordering = Ordering;
fn assign_round(
&mut self,
other: &'a $T,
round: Round
) -> Ordering {
let mpfr_ret = unsafe {
$func(self.inner_mut(), other.inner(), rraw(round))
};
mpfr_ret.cmp(&0)
}
}
impl AssignRound<$T> for Float {
type Round = Round;
type Ordering = Ordering;
fn assign_round(&mut self, other: $T, round: Round) -> Ordering {
self.assign_round(&other, round)
}
}
};
}
assign! { Float, mpfr::set }
assign! { Integer, mpfr::set_z }
#[cfg(feature = "rational")]
assign! { Rational, mpfr::set_q }
ref_math_op1_float! { mpfr::sqr; struct SquareRef {} }
ref_math_op1_float! { mpfr::sqrt; struct SqrtRef {} }
ref_math_op1_float! { mpfr::rec_sqrt; struct RecipSqrtRef {} }
ref_math_op1_float! { mpfr::cbrt; struct CbrtRef {} }
ref_math_op1_float! { mpfr::root; struct RootRef { k: u32 } }
ref_math_op1_float! { mpfr::abs; struct AbsRef {} }
ref_math_op1_float! { xmpfr::recip; struct RecipRef {} }
ref_math_op2_float! { mpfr::dim; struct AbsDiffRef { other } }
ref_math_op1_float! { mpfr::log; struct LnRef {} }
ref_math_op1_float! { mpfr::log2; struct Log2Ref {} }
ref_math_op1_float! { mpfr::log10; struct Log10Ref {} }
ref_math_op1_float! { mpfr::exp; struct ExpRef {} }
ref_math_op1_float! { mpfr::exp2; struct Exp2Ref {} }
ref_math_op1_float! { mpfr::exp10; struct Exp10Ref {} }
ref_math_op1_float! { mpfr::sin; struct SinRef {} }
ref_math_op1_float! { mpfr::cos; struct CosRef {} }
ref_math_op1_float! { mpfr::tan; struct TanRef {} }
ref_math_op1_2_float! { mpfr::sin_cos; struct SinCosRef {} }
ref_math_op1_float! { mpfr::sec; struct SecRef {} }
ref_math_op1_float! { mpfr::csc; struct CscRef {} }
ref_math_op1_float! { mpfr::cot; struct CotRef {} }
ref_math_op1_float! { mpfr::acos; struct AcosRef {} }
ref_math_op1_float! { mpfr::asin; struct AsinRef {} }
ref_math_op1_float! { mpfr::atan; struct AtanRef {} }
ref_math_op2_float! { mpfr::atan2; struct Atan2Ref { other } }
ref_math_op1_float! { mpfr::cosh; struct CoshRef {} }
ref_math_op1_float! { mpfr::sinh; struct SinhRef {} }
ref_math_op1_float! { mpfr::tanh; struct TanhRef {} }
ref_math_op1_2_float! { mpfr::sinh_cosh; struct SinhCoshRef {} }
ref_math_op1_float! { mpfr::sech; struct SechRef {} }
ref_math_op1_float! { mpfr::csch; struct CschRef {} }
ref_math_op1_float! { mpfr::coth; struct CothRef {} }
ref_math_op1_float! { mpfr::acosh; struct AcoshRef {} }
ref_math_op1_float! { mpfr::asinh; struct AsinhRef {} }
ref_math_op1_float! { mpfr::atanh; struct AtanhRef {} }
ref_math_op1_float! { mpfr::log1p; struct Ln1pRef {} }
ref_math_op1_float! { mpfr::expm1; struct ExpM1Ref {} }
ref_math_op1_float! { mpfr::eint; struct EintRef {} }
ref_math_op1_float! { mpfr::li2; struct Li2Ref {} }
ref_math_op1_float! { mpfr::gamma; struct GammaRef {} }
ref_math_op1_float! { mpfr::lngamma; struct LnGammaRef {} }
pub struct LnAbsGammaRef<'a> {
ref_self: &'a Float,
}
impl<'a> Assign<LnAbsGammaRef<'a>> for (&'a mut Float, &'a mut Ordering) {
fn assign(&mut self, src: LnAbsGammaRef<'a>) {
self.assign_round(src, Round::Nearest);
}
}
impl<'a> AssignRound<LnAbsGammaRef<'a>> for (&'a mut Float, &'a mut Ordering) {
type Round = Round;
type Ordering = Ordering;
fn assign_round(
&mut self,
src: LnAbsGammaRef<'a>,
round: Round,
) -> Ordering {
let mut sign: c_int = 0;
let sign_ptr = &mut sign as *mut c_int;
let mpfr_ret = unsafe {
mpfr::lgamma(
self.0.inner_mut(),
sign_ptr,
src.ref_self.inner(),
rraw(round),
)
};
*self.1 = if sign < 0 {
Ordering::Less
} else {
Ordering::Greater
};
mpfr_ret.cmp(&0)
}
}
ref_math_op1_float! { mpfr::digamma; struct DigammaRef {} }
ref_math_op1_float! { mpfr::zeta; struct ZetaRef {} }
ref_math_op1_float! { mpfr::erf; struct ErfRef {} }
ref_math_op1_float! { mpfr::erfc; struct ErfcRef {} }
ref_math_op1_float! { mpfr::j0; struct J0Ref {} }
ref_math_op1_float! { mpfr::j1; struct J1Ref {} }
ref_math_op1_float! { xmpfr::jn; struct JnRef { n: i32 } }
ref_math_op1_float! { mpfr::y0; struct Y0Ref {} }
ref_math_op1_float! { mpfr::y1; struct Y1Ref {} }
ref_math_op1_float! { xmpfr::yn; struct YnRef { n: i32 } }
ref_math_op2_float! { mpfr::agm; struct AgmRef { other } }
ref_math_op2_float! { mpfr::hypot; struct HypotRef { other } }
ref_math_op1_float! { mpfr::ai; struct AiRef {} }
ref_math_op1_float! { mpfr::rint_ceil; struct CeilRef {} }
ref_math_op1_float! { mpfr::rint_floor; struct FloorRef {} }
ref_math_op1_float! { mpfr::rint_round; struct RoundRef {} }
ref_math_op1_float! { mpfr::rint_trunc; struct TruncRef {} }
ref_math_op1_float! { mpfr::frac; struct FractRef {} }
ref_math_op1_2_float! { mpfr::modf; struct TruncFractRef {} }
impl Neg for Float {
type Output = Float;
fn neg(mut self) -> Float {
self.neg_assign();
self
}
}
impl NegAssign for Float {
fn neg_assign(&mut self) {
unsafe {
mpfr::neg(self.inner_mut(), self.inner(), rraw(Round::Nearest));
}
}
}
impl<'a> Neg for &'a Float {
type Output = NegRef<'a>;
fn neg(self) -> NegRef<'a> {
NegRef { val: self }
}
}
pub struct NegRef<'a> {
val: &'a Float,
}
impl<'a> AssignRound<NegRef<'a>> for Float {
type Round = Round;
type Ordering = Ordering;
fn assign_round(&mut self, src: NegRef<'a>, round: Round) -> Ordering {
let mpfr_ret = unsafe {
mpfr::neg(self.inner_mut(), src.val.inner(), rraw(round))
};
mpfr_ret.cmp(&0)
}
}
macro_rules! arith_commut_self_float {
{
$func:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$Ref:ident $RefOwn:ident
} => {
arith_commut_self_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$Ref $RefOwn
}
}
}
macro_rules! arith_noncommut_self_float {
{
$func:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$ImpFromAssign:ident $method_from_assign:ident;
$Ref:ident $RefOwn:ident
} => {
arith_noncommut_self_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$ImpFromAssign $method_from_assign;
$Ref $RefOwn
}
}
}
macro_rules! arith_forward_float {
{
$func:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$T:ty;
$Ref:ident $RefOwn:ident
} => {
arith_forward_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$T;
$Ref $RefOwn
}
}
}
macro_rules! arith_commut_float {
{
$func:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$T:ty;
$Ref:ident $RefOwn:ident
} => {
arith_commut_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$T;
$Ref $RefOwn
}
}
}
macro_rules! arith_noncommut_float {
{
$func:path, $func_from:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$ImpFromAssign:ident $method_from_assign:ident;
$T:ty;
$Ref:ident $RefFrom:ident $RefOwn:ident $RefFromOwn:ident
} => {
arith_noncommut_round! {
Float, Round => Ordering;
$func, $func_from, rraw => ordering1;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$ImpFromAssign $method_from_assign;
$T;
$Ref $RefFrom $RefOwn $RefFromOwn
}
}
}
arith_commut_self_float! {
mpfr::add;
Add add;
AddRound add_round;
AddAssign add_assign;
AddRef AddRefOwn
}
arith_noncommut_self_float! {
mpfr::sub;
Sub sub;
SubRound sub_round;
SubAssign sub_assign;
SubFromAssign sub_from_assign;
SubRef SubRefOwn
}
arith_commut_self_float! {
mpfr::mul;
Mul mul;
MulRound mul_round;
MulAssign mul_assign;
MulRef MulRefOwn
}
arith_noncommut_self_float! {
mpfr::div;
Div div;
DivRound div_round;
DivAssign div_assign;
DivFromAssign div_from_assign;
DivRef DivRefOwn
}
arith_noncommut_self_float! {
mpfr::pow;
Pow pow;
PowRound pow_round;
PowAssign pow_assign;
PowFromAssign pow_from_assign;
PowRef PowRefOwn
}
arith_commut_float! {
mpfr::add_z;
Add add;
AddRound add_round;
AddAssign add_assign;
Integer;
AddRefInteger AddRefIntegerOwn
}
arith_noncommut_float! {
mpfr::sub_z, mpfr::z_sub;
Sub sub;
SubRound sub_round;
SubAssign sub_assign;
SubFromAssign sub_from_assign;
Integer;
SubRefInteger SubFromRefInteger SubRefIntegerOwn SubFromRefIntegerOwn
}
arith_commut_float! {
mpfr::mul_z;
Mul mul;
MulRound mul_round;
MulAssign mul_assign;
Integer;
MulRefInteger MulRefIntegerOwn
}
arith_noncommut_float! {
mpfr::div_z, xmpfr::z_div;
Div div;
DivRound div_round;
DivAssign div_assign;
DivFromAssign div_from_assign;
Integer;
DivRefInteger DivFromRefInteger DivRefIntegerOwn DivFromRefIntegerOwn
}
arith_forward_float! {
mpfr::pow_z;
Pow pow;
PowRound pow_round;
PowAssign pow_assign;
Integer;
PowRefInteger PowRefIntegerOwn
}
#[cfg(feature = "rational")]
arith_commut_float! {
mpfr::add_q;
Add add;
AddRound add_round;
AddAssign add_assign;
Rational;
AddRefRational AddRefRationalOwn
}
#[cfg(feature = "rational")]
arith_noncommut_float! {
mpfr::sub_q, xmpfr::q_sub;
Sub sub;
SubRound sub_round;
SubAssign sub_assign;
SubFromAssign sub_from_assign;
Rational;
SubRefRational SubFromRefRational SubRefRationalOwn SubFromRefRationalOwn
}
#[cfg(feature = "rational")]
arith_commut_float! {
mpfr::mul_q;
Mul mul;
MulRound mul_round;
MulAssign mul_assign;
Rational;
MulRefRational MulRefRationalOwn
}
#[cfg(feature = "rational")]
arith_noncommut_float! {
mpfr::div_q, xmpfr::q_div;
Div div;
DivRound div_round;
DivAssign div_assign;
DivFromAssign div_from_assign;
Rational;
DivRefRational DivFromRefRational DivRefRationalOwn DivFromRefRationalOwn
}
macro_rules! arith_prim_float {
{
$func:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$T:ty;
$Ref:ident
} => {
arith_prim_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$T;
$Ref
}
}
}
macro_rules! arith_prim_shift_float {
{
$func:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$T:ty;
$Ref:ident
} => {
arith_prim_shift_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$Imp $method;
$ImpAssign $method_assign;
$T;
$Ref
}
}
}
macro_rules! arith_prim_commut_float {
{
$func:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$T:ty;
$Ref:ident
} => {
arith_prim_commut_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$T;
$Ref
}
}
}
macro_rules! arith_prim_noncommut_float {
{
$func:path, $func_from:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$ImpFromAssign:ident $method_from_assign:ident;
$T:ty;
$Ref:ident $RefFrom:ident
} => {
arith_prim_noncommut_round! {
Float, Round => Ordering;
$func, $func_from, rraw => ordering1;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$ImpFromAssign $method_from_assign;
$T;
$Ref $RefFrom
}
}
}
macro_rules! conv_ops {
{
($T:ty, $set:path),
($AddRef:ident $add:path,
$SubRef:ident $sub:path,
$SubFromRef:ident $sub_from:path),
($MulRef:ident $mul:path,
$DivRef:ident $div: path,
$DivFromRef:ident $div_from:path)
} => {
impl AssignRound<$T> for Float {
type Round = Round;
type Ordering = Ordering;
fn assign_round(&mut self, val: $T, round: Round) -> Ordering {
let mpfr_ret = unsafe {
$set(self.inner_mut(), val.into(), rraw(round))
};
mpfr_ret.cmp(&0)
}
}
arith_prim_commut_float! {
$add;
Add add;
AddRound add_round;
AddAssign add_assign;
$T;
$AddRef
}
arith_prim_noncommut_float! {
$sub, $sub_from;
Sub sub;
SubRound sub_round;
SubAssign sub_assign;
SubFromAssign sub_from_assign;
$T;
$SubRef $SubFromRef
}
arith_prim_commut_float! {
$mul;
Mul mul;
MulRound mul_round;
MulAssign mul_assign;
$T;
$MulRef
}
arith_prim_noncommut_float! {
$div, $div_from;
Div div;
DivRound div_round;
DivAssign div_assign;
DivFromAssign div_from_assign;
$T;
$DivRef $DivFromRef
}
}
}
conv_ops! {
(i32, mpfr::set_si),
(AddRefI32 mpfr::add_si,
SubRefI32 mpfr::sub_si,
SubFromRefI32 mpfr::si_sub),
(MulRefI32 mpfr::mul_si,
DivRefI32 mpfr::div_si,
DivFromRefI32 mpfr::si_div)
}
impl AssignRound<i64> for Float {
type Round = Round;
type Ordering = Ordering;
fn assign_round(&mut self, other: i64, round: Round) -> Ordering {
let mpfr_ret =
unsafe { xmpfr::set_i64(self.inner_mut(), other, rraw(round)) };
mpfr_ret.cmp(&0)
}
}
conv_ops! {
(u32, mpfr::set_ui),
(AddRefU32 mpfr::add_ui,
SubRefU32 mpfr::sub_ui,
SubFromRefU32 mpfr::ui_sub),
(MulRefU32 mpfr::mul_ui,
DivRefU32 mpfr::div_ui,
DivFromRefU32 mpfr::ui_div)
}
impl AssignRound<u64> for Float {
type Round = Round;
type Ordering = Ordering;
fn assign_round(&mut self, other: u64, round: Round) -> Ordering {
let mpfr_ret =
unsafe { xmpfr::set_u64(self.inner_mut(), other, rraw(round)) };
mpfr_ret.cmp(&0)
}
}
conv_ops! {
(f32, xmpfr::set_f32),
(AddRefF32 xmpfr::add_f32,
SubRefF32 xmpfr::sub_f32,
SubFromRefF32 xmpfr::f32_sub),
(MulRefF32 xmpfr::mul_f32,
DivRefF32 xmpfr::div_f32,
DivFromRefF32 xmpfr::f32_div)
}
conv_ops! {
(f64, mpfr::set_d),
(AddRefF64 mpfr::add_d,
SubRefF64 mpfr::sub_d,
SubFromRefF64 mpfr::d_sub),
(MulRefF64 mpfr::mul_d,
DivRefF64 mpfr::div_d,
DivFromRefF64 mpfr::d_div)
}
arith_prim_shift_float! {
mpfr::mul_2ui;
Shl shl;
ShlAssign shl_assign;
u32;
ShlRefU32
}
arith_prim_shift_float! {
mpfr::div_2ui;
Shr shr;
ShrAssign shr_assign;
u32;
ShrRefU32
}
arith_prim_noncommut_float!{
mpfr::pow_ui, mpfr::ui_pow;
Pow pow;
PowRound pow_round;
PowAssign pow_assign;
PowFromAssign pow_from_assign;
u32;
PowRefU32 PowFromRefU32
}
arith_prim_shift_float! {
mpfr::mul_2si;
Shl shl;
ShlAssign shl_assign;
i32;
ShlRefI32
}
arith_prim_shift_float! {
mpfr::div_2si;
Shr shr;
ShrAssign shr_assign;
i32;
ShrRefI32
}
arith_prim_float!{
mpfr::pow_si;
Pow pow;
PowRound pow_round;
PowAssign pow_assign;
i32;
PowRefI32
}
arith_prim_float!{
xmpfr::pow_f64;
Pow pow;
PowRound pow_round;
PowAssign pow_assign;
f64;
PowRefF64
}
arith_prim_float!{
xmpfr::pow_f32;
Pow pow;
PowRound pow_round;
PowAssign pow_assign;
f32;
PowRefF32
}
impl<'a> Add<MulRef<'a>> for Float {
type Output = Float;
fn add(self, rhs: MulRef) -> Float {
self.add_round(rhs, Round::Nearest).0
}
}
impl<'a> AddRound<MulRef<'a>> for Float {
type Round = Round;
type Ordering = Ordering;
type Output = Float;
fn add_round(mut self, rhs: MulRef, round: Round) -> (Float, Ordering) {
let mpfr_ret = unsafe {
mpfr::fma(
self.inner_mut(),
rhs.lhs.inner(),
rhs.rhs.inner(),
self.inner(),
rraw(round),
)
};
(self, mpfr_ret.cmp(&0))
}
}
impl<'a> AddAssign<MulRef<'a>> for Float {
fn add_assign(&mut self, rhs: MulRef) {
unsafe {
mpfr::fma(
self.inner_mut(),
rhs.lhs.inner(),
rhs.rhs.inner(),
self.inner(),
rraw(Round::Nearest),
);
}
}
}
impl PartialEq for Float {
fn eq(&self, other: &Float) -> bool {
unsafe { mpfr::equal_p(self.inner(), other.inner()) != 0 }
}
}
impl PartialOrd for Float {
fn partial_cmp(&self, other: &Float) -> Option<Ordering> {
unsafe {
match mpfr::unordered_p(self.inner(), other.inner()) {
0 => Some(mpfr::cmp(self.inner(), other.inner()).cmp(&0)),
_ => None,
}
}
}
fn lt(&self, other: &Float) -> bool {
unsafe { mpfr::less_p(self.inner(), other.inner()) != 0 }
}
fn le(&self, other: &Float) -> bool {
unsafe { mpfr::lessequal_p(self.inner(), other.inner()) != 0 }
}
fn gt(&self, other: &Float) -> bool {
unsafe { mpfr::greater_p(self.inner(), other.inner()) != 0 }
}
fn ge(&self, other: &Float) -> bool {
unsafe { mpfr::greaterequal_p(self.inner(), other.inner()) != 0 }
}
}
macro_rules! cmp {
{ $T:ty, $eval:expr } => {
impl PartialEq<$T> for Float {
fn eq(&self, other: &$T) -> bool {
self.partial_cmp(other) == Some(Ordering::Equal)
}
}
impl PartialOrd<$T> for Float {
fn partial_cmp(&self, other: &$T) -> Option<Ordering> {
if self.is_nan() {
return None;
}
Some($eval(self.inner(), other).cmp(&0))
}
}
impl PartialEq<Float> for $T {
fn eq(&self, other: &Float) -> bool {
other.eq(self)
}
}
impl PartialOrd<Float> for $T {
fn partial_cmp(&self, other: &Float) -> Option<Ordering> {
other.partial_cmp(self).map(Ordering::reverse)
}
}
}
}
cmp! { Integer, |f, t: &Integer| unsafe { mpfr::cmp_z(f, t.inner()) } }
#[cfg(feature = "rational")]
cmp! { Rational, |f, t: &Rational| unsafe { mpfr::cmp_q(f, t.inner()) } }
cmp! { u32, |f, t: &u32| unsafe { mpfr::cmp_ui(f, (*t).into()) } }
cmp! { i32, |f, t: &i32| unsafe { mpfr::cmp_si(f, (*t).into()) } }
cmp! { f64, |f, t: &f64| unsafe { mpfr::cmp_d(f, *t) } }
cmp! { f32, |f, t: &f32| unsafe { mpfr::cmp_d(f, *t as f64) } }
fn make_string(
f: &Float,
radix: i32,
precision: Option<usize>,
round: Round,
to_upper: bool,
) -> String {
use std::fmt::Write;
assert!(radix >= 2 && radix <= 36, "radix out of range");
if f.is_zero() {
return "0.0".to_string();
}
if f.is_infinite() {
return match (radix > 10, f.get_sign()) {
(false, false) => "inf".to_string(),
(false, true) => "-inf".to_string(),
(true, false) => "@inf@".to_string(),
(true, true) => "-@inf@".to_string(),
};
}
if f.is_nan() {
let s = if radix <= 10 { "NaN" } else { "@NaN@" };
return s.to_string();
}
let mut buf = String::new();
let mut exp: mpfr::exp_t;
let digits = precision.map(|x| if x == 1 { 2 } else { x }).unwrap_or(0);
let s;
let cstr;
unsafe {
exp = mem::uninitialized();
s = mpfr::get_str(
ptr::null_mut(),
&mut exp,
radix.into(),
digits,
f.inner(),
rraw(round),
);
assert!(!s.is_null());
cstr = CStr::from_ptr(s);
}
let mut chars = cstr.to_str().unwrap().chars();
let c = chars.next().unwrap();
buf.push(char_to_upper_if(c, to_upper));
if c == '-' {
let c = chars.next().unwrap();
buf.push(char_to_upper_if(c, to_upper));
}
buf.push('.');
for c in chars {
buf.push(char_to_upper_if(c, to_upper));
}
unsafe {
mpfr::free_str(s);
}
buf.push(if radix <= 10 {
char_to_upper_if('e', to_upper)
} else {
'@'
});
let exp = exp.checked_sub(1).expect("overflow");
let _ = write!(buf, "{}", exp);
buf
}
fn fmt_radix(
flt: &Float,
f: &mut Formatter,
radix: i32,
to_upper: bool,
prefix: &str,
show_neg_zero: bool,
) -> fmt::Result {
let s = make_string(flt, radix, f.precision(), Round::Nearest, to_upper);
if !flt.is_finite() {
return f.pad(&s);
}
let (neg, buf) = if s.starts_with('-') {
(true, &s[1..])
} else {
(show_neg_zero && flt.is_zero() && flt.get_sign(), &s[..])
};
f.pad_integral(!neg, prefix, buf)
}
#[derive(Clone, Debug)]
pub struct ValidFloat<'a> {
poss: ValidPoss<'a>,
radix: i32,
exp_plus: Option<usize>,
}
#[derive(Clone, Debug)]
enum ValidPoss<'a> {
Bytes(&'a [u8]),
Special(Special),
}
impl<'a> AssignRound<ValidFloat<'a>> for Float {
type Round = Round;
type Ordering = Ordering;
fn assign_round(&mut self, rhs: ValidFloat, round: Round) -> Ordering {
let bytes = match rhs.poss {
ValidPoss::Special(s) => {
self.assign(s);
return Ordering::Equal;
}
ValidPoss::Bytes(b) => b,
};
let mut v = Vec::<u8>::with_capacity(bytes.len() + 1);
if let Some(exp_plus) = rhs.exp_plus {
v.extend_from_slice(&bytes[0..exp_plus]);
v.extend_from_slice(&bytes[exp_plus + 1..]);
} else {
v.extend_from_slice(bytes);
}
v.push(0);
let mut c_str_end: *const c_char = ptr::null();
let mpfr_ret = unsafe {
let c_str = CStr::from_bytes_with_nul_unchecked(&v);
mpfr::strtofr(
self.inner_mut(),
c_str.as_ptr(),
&mut c_str_end as *mut _ as *mut *mut c_char,
rhs.radix as c_int,
rraw(round),
)
};
let nul = v.last().unwrap() as *const _ as *const c_char;
assert_eq!(c_str_end, nul);
mpfr_ret.cmp(&0)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ParseFloatError {
kind: ParseErrorKind,
}
#[derive(Clone, Debug, Eq, PartialEq)]
enum ParseErrorKind {
InvalidDigit,
NoDigits,
SignifNoDigits,
ExpNoDigits,
PointInExp,
TooManyPoints,
TooManyExp,
}
impl Error for ParseFloatError {
fn description(&self) -> &str {
use self::ParseErrorKind::*;
match self.kind {
InvalidDigit => "invalid digit found in string",
NoDigits => "string has no digits",
SignifNoDigits => "string has no digits for significand",
ExpNoDigits => "string has no digits for exponent",
PointInExp => "string has point in exponent",
TooManyPoints => "more than one point found in string",
TooManyExp => "more than one exponent found in string",
}
}
}
impl Display for ParseFloatError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Debug::fmt(self, f)
}
}
unsafe impl Send for Float {}
unsafe impl Sync for Float {}
fn lcase_in(a: &[u8], bs: &[&[u8]]) -> bool {
'next_b: for b in bs {
if a.len() != b.len() {
continue 'next_b;
}
for (ac, &bc) in a.iter().map(lcase_ascii).zip(b.iter()) {
if ac != bc {
continue 'next_b;
}
}
return true;
}
false
}
fn lcase_ascii(byte: &u8) -> u8 {
if b'A' <= *byte && *byte <= b'Z' {
*byte - b'A' + b'a'
} else {
*byte
}
}
fn char_to_upper_if(c: char, to_upper: bool) -> char {
if to_upper { c.to_ascii_uppercase() } else { c }
}
impl Inner for Float {
type Output = mpfr_t;
fn inner(&self) -> &mpfr_t {
&self.inner
}
}
impl InnerMut for Float {
unsafe fn inner_mut(&mut self) -> &mut mpfr_t {
&mut self.inner
}
}