use {Assign, AssignRound};
#[cfg(feature = "integer")]
use Integer;
#[cfg(feature = "rational")]
use Rational;
use ext::mpfr as xmpfr;
use float::{OrdFloat, SmallFloat};
use inner::{Inner, InnerMut};
use ops::{AddAssignRound, AddFrom, AddFromRound, DivAssignRound, DivFrom,
DivFromRound, MulAssignRound, MulFrom, MulFromRound, NegAssign, Pow,
PowAssign, PowAssignRound, PowFrom, PowFromRound, SubAssignRound,
SubFrom, SubFromRound};
#[cfg(feature = "rand")]
use rand::RandState;
use gmp_mpfr_sys::mpfr::{self, mpfr_t};
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::marker::PhantomData;
use std::mem;
use std::ops::{Add, AddAssign, Deref, 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;
#[inline]
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
}
}
#[inline]
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
}
}
#[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
}
}
#[inline]
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, 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,
}
#[inline]
fn ordering1(ord: c_int) -> Ordering {
ord.cmp(&0)
}
#[inline]
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 Default for Float {
#[inline]
fn default() -> Float {
Float::new(53)
}
}
impl Clone for Float {
#[inline]
fn clone(&self) -> Float {
let mut ret = Float::new(self.prec());
ret.assign(self);
ret
}
#[inline]
fn clone_from(&mut self, source: &Float) {
self.set_prec(source.prec());
self.assign(source);
}
}
impl Drop for Float {
#[inline]
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_mut:meta])*
fn $method_mut:ident;
$(#[$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_mut])*
fn $method_mut;
$(#[$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_mut:meta])*
fn $method_mut:ident;
$(#[$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_mut])*
fn $method_mut;
$(#[$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_mut:meta])*
fn $method_mut:ident;
$(#[$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_mut])*
fn $method_mut;
$(#[$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 {
#[inline]
pub fn new(prec: u32) -> Float {
let mut ret = Float::new_nan(prec);
ret.assign(Special::Zero);
ret
}
#[inline]
pub fn with_val<T>(prec: u32, val: T) -> Float
where
Float: Assign<T>,
{
let mut ret = Float::new_nan(prec);
ret.assign(val);
ret
}
#[inline]
pub fn with_val_round<T>(
prec: u32,
val: T,
round: Round,
) -> (Float, Ordering)
where
Float: AssignRound<T, Round = Round, Ordering = Ordering>,
{
let mut ret = Float::new_nan(prec);
let ord = ret.assign_round(val, round);
(ret, ord)
}
#[inline]
fn new_nan(prec: u32) -> Float {
assert!(
prec >= prec_min() && prec <= prec_max(),
"precision out of range"
);
unsafe {
let mut ret: Float = mem::uninitialized();
mpfr::init2(ret.inner_mut(), prec as mpfr::prec_t);
ret
}
}
#[inline]
pub fn prec(&self) -> u32 {
unsafe { mpfr::get_prec(self.inner()) as u32 }
}
#[inline]
pub fn set_prec(&mut self, prec: u32) {
self.set_prec_round(prec, Round::Nearest);
}
#[inline]
pub fn set_prec_round(&mut self, prec: u32, round: Round) -> Ordering {
assert!(
prec >= prec_min() && prec <= prec_max(),
"precision out of range"
);
let ret = unsafe {
mpfr::prec_round(
self.inner_mut(),
prec as mpfr::prec_t,
rraw(round),
)
};
ordering1(ret)
}
#[inline]
pub fn from_str(src: &str, prec: u32) -> Result<Float, ParseFloatError> {
let mut f = Float::new_nan(prec);
f.assign_str(src)?;
Ok(f)
}
#[inline]
pub fn from_str_round(
src: &str,
prec: u32,
round: Round,
) -> Result<(Float, Ordering), ParseFloatError> {
let mut f = Float::new_nan(prec);
let ord = f.assign_str_round(src, round)?;
Ok((f, ord))
}
#[inline]
pub fn from_str_radix(
src: &str,
radix: i32,
prec: u32,
) -> Result<Float, ParseFloatError> {
let mut f = Float::new_nan(prec);
f.assign_str_radix(src, radix)?;
Ok(f)
}
#[inline]
pub fn from_str_radix_round(
src: &str,
radix: i32,
prec: u32,
round: Round,
) -> Result<(Float, Ordering), ParseFloatError> {
let mut f = Float::new_nan(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,
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::NegInfinity);
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)
}
#[cfg(feature = "integer")]
#[inline]
pub fn to_integer(&self) -> Option<Integer> {
self.to_integer_round(Round::Nearest).map(|x| x.0)
}
#[cfg(feature = "integer")]
#[inline]
pub fn to_integer_round(
&self,
round: Round,
) -> Option<(Integer, Ordering)> {
if !self.is_finite() {
return None;
}
let mut i = Integer::new();
let ret =
unsafe { mpfr::get_z(i.inner_mut(), self.inner(), rraw(round)) };
Some((i, ordering1(ret)))
}
#[cfg(feature = "integer")]
#[inline]
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")]
#[inline]
pub fn to_rational(&self) -> Option<Rational> {
self.to_integer_exp()
.map(|(num, exp)| Rational::from(num) << exp)
}
#[inline]
pub fn to_i32_saturating(&self) -> Option<i32> {
self.to_i32_saturating_round(Round::Nearest)
}
#[inline]
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)
}
}
#[inline]
pub fn to_u32_saturating(&self) -> Option<u32> {
self.to_u32_saturating_round(Round::Nearest)
}
#[inline]
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)
}
}
#[inline]
pub fn to_f32(&self) -> f32 {
self.to_f32_round(Round::Nearest)
}
#[inline]
pub fn to_f32_round(&self, round: Round) -> f32 {
self.to_f64_round(round) as f32
}
#[inline]
pub fn to_f64(&self) -> f64 {
self.to_f64_round(Round::Nearest)
}
#[inline]
pub fn to_f64_round(&self, round: Round) -> f64 {
unsafe { mpfr::get_d(self.inner(), rraw(round)) }
}
#[inline]
pub fn to_f32_exp(&self) -> (f32, i32) {
self.to_f32_exp_round(Round::Nearest)
}
#[inline]
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)
}
#[inline]
pub fn to_f64_exp(&self) -> (f64, i32) {
self.to_f64_exp_round(Round::Nearest)
}
#[inline]
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)
}
#[inline]
pub fn to_string_radix(
&self,
radix: i32,
num_digits: Option<usize>,
) -> String {
self.to_string_radix_round(radix, num_digits, Round::Nearest)
}
#[inline]
pub fn to_string_radix_round(
&self,
radix: i32,
num_digits: Option<usize>,
round: Round,
) -> String {
make_string(self, radix, num_digits, round, false)
}
#[inline]
pub fn assign_str(&mut self, src: &str) -> Result<(), ParseFloatError> {
self.assign_str_radix(src, 10)
}
#[inline]
pub fn assign_str_round(
&mut self,
src: &str,
round: Round,
) -> Result<Ordering, ParseFloatError> {
self.assign_str_radix_round(src, 10, round)
}
#[inline]
pub fn assign_str_radix(
&mut self,
src: &str,
radix: i32,
) -> Result<(), ParseFloatError> {
self.assign_str_radix_round(src, radix, Round::Nearest)?;
Ok(())
}
#[inline]
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 as_neg(&self) -> BorrowFloat {
let mut ret = BorrowFloat {
inner: self.inner,
phantom: PhantomData,
};
unsafe {
if self.is_nan() {
mpfr::set_nanflag();
} else {
ret.inner.sign.neg_assign();
}
}
ret
}
pub fn as_abs(&self) -> BorrowFloat {
let mut ret = BorrowFloat {
inner: self.inner,
phantom: PhantomData,
};
unsafe {
if self.is_nan() {
mpfr::set_nanflag();
} else {
ret.inner.sign = 1;
}
}
ret
}
pub fn as_ord(&self) -> &OrdFloat {
unsafe { &*(self as *const _ as *const _) }
}
#[inline]
pub fn is_integer(&self) -> bool {
unsafe { mpfr::integer_p(self.inner()) != 0 }
}
#[inline]
pub fn is_nan(&self) -> bool {
unsafe { mpfr::nan_p(self.inner()) != 0 }
}
#[inline]
pub fn is_infinite(&self) -> bool {
unsafe { mpfr::inf_p(self.inner()) != 0 }
}
#[inline]
pub fn is_finite(&self) -> bool {
unsafe { mpfr::number_p(self.inner()) != 0 }
}
#[inline]
pub fn is_zero(&self) -> bool {
unsafe { mpfr::zero_p(self.inner()) != 0 }
}
#[inline]
pub fn is_normal(&self) -> bool {
unsafe { mpfr::regular_p(self.inner()) != 0 }
}
#[inline]
pub fn sign(&self) -> Option<Ordering> {
if self.is_nan() {
None
} else {
let ret = unsafe { mpfr::sgn(self.inner()) };
Some(ordering1(ret))
}
}
#[inline]
pub fn cmp_abs(&self, other: &Float) -> Option<Ordering> {
unsafe {
match mpfr::unordered_p(self.inner(), other.inner()) {
0 => Some(ordering1(mpfr::cmpabs(self.inner(), other.inner()))),
_ => None,
}
}
}
#[inline]
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
}
}
#[inline]
pub fn is_sign_positive(&self) -> bool {
!self.is_sign_negative()
}
#[inline]
pub fn is_sign_negative(&self) -> bool {
unsafe { mpfr::signbit(self.inner()) != 0 }
}
#[inline]
pub fn subnormalize(&mut self) -> &mut Float {
self.subnormalize_round(Ordering::Equal, Round::Nearest);
self
}
#[inline]
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 ret =
unsafe { mpfr::subnormalize(self.inner_mut(), prev, rraw(round)) };
ordering1(ret)
}
math_op1_float! {
mpfr::sqr;
fn square();
fn square_mut;
fn square_round;
fn square_ref -> SquareRef;
}
math_op1_float! {
mpfr::sqrt;
fn sqrt();
fn sqrt_mut;
fn sqrt_round;
fn sqrt_ref -> SqrtRef;
}
#[inline]
pub fn assign_sqrt_u(&mut self, u: u32) {
self.assign_sqrt_u_round(u, Round::Nearest);
}
#[inline]
pub fn assign_sqrt_u_round(&mut self, u: u32, round: Round) -> Ordering {
let ret =
unsafe { mpfr::sqrt_ui(self.inner_mut(), u.into(), rraw(round)) };
ordering1(ret)
}
math_op1_float! {
mpfr::rec_sqrt;
fn recip_sqrt();
fn recip_sqrt_mut;
fn recip_sqrt_round;
fn recip_sqrt_ref -> RecipSqrtRef;
}
math_op1_float! {
mpfr::cbrt;
fn cbrt();
fn cbrt_mut;
fn cbrt_round;
fn cbrt_ref -> CbrtRef;
}
math_op1_float! {
mpfr::root;
fn root(k: u32);
fn root_mut;
fn root_round;
fn root_ref -> RootRef;
}
math_op1_no_round! {
Float;
mpfr::abs, rraw;
fn abs();
fn abs_mut;
fn abs_ref -> AbsRef;
}
math_op1_float! {
xmpfr::recip;
fn recip();
fn recip_mut;
fn recip_round;
fn recip_ref -> RecipRef;
}
math_op2_float! {
mpfr::min;
fn min(other);
fn min_mut;
fn min_round;
fn min_ref -> MinRef;
}
math_op2_float! {
mpfr::max;
fn max(other);
fn max_mut;
fn max_round;
fn max_ref -> MaxRef;
}
math_op2_float! {
mpfr::dim;
fn pos_diff(other);
fn pos_diff_mut;
fn pos_diff_round;
fn pos_diff_ref -> AbsDiffRef;
}
math_op1_float! {
mpfr::log;
fn ln();
fn ln_mut;
fn ln_round;
fn ln_ref -> LnRef;
}
math_op1_float! {
mpfr::log2;
fn log2();
fn log2_mut;
fn log2_round;
fn log2_ref -> Log2Ref;
}
math_op1_float! {
mpfr::log10;
fn log10();
fn log10_mut;
fn log10_round;
fn log10_ref -> Log10Ref;
}
math_op1_float! {
mpfr::exp;
fn exp();
fn exp_mut;
fn exp_round;
fn exp_ref -> ExpRef;
}
math_op1_float! {
mpfr::exp2;
fn exp2();
fn exp2_mut;
fn exp2_round;
fn exp2_ref -> Exp2Ref;
}
math_op1_float! {
mpfr::exp10;
fn exp10();
fn exp10_mut;
fn exp10_round;
fn exp10_ref -> Exp10Ref;
}
math_op1_float! {
mpfr::sin;
fn sin();
fn sin_mut;
fn sin_round;
fn sin_ref -> SinRef;
}
math_op1_float! {
mpfr::cos;
fn cos();
fn cos_mut;
fn cos_round;
fn cos_ref -> CosRef;
}
math_op1_float! {
mpfr::tan;
fn tan();
fn tan_mut;
fn tan_round;
fn tan_ref -> TanRef;
}
math_op1_2_float! {
mpfr::sin_cos;
fn sin_cos(cos);
fn sin_cos_mut;
fn sin_cos_round;
fn sin_cos_ref -> SinCosRef;
}
math_op1_float! {
mpfr::sec;
fn sec();
fn sec_mut;
fn sec_round;
fn sec_ref -> SecRef;
}
math_op1_float! {
mpfr::csc;
fn csc();
fn csc_mut;
fn csc_round;
fn csc_ref -> CscRef;
}
math_op1_float! {
mpfr::cot;
fn cot();
fn cot_mut;
fn cot_round;
fn cot_ref -> CotRef;
}
math_op1_float! {
mpfr::acos;
fn acos();
fn acos_mut;
fn acos_round;
fn acos_ref -> AcosRef;
}
math_op1_float! {
mpfr::asin;
fn asin();
fn asin_mut;
fn asin_round;
fn asin_ref -> AsinRef;
}
math_op1_float! {
mpfr::atan;
fn atan();
fn atan_mut;
fn atan_round;
fn atan_ref -> AtanRef;
}
math_op2_float! {
mpfr::atan2;
fn atan2(other);
fn atan2_mut;
fn atan2_round;
fn atan2_ref -> Atan2Ref;
}
math_op1_float! {
mpfr::sinh;
fn sinh();
fn sinh_mut;
fn sinh_round;
fn sinh_ref -> SinhRef;
}
math_op1_float! {
mpfr::cosh;
fn cosh();
fn cosh_mut;
fn cosh_round;
fn cosh_ref -> CoshRef;
}
math_op1_float! {
mpfr::tanh;
fn tanh();
fn tanh_mut;
fn tanh_round;
fn tanh_ref -> TanhRef;
}
math_op1_2_float! {
mpfr::sinh_cosh;
fn sinh_cosh(cos);
fn sinh_cosh_mut;
fn sinh_cosh_round;
fn sinh_cosh_ref -> SinhCoshRef;
}
math_op1_float! {
mpfr::sech;
fn sech();
fn sech_mut;
fn sech_round;
fn sech_ref -> SechRef;
}
math_op1_float! {
mpfr::csch;
fn csch();
fn csch_mut;
fn csch_round;
fn csch_ref -> CschRef;
}
math_op1_float! {
mpfr::coth;
fn coth();
fn coth_mut;
fn coth_round;
fn coth_ref -> CothRef;
}
math_op1_float! {
mpfr::acosh;
fn acosh();
fn acosh_mut;
fn acosh_round;
fn acosh_ref -> AcoshRef;
}
math_op1_float! {
mpfr::asinh;
fn asinh();
fn asinh_mut;
fn asinh_round;
fn asinh_ref -> AsinhRef;
}
math_op1_float! {
mpfr::atanh;
fn atanh();
fn atanh_mut;
fn atanh_round;
fn atanh_ref -> AtanhRef;
}
#[inline]
pub fn assign_factorial_u(&mut self, u: u32) {
self.assign_factorial_u_round(u, Round::Nearest);
}
#[inline]
pub fn assign_factorial_u_round(
&mut self,
u: u32,
round: Round,
) -> Ordering {
let ret =
unsafe { mpfr::fac_ui(self.inner_mut(), u.into(), rraw(round)) };
ordering1(ret)
}
math_op1_float! {
mpfr::log1p;
fn ln_1p();
fn ln_1p_mut;
fn ln_1p_round;
fn ln_1p_ref -> Ln1pRef;
}
math_op1_float! {
mpfr::expm1;
fn exp_m1();
fn exp_m1_mut;
fn exp_m1_round;
fn exp_m1_ref -> ExpM1Ref;
}
math_op1_float! {
mpfr::eint;
fn eint();
fn eint_mut;
fn eint_round;
fn eint_ref -> EintRef;
}
math_op1_float! {
mpfr::li2;
fn li2();
fn li2_mut;
fn li2_round;
fn li2_ref -> Li2Ref;
}
math_op1_float! {
mpfr::gamma;
fn gamma();
fn gamma_mut;
fn gamma_round;
fn gamma_ref -> GammaRef;
}
math_op1_float! {
mpfr::lngamma;
fn ln_gamma();
fn ln_gamma_mut;
fn ln_gamma_round;
fn ln_gamma_ref -> LnGammaRef;
}
#[inline]
pub fn ln_abs_gamma(mut self) -> (Float, Ordering) {
let sign = self.ln_abs_gamma_round(Round::Nearest).0;
(self, sign)
}
#[inline]
pub fn ln_abs_gamma_mut(&mut self) -> Ordering {
self.ln_abs_gamma_round(Round::Nearest).0
}
#[inline]
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 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, ordering1(ret))
}
#[inline]
pub fn ln_abs_gamma_ref(&self) -> LnAbsGammaRef {
LnAbsGammaRef { ref_self: self }
}
math_op1_float! {
mpfr::digamma;
fn digamma();
fn digamma_mut;
fn digamma_round;
fn digamma_ref -> DigammaRef;
}
math_op1_float! {
mpfr::zeta;
fn zeta();
fn zeta_mut;
fn zeta_round;
fn zeta_ref -> ZetaRef;
}
#[inline]
pub fn assign_zeta_u(&mut self, u: u32) {
self.assign_zeta_u_round(u, Round::Nearest);
}
#[inline]
pub fn assign_zeta_u_round(&mut self, u: u32, round: Round) -> Ordering {
let ret =
unsafe { mpfr::zeta_ui(self.inner_mut(), u.into(), rraw(round)) };
ordering1(ret)
}
math_op1_float! {
mpfr::erf;
fn erf();
fn erf_mut;
fn erf_round;
fn erf_ref -> ErfRef;
}
math_op1_float! {
mpfr::erfc;
fn erfc();
fn erfc_mut;
fn erfc_round;
fn erfc_ref -> ErfcRef;
}
math_op1_float! {
mpfr::j0;
fn j0();
fn j0_mut;
fn j0_round;
fn j0_ref -> J0Ref;
}
math_op1_float! {
mpfr::j1;
fn j1();
fn j1_mut;
fn j1_round;
fn j1_ref -> J1Ref;
}
math_op1_float! {
xmpfr::jn;
fn jn(n: i32);
fn jn_mut;
fn jn_round;
fn jn_ref -> JnRef;
}
math_op1_float! {
mpfr::y0;
fn y0();
fn y0_mut;
fn y0_round;
fn y0_ref -> Y0Ref;
}
math_op1_float! {
mpfr::y1;
fn y1();
fn y1_mut;
fn y1_round;
fn y1_ref -> Y1Ref;
}
math_op1_float! {
xmpfr::yn;
fn yn(n: i32);
fn yn_mut;
fn yn_round;
fn yn_ref -> YnRef;
}
math_op2_float! {
mpfr::agm;
fn agm(other);
fn agm_mut;
fn agm_round;
fn agm_ref -> AgmRef;
}
math_op2_float! {
mpfr::hypot;
fn hypot(other);
fn hypot_mut;
fn hypot_round;
fn hypot_ref -> HypotRef;
}
math_op1_float! {
mpfr::ai;
fn ai();
fn ai_mut;
fn ai_round;
fn ai_ref -> AiRef;
}
math_op1_no_round! {
Float;
mpfr::rint_ceil, rraw;
fn ceil();
fn ceil_mut;
fn ceil_ref -> CeilRef;
}
math_op1_no_round! {
Float;
mpfr::rint_floor, rraw;
fn floor();
fn floor_mut;
fn floor_ref -> FloorRef;
}
math_op1_no_round! {
Float;
mpfr::rint_round, rraw;
fn round();
fn round_mut;
fn round_ref -> RoundRef;
}
math_op1_no_round! {
Float;
mpfr::rint_trunc, rraw;
fn trunc();
fn trunc_mut;
fn trunc_ref -> TruncRef;
}
math_op1_no_round! {
Float;
mpfr::frac, rraw;
fn fract();
fn fract_mut;
fn fract_ref -> FractRef;
}
math_op1_2_float! {
mpfr::modf;
fn trunc_fract(fract);
fn trunc_fract_mut;
fn trunc_fract_round;
fn trunc_fract_ref -> TruncFractRef;
}
#[cfg(feature = "rand")]
#[inline]
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(())
}
}
#[cfg(feature = "rand")]
#[inline]
pub fn assign_random_cont(&mut self, rng: &mut RandState) {
self.assign_random_cont_round(rng, Round::Nearest);
}
#[cfg(feature = "rand")]
#[inline]
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)
}
#[cfg(feature = "rand")]
#[inline]
pub fn assign_random_gaussian(
&mut self,
other: Option<&mut Float>,
rng: &mut RandState,
) {
self.assign_random_gaussian_round(other, rng, Default::default());
}
#[cfg(feature = "rand")]
#[inline]
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 From<OrdFloat> for Float {
fn from(ord: OrdFloat) -> Float {
unsafe { mem::transmute(ord) }
}
}
impl Display for Float {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, false, "", false)
}
}
impl Debug for Float {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, false, "", true)
}
}
impl LowerExp for Float {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, false, "", false)
}
}
impl UpperExp for Float {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, true, "", false)
}
}
impl Binary for Float {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 2, false, "0b", false)
}
}
impl Octal for Float {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 8, false, "0o", false)
}
}
impl LowerHex for Float {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 16, false, "0x", false)
}
}
impl UpperHex for Float {
#[inline]
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>,
{
#[inline]
fn assign(&mut self, other: T) {
self.assign_round(other, Round::Nearest);
}
}
impl AssignRound<Constant> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(&mut self, other: Constant, round: Round) -> Ordering {
let 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))
}
}
};
ordering1(ret)
}
}
impl AssignRound<Special> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(&mut self, other: Special, _round: Round) -> Ordering {
unsafe {
const EXP_MAX: c_long = ((!0 as c_ulong) >> 1) as c_long;
const EXP_ZERO: c_long = 0 - EXP_MAX;
const EXP_INF: c_long = 2 - EXP_MAX;
match other {
Special::Zero => {
let ptr = self.inner_mut();
(*ptr).sign = 1;
(*ptr).exp = EXP_ZERO;
}
Special::NegZero => {
let ptr = self.inner_mut();
(*ptr).sign = -1;
(*ptr).exp = EXP_ZERO;
}
Special::Infinity => {
let ptr = self.inner_mut();
(*ptr).sign = 1;
(*ptr).exp = EXP_INF;
}
Special::NegInfinity => {
let ptr = self.inner_mut();
(*ptr).sign = -1;
(*ptr).exp = EXP_INF;
}
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;
#[inline]
fn assign_round(
&mut self,
other: &'a $T,
round: Round
) -> Ordering {
let ret = unsafe {
$func(self.inner_mut(), other.inner(), rraw(round))
};
ordering1(ret)
}
}
impl AssignRound<$T> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(&mut self, other: $T, round: Round) -> Ordering {
self.assign_round(&other, round)
}
}
};
}
assign! { Float, mpfr::set }
#[cfg(feature = "integer")]
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::min; struct MinRef { other } }
ref_math_op2_float! { mpfr::max; struct MaxRef { other } }
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) {
#[inline]
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;
#[inline]
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 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
};
ordering1(ret)
}
}
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 {} }
#[derive(Clone, Copy)]
pub struct BorrowFloat<'a> {
inner: mpfr_t,
phantom: PhantomData<&'a Float>,
}
impl<'a> Deref for BorrowFloat<'a> {
type Target = Float;
#[inline]
fn deref(&self) -> &Float {
let ptr = (&self.inner) as *const _ as *const _;
unsafe { &*ptr }
}
}
impl Neg for Float {
type Output = Float;
#[inline]
fn neg(mut self) -> Float {
self.neg_assign();
self
}
}
impl NegAssign for Float {
#[inline]
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>;
#[inline]
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;
#[inline]
fn assign_round(&mut self, src: NegRef<'a>, round: Round) -> Ordering {
let ret = unsafe {
mpfr::neg(self.inner_mut(), src.val.inner(), rraw(round))
};
ordering1(ret)
}
}
macro_rules! arith_binary_self_float {
{
$func:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$ImpAssignRound:ident $method_assign_round:ident;
$ImpFrom:ident $method_from:ident;
$ImpFromRound:ident $method_from_round:ident;
$Ref:ident
} => {
arith_binary_self_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$Imp $method;
$ImpAssign $method_assign;
$ImpAssignRound $method_assign_round;
$ImpFrom $method_from;
$ImpFromRound $method_from_round;
$Ref
}
}
}
#[cfg(feature = "integer")]
macro_rules! arith_forward_float {
{
$func:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$ImpAssignRound:ident $method_assign_round:ident;
$T:ty;
$Ref:ident $RefOwn:ident
} => {
arith_forward_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$Imp $method;
$ImpAssign $method_assign;
$ImpAssignRound $method_assign_round;
$T;
$Ref $RefOwn
}
}
}
#[cfg(feature = "integer")]
macro_rules! arith_commut_float {
{
$func:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$ImpAssignRound:ident $method_assign_round:ident;
$ImpFrom:ident $method_from:ident;
$ImpFromRound:ident $method_from_round:ident;
$T:ty;
$Ref:ident $RefOwn:ident
} => {
arith_commut_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$Imp $method;
$ImpAssign $method_assign;
$ImpAssignRound $method_assign_round;
$ImpFrom $method_from;
$ImpFromRound $method_from_round;
$T;
$Ref $RefOwn
}
}
}
#[cfg(feature = "integer")]
macro_rules! arith_noncommut_float {
{
$func:path, $func_from:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$ImpAssignRound:ident $method_assign_round:ident;
$ImpFrom:ident $method_from:ident;
$ImpFromRound:ident $method_from_round:ident;
$T:ty;
$Ref:ident $RefFrom:ident $RefOwn:ident $RefFromOwn:ident
} => {
arith_noncommut_round! {
Float, Round => Ordering;
$func, $func_from, rraw => ordering1;
$Imp $method;
$ImpAssign $method_assign;
$ImpAssignRound $method_assign_round;
$ImpFrom $method_from;
$ImpFromRound $method_from_round;
$T;
$Ref $RefFrom $RefOwn $RefFromOwn
}
}
}
arith_binary_self_float! {
mpfr::add;
Add add;
AddAssign add_assign;
AddAssignRound add_assign_round;
AddFrom add_from;
AddFromRound add_from_round;
AddRef
}
arith_binary_self_float! {
mpfr::sub;
Sub sub;
SubAssign sub_assign;
SubAssignRound sub_assign_round;
SubFrom sub_from;
SubFromRound sub_from_round;
SubRef
}
arith_binary_self_float! {
mpfr::mul;
Mul mul;
MulAssign mul_assign;
MulAssignRound mul_assign_round;
MulFrom mul_from;
MulFromRound mul_from_round;
MulRef
}
arith_binary_self_float! {
mpfr::div;
Div div;
DivAssign div_assign;
DivAssignRound div_assign_round;
DivFrom div_from;
DivFromRound div_from_round;
DivRef
}
arith_binary_self_float! {
mpfr::pow;
Pow pow;
PowAssign pow_assign;
PowAssignRound pow_assign_round;
PowFrom pow_from;
PowFromRound pow_from_round;
PowRef
}
#[cfg(feature = "integer")]
arith_commut_float! {
mpfr::add_z;
Add add;
AddAssign add_assign;
AddAssignRound add_assign_round;
AddFrom add_from;
AddFromRound add_from_round;
Integer;
AddRefInteger AddRefIntegerOwn
}
#[cfg(feature = "integer")]
arith_noncommut_float! {
mpfr::sub_z, mpfr::z_sub;
Sub sub;
SubAssign sub_assign;
SubAssignRound sub_assign_round;
SubFrom sub_from;
SubFromRound sub_from_round;
Integer;
SubRefInteger SubFromRefInteger SubRefIntegerOwn SubFromRefIntegerOwn
}
#[cfg(feature = "integer")]
arith_commut_float! {
mpfr::mul_z;
Mul mul;
MulAssign mul_assign;
MulAssignRound mul_assign_round;
MulFrom mul_from;
MulFromRound mul_from_round;
Integer;
MulRefInteger MulRefIntegerOwn
}
#[cfg(feature = "integer")]
arith_noncommut_float! {
mpfr::div_z, xmpfr::z_div;
Div div;
DivAssign div_assign;
DivAssignRound div_assign_round;
DivFrom div_from;
DivFromRound div_from_round;
Integer;
DivRefInteger DivFromRefInteger DivRefIntegerOwn DivFromRefIntegerOwn
}
#[cfg(feature = "integer")]
arith_forward_float! {
mpfr::pow_z;
Pow pow;
PowAssign pow_assign;
PowAssignRound pow_assign_round;
Integer;
PowRefInteger PowRefIntegerOwn
}
#[cfg(feature = "rational")]
arith_commut_float! {
mpfr::add_q;
Add add;
AddAssign add_assign;
AddAssignRound add_assign_round;
AddFrom add_from;
AddFromRound add_from_round;
Rational;
AddRefRational AddRefRationalOwn
}
#[cfg(feature = "rational")]
arith_noncommut_float! {
mpfr::sub_q, xmpfr::q_sub;
Sub sub;
SubAssign sub_assign;
SubAssignRound sub_assign_round;
SubFrom sub_from;
SubFromRound sub_from_round;
Rational;
SubRefRational SubFromRefRational SubRefRationalOwn SubFromRefRationalOwn
}
#[cfg(feature = "rational")]
arith_commut_float! {
mpfr::mul_q;
Mul mul;
MulAssign mul_assign;
MulAssignRound mul_assign_round;
MulFrom mul_from;
MulFromRound mul_from_round;
Rational;
MulRefRational MulRefRationalOwn
}
#[cfg(feature = "rational")]
arith_noncommut_float! {
mpfr::div_q, xmpfr::q_div;
Div div;
DivAssign div_assign;
DivAssignRound div_assign_round;
DivFrom div_from;
DivFromRound div_from_round;
Rational;
DivRefRational DivFromRefRational DivRefRationalOwn DivFromRefRationalOwn
}
macro_rules! arith_prim_exact_float {
{
$func:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$T:ty;
$Ref:ident
} => {
arith_prim_exact_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;
$ImpAssign:ident $method_assign:ident;
$ImpAssignRound:ident $method_assign_round:ident;
$ImpFrom:ident $method_from:ident;
$ImpFromRound:ident $method_from_round:ident;
$T:ty;
$Ref:ident
} => {
arith_prim_commut_round! {
Float, Round => Ordering;
$func, rraw => ordering1;
$Imp $method;
$ImpAssign $method_assign;
$ImpAssignRound $method_assign_round;
$ImpFrom $method_from;
$ImpFromRound $method_from_round;
$T;
$Ref
}
}
}
macro_rules! arith_prim_noncommut_float {
{
$func:path, $func_from:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$ImpAssignRound:ident $method_assign_round:ident;
$ImpFrom:ident $method_from:ident;
$ImpFromRound:ident $method_from_round:ident;
$T:ty;
$Ref:ident $RefFrom:ident
} => {
arith_prim_noncommut_round! {
Float, Round => Ordering;
$func, $func_from, rraw => ordering1;
$Imp $method;
$ImpAssign $method_assign;
$ImpAssignRound $method_assign_round;
$ImpFrom $method_from;
$ImpFromRound $method_from_round;
$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;
#[inline]
fn assign_round(&mut self, val: $T, round: Round) -> Ordering {
let ret = unsafe {
$set(self.inner_mut(), val.into(), rraw(round))
};
ordering1(ret)
}
}
arith_prim_commut_float! {
$add;
Add add;
AddAssign add_assign;
AddAssignRound add_assign_round;
AddFrom add_from;
AddFromRound add_from_round;
$T;
$AddRef
}
arith_prim_noncommut_float! {
$sub, $sub_from;
Sub sub;
SubAssign sub_assign;
SubAssignRound sub_assign_round;
SubFrom sub_from;
SubFromRound sub_from_round;
$T;
$SubRef $SubFromRef
}
arith_prim_commut_float! {
$mul;
Mul mul;
MulAssign mul_assign;
MulAssignRound mul_assign_round;
MulFrom mul_from;
MulFromRound mul_from_round;
$T;
$MulRef
}
arith_prim_noncommut_float! {
$div, $div_from;
Div div;
DivAssign div_assign;
DivAssignRound div_assign_round;
DivFrom div_from;
DivFromRound div_from_round;
$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;
#[inline]
fn assign_round(&mut self, other: i64, round: Round) -> Ordering {
let ret =
unsafe { xmpfr::set_i64(self.inner_mut(), other, rraw(round)) };
ordering1(ret)
}
}
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;
#[inline]
fn assign_round(&mut self, other: u64, round: Round) -> Ordering {
let ret =
unsafe { xmpfr::set_u64(self.inner_mut(), other, rraw(round)) };
ordering1(ret)
}
}
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_exact_float! {
mpfr::mul_2ui;
Shl shl;
ShlAssign shl_assign;
u32;
ShlRefU32
}
arith_prim_exact_float! {
mpfr::div_2ui;
Shr shr;
ShrAssign shr_assign;
u32;
ShrRefU32
}
arith_prim_noncommut_float!{
mpfr::pow_ui, mpfr::ui_pow;
Pow pow;
PowAssign pow_assign;
PowAssignRound pow_assign_round;
PowFrom pow_from;
PowFromRound pow_from_round;
u32;
PowRefU32 PowFromRefU32
}
arith_prim_exact_float! {
mpfr::mul_2si;
Shl shl;
ShlAssign shl_assign;
i32;
ShlRefI32
}
arith_prim_exact_float! {
mpfr::div_2si;
Shr shr;
ShrAssign shr_assign;
i32;
ShrRefI32
}
arith_prim_noncommut_float!{
mpfr::pow_si, xmpfr::si_pow;
Pow pow;
PowAssign pow_assign;
PowAssignRound pow_assign_round;
PowFrom pow_from;
PowFromRound pow_from_round;
i32;
PowRefI32 PowFromRefI32
}
arith_prim_noncommut_float!{
xmpfr::pow_f64, xmpfr::f64_pow;
Pow pow;
PowAssign pow_assign;
PowAssignRound pow_assign_round;
PowFrom pow_from;
PowFromRound pow_from_round;
f64;
PowRefF64 PowFromRefF64
}
arith_prim_noncommut_float!{
xmpfr::pow_f32, xmpfr::f32_pow;
Pow pow;
PowAssign pow_assign;
PowAssignRound pow_assign_round;
PowFrom pow_from;
PowFromRound pow_from_round;
f32;
PowRefF32 PowFromRefF32
}
mul_op_commut_round! {
Float, Round => Ordering;
add_mul, rraw => ordering1;
Add add;
AddAssign add_assign;
AddAssignRound add_assign_round;
AddFrom add_from;
AddFromRound add_from_round;
MulRef;
AddMulRef
}
mul_op_noncommut_round! {
Float, Round => Ordering;
sub_mul, mul_sub, rraw => ordering1;
Sub sub;
SubAssign sub_assign;
SubAssignRound sub_assign_round;
SubFrom sub_from;
SubFromRound sub_from_round;
MulRef;
SubMulRef SubMulFromRef
}
unsafe fn add_mul(
rop: *mut mpfr_t,
add: *const mpfr_t,
mul: MulRef,
rnd: mpfr::rnd_t,
) -> c_int {
mpfr::fma(rop, mul.lhs.inner(), mul.rhs.inner(), add, rnd)
}
unsafe fn sub_mul(
rop: *mut mpfr_t,
add: *const mpfr_t,
mul: MulRef,
rnd: mpfr::rnd_t,
) -> c_int {
xmpfr::submul(rop, add, (mul.lhs.inner(), mul.rhs.inner()), rnd)
}
unsafe fn mul_sub(
rop: *mut mpfr_t,
mul: MulRef,
sub: *const mpfr_t,
rnd: mpfr::rnd_t,
) -> c_int {
mpfr::fms(rop, mul.lhs.inner(), mul.rhs.inner(), sub, rnd)
}
impl PartialEq for Float {
#[inline]
fn eq(&self, other: &Float) -> bool {
unsafe { mpfr::equal_p(self.inner(), other.inner()) != 0 }
}
}
impl PartialOrd for Float {
#[inline]
fn partial_cmp(&self, other: &Float) -> Option<Ordering> {
unsafe {
match mpfr::unordered_p(self.inner(), other.inner()) {
0 => Some(ordering1(mpfr::cmp(self.inner(), other.inner()))),
_ => None,
}
}
}
#[inline]
fn lt(&self, other: &Float) -> bool {
unsafe { mpfr::less_p(self.inner(), other.inner()) != 0 }
}
#[inline]
fn le(&self, other: &Float) -> bool {
unsafe { mpfr::lessequal_p(self.inner(), other.inner()) != 0 }
}
#[inline]
fn gt(&self, other: &Float) -> bool {
unsafe { mpfr::greater_p(self.inner(), other.inner()) != 0 }
}
#[inline]
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 {
#[inline]
fn eq(&self, other: &$T) -> bool {
self.partial_cmp(other) == Some(Ordering::Equal)
}
}
impl PartialOrd<$T> for Float {
#[inline]
fn partial_cmp(&self, other: &$T) -> Option<Ordering> {
if self.is_nan() {
return None;
}
Some(ordering1($eval(self.inner(), other)))
}
}
impl PartialEq<Float> for $T {
#[inline]
fn eq(&self, other: &Float) -> bool {
other.eq(self)
}
}
impl PartialOrd<Float> for $T {
#[inline]
fn partial_cmp(&self, other: &Float) -> Option<Ordering> {
other.partial_cmp(self).map(Ordering::reverse)
}
}
}
}
#[cfg(feature = "integer")]
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) } }
sum_prod! { Float, Float::with_val(53, 0), Float::with_val(53, 1) }
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.is_sign_negative()) {
(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);
}
let exp = exp.checked_sub(1).expect("overflow");
if exp != 0 {
buf.push(if radix <= 10 {
char_to_upper_if('e', to_upper)
} else {
'@'
});
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.is_sign_negative(),
&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 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);
ordering1(ret)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ParseFloatError {
kind: ParseErrorKind,
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
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 {
#[inline]
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;
#[inline]
fn inner(&self) -> &mpfr_t {
&self.inner
}
}
impl InnerMut for Float {
#[inline]
unsafe fn inner_mut(&mut self) -> &mut mpfr_t {
&mut self.inner
}
}