use Assign;
#[cfg(feature = "integer")]
use Integer;
#[cfg(feature = "rational")]
use Rational;
use ext::mpfr as xmpfr;
use float::{self, AssignRound, OrdFloat, Round, SmallFloat, Special};
use gmp_mpfr_sys::mpfr::{self, mpfr_t};
use inner::{Inner, InnerMut};
use ops::NegAssign;
#[cfg(feature = "rand")]
use rand::RandState;
use std::{i32, u32};
use std::ascii::AsciiExt;
use std::cmp::Ordering;
use std::error::Error;
use std::ffi::CStr;
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::os::raw::{c_char, c_int, c_long, c_ulong};
use std::ptr;
#[inline]
pub 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,
}
}
#[inline]
pub 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,
}
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_mut])*
fn $method_mut;
$(#[$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_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 >= float::prec_min() && prec <= float::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 >= float::prec_min() && prec <= float::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::ParseErrorKind as Kind;
use self::ParseFloatError as Error;
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 >= c_long::from(i32::MAX) {
Some(i32::MAX)
} else if i <= c_long::from(i32::MIN) {
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 >= c_ulong::from(u32::MAX) {
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 {
unsafe { xmpfr::get_f32(self.inner(), rraw(round)) }
}
#[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 cmp0(&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 <= mpfr::exp_t::from(i32::MAX), "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 (emin, emax) = match self.prec() {
11 => (-23, 16),
24 => (-148, 128),
53 => (-1073, 1024),
113 => (-16_493, 16_384),
237 => (-262_377, 262_144),
_ => return prev_rounding,
};
let prev = match prev_rounding {
Ordering::Less => -1,
Ordering::Equal => 0,
Ordering::Greater => 1,
};
unsafe {
let save_emin = mpfr::get_emin();
let save_emax = mpfr::get_emax();
mpfr::set_emin(emin);
mpfr::set_emax(emax);
let ret = mpfr::subnormalize(self.inner_mut(), prev, rraw(round));
mpfr::set_emin(save_emin);
mpfr::set_emax(save_emax);
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;
}
#[inline]
pub fn clamp<'a, Min, Max>(mut self, min: &'a Min, max: &'a Max) -> Float
where
Float: PartialOrd<Min>
+ PartialOrd<Max>
+ AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ AssignRound<&'a Max, Round = Round, Ordering = Ordering>,
{
self.clamp_round(min, max, Round::Nearest);
self
}
#[inline]
pub fn clamp_mut<'a, Min, Max>(&mut self, min: &'a Min, max: &'a Max)
where
Float: PartialOrd<Min>
+ PartialOrd<Max>
+ AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ AssignRound<&'a Max, Round = Round, Ordering = Ordering>,
{
self.clamp_round(min, max, Round::Nearest);
}
pub fn clamp_round<'a, Min, Max>(
&mut self,
min: &'a Min,
max: &'a Max,
round: Round,
) -> Ordering
where
Float: PartialOrd<Min>
+ PartialOrd<Max>
+ AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ AssignRound<&'a Max, Round = Round, Ordering = Ordering>,
{
if (&*self).lt(min) {
let dir = self.assign_round(min, round);
assert!(!(&*self).gt(max), "minimum larger than maximum");
dir
} else if (&*self).gt(max) {
let dir = self.assign_round(max, round);
assert!(!(&*self).lt(min), "minimum larger than maximum");
dir
} else {
Ordering::Equal
}
}
#[inline]
pub fn clamp_ref<'a, Min, Max>(
&'a self,
min: &'a Min,
max: &'a Max,
) -> ClampRef<'a, Min, Max>
where
Float: PartialOrd<Min>
+ PartialOrd<Max>
+ AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ AssignRound<&'a Max, Round = Round, Ordering = Ordering>,
{
ClampRef {
ref_self: self,
min,
max,
}
}
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 positive_diff(other);
fn positive_diff_mut;
fn positive_diff_round;
fn positive_diff_ref -> PositiveDiffRef;
}
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::asin;
fn asin();
fn asin_mut;
fn asin_round;
fn asin_ref -> AsinRef;
}
math_op1_float! {
mpfr::acos;
fn acos();
fn acos_mut;
fn acos_round;
fn acos_ref -> AcosRef;
}
math_op1_float! {
mpfr::atan;
fn atan();
fn atan_mut;
fn atan_round;
fn atan_ref -> AtanRef;
}
math_op2_float! {
mpfr::atan2;
fn atan2(x);
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::asinh;
fn asinh();
fn asinh_mut;
fn asinh_round;
fn asinh_ref -> AsinhRef;
}
math_op1_float! {
mpfr::acosh;
fn acosh();
fn acosh_mut;
fn acosh_round;
fn acosh_ref -> AcoshRef;
}
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)
}
}
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 {} }
#[derive(Clone, Copy)]
pub struct ClampRef<'a, Min, Max>
where
Float: PartialOrd<Min>
+ PartialOrd<Max>
+ AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ AssignRound<&'a Max, Round = Round, Ordering = Ordering>,
Min: 'a,
Max: 'a,
{
ref_self: &'a Float,
min: &'a Min,
max: &'a Max,
}
impl<'a, Min, Max> AssignRound<ClampRef<'a, Min, Max>> for Float
where
Float: PartialOrd<Min>
+ PartialOrd<Max>
+ AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ AssignRound<&'a Max, Round = Round, Ordering = Ordering>,
Min: 'a,
Max: 'a,
{
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(
&mut self,
src: ClampRef<'a, Min, Max>,
round: Round,
) -> Ordering {
if src.ref_self.lt(src.min) {
let dir = self.assign_round(src.min, round);
assert!(!(&*self).gt(src.max), "minimum larger than maximum");
dir
} else if src.ref_self.gt(src.max) {
let dir = self.assign_round(src.max, round);
assert!(!(&*self).lt(src.min), "minimum larger than maximum");
dir
} else {
self.assign_round(src.ref_self, round)
}
}
}
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 PositiveDiffRef { 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 { x } }
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 }
}
}
pub 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
}
#[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",
}
}
}
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
}
}