use crate::cast::cast;
use crate::ext::xmpfr::{self, ordering1, raw_round};
use crate::float::arith::{
AddMulIncomplete, MulAddMulIncomplete, MulSubMulIncomplete,
SubMulFromIncomplete,
};
use crate::float::{self, OrdFloat, Round, SmallFloat, Special};
#[cfg(feature = "integer")]
use crate::integer::big::BorrowInteger;
use crate::misc;
use crate::ops::{AddAssignRound, AssignRound, NegAssign};
#[cfg(feature = "rand")]
use crate::rand::RandState;
use crate::Assign;
#[cfg(feature = "integer")]
use crate::Integer;
#[cfg(feature = "rational")]
use crate::Rational;
#[cfg(feature = "integer")]
use gmp_mpfr_sys::gmp;
use gmp_mpfr_sys::mpfr::{self, mpfr_t};
use std::cmp::Ordering;
use std::error::Error;
use std::ffi::{CStr, CString};
use std::marker::PhantomData;
use std::mem;
use std::num::FpCategory;
use std::ops::{Add, AddAssign, Deref};
use std::os::raw::{c_char, c_int, c_long, c_ulong};
use std::ptr;
use std::str;
use std::{i32, u32};
#[repr(transparent)]
pub struct Float {
inner: mpfr_t,
}
impl Float {
pub(crate) fn inner(&self) -> &mpfr_t {
&self.inner
}
pub(crate) unsafe fn inner_mut(&mut self) -> &mut mpfr_t {
&mut self.inner
}
}
fn _static_assertions() {
static_assert_size!(Float, mpfr_t);
static_assert_size!(BorrowFloat<'_>, mpfr_t);
}
macro_rules! ref_math_op0_float {
(
$func:path;
$(#[$attr_ref:meta])*
struct $Incomplete:ident { $($param:ident: $T:ty),* }
) => {
ref_math_op0_round! {
Float, Round => Ordering;
$func;
$(#[$attr_ref])*
struct $Incomplete { $($param: $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 -> $Incomplete:ident;
) => {
math_op1_round! {
Round => Ordering;
$func;
$(#[$attr])*
fn $method($($param: $T),*);
$(#[$attr_mut])*
fn $method_mut;
$(#[$attr_round])*
fn $method_round;
$(#[$attr_ref])*
fn $method_ref -> $Incomplete;
}
};
}
macro_rules! ref_math_op1_float {
(
$func:path;
$(#[$attr_ref:meta])*
struct $Incomplete:ident { $($param:ident: $T:ty),* }
) => {
ref_math_op1_round! {
Float, Round => Ordering;
$func;
$(#[$attr_ref])*
struct $Incomplete { $($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 -> $Incomplete:ident;
) => {
math_op1_2_round! {
Round => (Ordering, Ordering);
$func;
$(#[$attr])*
fn $method($rop $(, $param: $T)*);
$(#[$attr_mut])*
fn $method_mut;
$(#[$attr_round])*
fn $method_round;
$(#[$attr_ref])*
fn $method_ref -> $Incomplete;
}
};
}
macro_rules! ref_math_op1_2_float {
(
$func:path;
$(#[$attr_ref:meta])*
struct $Incomplete:ident { $($param:ident: $T:ty),* }
) => {
ref_math_op1_2_round! {
Float, Round => (Ordering, Ordering);
$func;
$(#[$attr_ref])*
struct $Incomplete { $($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 -> $Incomplete:ident;
) => {
math_op2_round! {
Round => Ordering;
$func;
$(#[$attr])*
fn $method($op $(, $param: $T)*);
$(#[$attr_mut])*
fn $method_mut;
$(#[$attr_round])*
fn $method_round;
$(#[$attr_ref])*
fn $method_ref -> $Incomplete;
}
};
}
macro_rules! ref_math_op2_float {
(
$func:path;
$(#[$attr_ref:meta])*
struct $Incomplete:ident { $op:ident $(, $param:ident: $T:ty),* }
) => {
ref_math_op2_round! {
Float, Round => Ordering;
$func;
$(#[$attr_ref])*
struct $Incomplete { $op $(, $param: $T)* }
}
};
}
impl Float {
#[inline]
pub fn new(prec: u32) -> Self {
Self::with_val(prec, Special::Zero)
}
#[inline]
pub fn with_val<T>(prec: u32, val: T) -> Self
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,
) -> (Self, Ordering)
where
Self: 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) -> Self {
assert!(
prec >= float::prec_min() && prec <= float::prec_max(),
"precision out of range"
);
unsafe {
let mut ret: Float = mem::uninitialized();
mpfr::init2(ret.as_raw_mut(), cast(prec));
ret
}
}
#[inline]
pub fn prec(&self) -> u32 {
unsafe { cast(mpfr::get_prec(self.as_raw())) }
}
#[inline]
pub fn set_prec(&mut self, prec: u32) {
self.set_prec_round(prec, Default::default());
}
#[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.as_raw_mut(), cast(prec), raw_round(round))
};
ordering1(ret)
}
#[inline]
pub unsafe fn from_raw(raw: mpfr_t) -> Self {
Float { inner: raw }
}
#[inline]
pub fn into_raw(self) -> mpfr_t {
let ret = self.inner;
mem::forget(self);
ret
}
#[inline]
pub fn as_raw(&self) -> *const mpfr_t {
&self.inner
}
#[inline]
pub fn as_raw_mut(&mut self) -> *mut mpfr_t {
&mut self.inner
}
pub fn parse<S>(src: S) -> Result<ParseIncomplete, ParseFloatError>
where
S: AsRef<[u8]>,
{
parse(src.as_ref(), 10)
}
pub fn parse_radix<S>(
src: S,
radix: i32,
) -> Result<ParseIncomplete, ParseFloatError>
where
S: AsRef<[u8]>,
{
parse(src.as_ref(), radix)
}
#[cfg(feature = "integer")]
#[inline]
pub fn to_integer(&self) -> Option<Integer> {
self.to_integer_round(Default::default()).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.as_raw_mut(), self.as_raw(), raw_round(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.as_raw_mut(), self.as_raw()) };
Some((i, cast(exp)))
}
#[cfg(feature = "rational")]
#[inline]
pub fn to_rational(&self) -> Option<Rational> {
if !self.is_finite() {
return None;
}
let mut r = Rational::new();
unsafe {
mpfr::get_q(r.as_raw_mut(), self.as_raw());
}
Some(r)
}
#[inline]
pub fn to_i32_saturating(&self) -> Option<i32> {
self.to_i32_saturating_round(Default::default())
}
#[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.as_raw(), raw_round(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(Default::default())
}
#[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.as_raw(), raw_round(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(Default::default())
}
#[inline]
pub fn to_f32_round(&self, round: Round) -> f32 {
unsafe { xmpfr::get_f32(self.as_raw(), raw_round(round)) }
}
#[inline]
pub fn to_f64(&self) -> f64 {
self.to_f64_round(Default::default())
}
#[inline]
pub fn to_f64_round(&self, round: Round) -> f64 {
unsafe { mpfr::get_d(self.as_raw(), raw_round(round)) }
}
#[inline]
pub fn to_f32_exp(&self) -> (f32, i32) {
self.to_f32_exp_round(Default::default())
}
#[inline]
pub fn to_f32_exp_round(&self, round: Round) -> (f32, i32) {
let mut sf = SmallFloat::from(0.0f32);
assert_eq!(sf.prec(), 24);
let mut exp: c_long = 0;
let f = unsafe {
mpfr::set(
sf.as_nonreallocating_float().as_raw_mut(),
self.as_raw(),
raw_round(round),
);
mpfr::get_d_2exp(&mut exp, sf.as_raw(), raw_round(round))
};
(f as f32, cast(exp))
}
#[inline]
pub fn to_f64_exp(&self) -> (f64, i32) {
self.to_f64_exp_round(Default::default())
}
#[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.as_raw(), raw_round(round))
};
(f, cast(exp))
}
#[inline]
pub fn to_string_radix(
&self,
radix: i32,
num_digits: Option<usize>,
) -> String {
self.to_string_radix_round(radix, num_digits, Default::default())
}
#[inline]
pub fn to_string_radix_round(
&self,
radix: i32,
num_digits: Option<usize>,
round: Round,
) -> String {
let mut s = String::new();
let format =
Format { radix, precision: num_digits, round, ..Format::default() };
append_to_string(&mut s, self, format);
s
}
pub fn as_neg(&self) -> BorrowFloat<'_> {
let mut ret = BorrowFloat { inner: self.inner, phantom: PhantomData };
NegAssign::neg_assign(&mut ret.inner.sign);
if self.is_nan() {
unsafe {
mpfr::set_nanflag();
}
}
ret
}
pub fn as_abs(&self) -> BorrowFloat<'_> {
let mut ret = BorrowFloat { inner: self.inner, phantom: PhantomData };
ret.inner.sign = 1;
if self.is_nan() {
unsafe {
mpfr::set_nanflag();
}
}
ret
}
#[inline]
pub fn as_ord(&self) -> &OrdFloat {
unsafe { &*cast_ptr!(self, OrdFloat) }
}
#[inline]
pub fn is_integer(&self) -> bool {
unsafe { mpfr::integer_p(self.as_raw()) != 0 }
}
#[inline]
pub fn is_nan(&self) -> bool {
unsafe { mpfr::nan_p(self.as_raw()) != 0 }
}
#[inline]
pub fn is_infinite(&self) -> bool {
unsafe { mpfr::inf_p(self.as_raw()) != 0 }
}
#[inline]
pub fn is_finite(&self) -> bool {
unsafe { mpfr::number_p(self.as_raw()) != 0 }
}
#[inline]
pub fn is_zero(&self) -> bool {
unsafe { mpfr::zero_p(self.as_raw()) != 0 }
}
#[inline]
pub fn is_normal(&self) -> bool {
unsafe { mpfr::regular_p(self.as_raw()) != 0 }
}
#[inline]
pub fn classify(&self) -> FpCategory {
let inner: *const mpfr_t = self.as_raw();
unsafe {
if mpfr::nan_p(inner) != 0 {
FpCategory::Nan
} else if mpfr::inf_p(inner) != 0 {
FpCategory::Infinite
} else if mpfr::zero_p(inner) != 0 {
FpCategory::Zero
} else {
FpCategory::Normal
}
}
}
#[inline]
pub fn cmp0(&self) -> Option<Ordering> {
if self.is_nan() {
None
} else {
let ret = unsafe { mpfr::sgn(self.as_raw()) };
Some(ordering1(ret))
}
}
#[inline]
pub fn cmp_abs(&self, other: &Self) -> Option<Ordering> {
unsafe {
match mpfr::unordered_p(self.as_raw(), other.as_raw()) {
0 => {
Some(ordering1(mpfr::cmpabs(self.as_raw(), other.as_raw())))
}
_ => None,
}
}
}
#[inline]
pub fn get_exp(&self) -> Option<i32> {
if self.is_normal() {
let e = unsafe { mpfr::get_exp(self.as_raw()) };
Some(cast(e))
} else {
None
}
}
#[cfg(feature = "integer")]
#[inline]
pub fn get_significand(&self) -> Option<BorrowInteger<'_>> {
if self.is_normal() {
let limb_bits = mpfr::prec_t::from(gmp::LIMB_BITS);
let limbs = (self.inner.prec - 1) / limb_bits + 1;
Some(BorrowInteger {
inner: gmp::mpz_t {
alloc: cast(limbs),
size: cast(limbs),
d: self.inner.d,
},
phantom: PhantomData,
})
} 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.as_raw()) != 0 }
}
#[inline]
pub fn next_toward(&mut self, to: &Self) {
unsafe {
mpfr::nexttoward(self.as_raw_mut(), to.as_raw());
}
}
#[inline]
pub fn next_up(&mut self) {
unsafe {
mpfr::nextabove(self.as_raw_mut());
}
}
#[inline]
pub fn next_down(&mut self) {
unsafe {
mpfr::nextbelow(self.as_raw_mut());
}
}
#[inline]
pub fn subnormalize_ieee(&mut self) -> &mut Self {
self.subnormalize_ieee_round(Ordering::Equal, Default::default());
self
}
pub fn subnormalize_ieee_round(
&mut self,
prev_rounding: Ordering,
round: Round,
) -> Ordering {
let prec = self.prec();
let exp_bits = match ieee_storage_bits_for_prec(prec) {
Some(storage_bits) => storage_bits - prec,
None => return prev_rounding,
};
let normal_exp_min = (-1i32 << (exp_bits - 1)) + 3;
self.subnormalize_round(normal_exp_min, prev_rounding, round)
}
#[inline]
pub fn subnormalize(&mut self, normal_exp_min: i32) -> &mut Self {
self.subnormalize_round(
normal_exp_min,
Ordering::Equal,
Default::default(),
);
self
}
pub fn subnormalize_round(
&mut self,
normal_exp_min: i32,
prev_rounding: Ordering,
round: Round,
) -> Ordering {
if !self.is_normal() {
return prev_rounding;
}
let exp_min = mpfr::exp_t::from(normal_exp_min);
let sub_exp_min = exp_min
.checked_sub(cast::<_, mpfr::exp_t>(self.prec() - 1))
.expect("overflow");
let exp = unsafe { mpfr::get_exp(self.as_raw()) };
if exp < sub_exp_min || exp >= exp_min {
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();
assert!(save_emax >= exp_min, "`normal_exp_min` too large");
mpfr::set_emin(sub_exp_min);
mpfr::set_emax(exp_min);
let ret =
mpfr::subnormalize(self.as_raw_mut(), prev, raw_round(round));
mpfr::set_emin(save_emin);
mpfr::set_emax(save_emax);
ordering1(ret)
}
}
#[inline]
pub fn sum<'a, I>(values: I) -> SumIncomplete<'a, I>
where
I: Iterator<Item = &'a Self>,
{
SumIncomplete { values }
}
#[inline]
pub fn dot<'a, I>(values: I) -> DotIncomplete<'a, I>
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
DotIncomplete { values }
}
pub fn mul_add(mut self, mul: &Self, add: &Self) -> Self {
self.mul_add_round(mul, add, Default::default());
self
}
pub fn mul_add_mut(&mut self, mul: &Self, add: &Self) {
self.mul_add_round(mul, add, Default::default());
}
pub fn mul_add_round(
&mut self,
mul: &Self,
add: &Self,
round: Round,
) -> Ordering {
let ret = unsafe {
mpfr::fma(
self.as_raw_mut(),
self.as_raw(),
mul.as_raw(),
add.as_raw(),
raw_round(round),
)
};
ordering1(ret)
}
pub fn mul_add_ref<'a>(
&'a self,
mul: &'a Self,
add: &'a Self,
) -> AddMulIncomplete<'a> {
self * mul + add
}
pub fn mul_sub(mut self, mul: &Self, sub: &Self) -> Self {
self.mul_sub_round(mul, sub, Default::default());
self
}
pub fn mul_sub_mut(&mut self, mul: &Self, sub: &Self) {
self.mul_sub_round(mul, sub, Default::default());
}
pub fn mul_sub_round(
&mut self,
mul: &Self,
sub: &Self,
round: Round,
) -> Ordering {
let ret = unsafe {
mpfr::fms(
self.as_raw_mut(),
self.as_raw(),
mul.as_raw(),
sub.as_raw(),
raw_round(round),
)
};
ordering1(ret)
}
pub fn mul_sub_ref<'a>(
&'a self,
mul: &'a Self,
sub: &'a Self,
) -> SubMulFromIncomplete<'a> {
self * mul - sub
}
pub fn mul_add_mul(
mut self,
mul: &Self,
add_mul1: &Self,
add_mul2: &Self,
) -> Self {
self.mul_add_mul_round(mul, add_mul1, add_mul2, Default::default());
self
}
pub fn mul_add_mul_mut(
&mut self,
mul: &Self,
add_mul1: &Self,
add_mul2: &Self,
) {
self.mul_add_mul_round(mul, add_mul1, add_mul2, Default::default());
}
pub fn mul_add_mul_round(
&mut self,
mul: &Self,
add_mul1: &Self,
add_mul2: &Self,
round: Round,
) -> Ordering {
let ret = unsafe {
mpfr::fmma(
self.as_raw_mut(),
self.as_raw(),
mul.as_raw(),
add_mul1.as_raw(),
add_mul2.as_raw(),
raw_round(round),
)
};
ordering1(ret)
}
pub fn mul_add_mul_ref<'a>(
&'a self,
mul: &'a Self,
add_mul1: &'a Self,
add_mul2: &'a Self,
) -> MulAddMulIncomplete<'a> {
self * mul + add_mul1 * add_mul2
}
pub fn mul_sub_mul(
mut self,
mul: &Self,
sub_mul1: &Self,
sub_mul2: &Self,
) -> Self {
self.mul_sub_mul_round(mul, sub_mul1, sub_mul2, Default::default());
self
}
pub fn mul_sub_mul_mut(
&mut self,
mul: &Self,
sub_mul1: &Self,
sub_mul2: &Self,
) {
self.mul_sub_mul_round(mul, sub_mul1, sub_mul2, Default::default());
}
pub fn mul_sub_mul_round(
&mut self,
mul: &Self,
sub_mul1: &Self,
sub_mul2: &Self,
round: Round,
) -> Ordering {
let ret = unsafe {
mpfr::fmms(
self.as_raw_mut(),
self.as_raw(),
mul.as_raw(),
sub_mul1.as_raw(),
sub_mul2.as_raw(),
raw_round(round),
)
};
ordering1(ret)
}
pub fn mul_sub_mul_ref<'a>(
&'a self,
mul: &'a Self,
sub_mul1: &'a Self,
sub_mul2: &'a Self,
) -> MulSubMulIncomplete<'a> {
self * mul - sub_mul1 * sub_mul2
}
math_op0! {
fn u_pow_u(base: u32, exponent: u32) -> UPowUIncomplete;
}
math_op0! {
fn i_pow_u(base: i32, exponent: u32) -> IPowUIncomplete;
}
math_op1_float! {
xmpfr::sqr;
fn square();
fn square_mut;
fn square_round;
fn square_ref -> SquareIncomplete;
}
math_op1_float! {
xmpfr::sqrt;
fn sqrt();
fn sqrt_mut;
fn sqrt_round;
fn sqrt_ref -> SqrtIncomplete;
}
math_op0! {
fn sqrt_u(u: u32) -> SqrtUIncomplete;
}
math_op1_float! {
xmpfr::rec_sqrt;
fn recip_sqrt();
fn recip_sqrt_mut;
fn recip_sqrt_round;
fn recip_sqrt_ref -> RecipSqrtIncomplete;
}
math_op1_float! {
xmpfr::cbrt;
fn cbrt();
fn cbrt_mut;
fn cbrt_round;
fn cbrt_ref -> CbrtIncomplete;
}
math_op1_float! {
xmpfr::rootn_ui;
fn root(k: u32);
fn root_mut;
fn root_round;
fn root_ref -> RootIncomplete;
}
math_op1_no_round! {
xmpfr::abs;
fn abs();
fn abs_mut;
fn abs_ref -> AbsIncomplete;
}
math_op1_no_round! {
xmpfr::signum;
fn signum();
fn signum_mut;
fn signum_ref -> SignumIncomplete;
}
math_op2_no_round! {
xmpfr::copysign;
fn copysign(y);
fn copysign_mut;
fn copysign_ref -> CopysignIncomplete;
}
#[inline]
pub fn clamp<'a, 'b, Min, Max>(mut self, min: &'a Min, max: &'b Max) -> Self
where
Self: PartialOrd<Min>
+ PartialOrd<Max>
+ AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ AssignRound<&'b Max, Round = Round, Ordering = Ordering>,
{
self.clamp_round(min, max, Default::default());
self
}
#[inline]
pub fn clamp_mut<'a, 'b, Min, Max>(&mut self, min: &'a Min, max: &'b Max)
where
Self: PartialOrd<Min>
+ PartialOrd<Max>
+ AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ AssignRound<&'b Max, Round = Round, Ordering = Ordering>,
{
self.clamp_round(min, max, Default::default());
}
pub fn clamp_round<'a, 'b, Min, Max>(
&mut self,
min: &'a Min,
max: &'b Max,
round: Round,
) -> Ordering
where
Self: PartialOrd<Min>
+ PartialOrd<Max>
+ AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ AssignRound<&'b Max, Round = Round, Ordering = Ordering>,
{
if (*self).lt(min) {
let dir = self.assign_round(min, round);
if (*self).gt(max) {
let dir2 = self.assign_round(max, round);
assert!(
dir == dir2 && !(*self).lt(min),
"minimum larger than maximum"
);
dir
} else {
dir
}
} else if (*self).gt(max) {
let dir = self.assign_round(max, round);
if (*self).lt(min) {
let dir2 = self.assign_round(min, round);
assert!(
dir == dir2 && !(*self).gt(max),
"minimum larger than maximum"
);
dir
} else {
dir
}
} else {
if self.is_nan() {
unsafe {
mpfr::set_nanflag();
}
}
Ordering::Equal
}
}
#[inline]
pub fn clamp_ref<'a, Min, Max>(
&'a self,
min: &'a Min,
max: &'a Max,
) -> ClampIncomplete<'a, Min, Max>
where
Self: PartialOrd<Min>
+ PartialOrd<Max>
+ AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ AssignRound<&'a Max, Round = Round, Ordering = Ordering>,
{
ClampIncomplete { ref_self: self, min, max }
}
math_op1_float! {
xmpfr::recip;
fn recip();
fn recip_mut;
fn recip_round;
fn recip_ref -> RecipIncomplete;
}
math_op2_float! {
xmpfr::min;
fn min(other);
fn min_mut;
fn min_round;
fn min_ref -> MinIncomplete;
}
math_op2_float! {
xmpfr::max;
fn max(other);
fn max_mut;
fn max_round;
fn max_ref -> MaxIncomplete;
}
math_op2_float! {
xmpfr::dim;
fn positive_diff(other);
fn positive_diff_mut;
fn positive_diff_round;
fn positive_diff_ref -> PositiveDiffIncomplete;
}
math_op1_float! {
xmpfr::log;
fn ln();
fn ln_mut;
fn ln_round;
fn ln_ref -> LnIncomplete;
}
math_op0! {
fn ln_u(u: u32) -> LnUIncomplete;
}
math_op1_float! {
xmpfr::log2;
fn log2();
fn log2_mut;
fn log2_round;
fn log2_ref -> Log2Incomplete;
}
math_op1_float! {
xmpfr::log10;
fn log10();
fn log10_mut;
fn log10_round;
fn log10_ref -> Log10Incomplete;
}
math_op1_float! {
xmpfr::exp;
fn exp();
fn exp_mut;
fn exp_round;
fn exp_ref -> ExpIncomplete;
}
math_op1_float! {
xmpfr::exp2;
fn exp2();
fn exp2_mut;
fn exp2_round;
fn exp2_ref -> Exp2Incomplete;
}
math_op1_float! {
xmpfr::exp10;
fn exp10();
fn exp10_mut;
fn exp10_round;
fn exp10_ref -> Exp10Incomplete;
}
math_op1_float! {
xmpfr::sin;
fn sin();
fn sin_mut;
fn sin_round;
fn sin_ref -> SinIncomplete;
}
math_op1_float! {
xmpfr::cos;
fn cos();
fn cos_mut;
fn cos_round;
fn cos_ref -> CosIncomplete;
}
math_op1_float! {
xmpfr::tan;
fn tan();
fn tan_mut;
fn tan_round;
fn tan_ref -> TanIncomplete;
}
math_op1_2_float! {
xmpfr::sin_cos;
fn sin_cos(cos);
fn sin_cos_mut;
fn sin_cos_round;
fn sin_cos_ref -> SinCosIncomplete;
}
math_op1_float! {
xmpfr::sec;
fn sec();
fn sec_mut;
fn sec_round;
fn sec_ref -> SecIncomplete;
}
math_op1_float! {
xmpfr::csc;
fn csc();
fn csc_mut;
fn csc_round;
fn csc_ref -> CscIncomplete;
}
math_op1_float! {
xmpfr::cot;
fn cot();
fn cot_mut;
fn cot_round;
fn cot_ref -> CotIncomplete;
}
math_op1_float! {
xmpfr::asin;
fn asin();
fn asin_mut;
fn asin_round;
fn asin_ref -> AsinIncomplete;
}
math_op1_float! {
xmpfr::acos;
fn acos();
fn acos_mut;
fn acos_round;
fn acos_ref -> AcosIncomplete;
}
math_op1_float! {
xmpfr::atan;
fn atan();
fn atan_mut;
fn atan_round;
fn atan_ref -> AtanIncomplete;
}
math_op2_float! {
xmpfr::atan2;
fn atan2(x);
fn atan2_mut;
fn atan2_round;
fn atan2_ref -> Atan2Incomplete;
}
math_op1_float! {
xmpfr::sinh;
fn sinh();
fn sinh_mut;
fn sinh_round;
fn sinh_ref -> SinhIncomplete;
}
math_op1_float! {
xmpfr::cosh;
fn cosh();
fn cosh_mut;
fn cosh_round;
fn cosh_ref -> CoshIncomplete;
}
math_op1_float! {
xmpfr::tanh;
fn tanh();
fn tanh_mut;
fn tanh_round;
fn tanh_ref -> TanhIncomplete;
}
math_op1_2_float! {
xmpfr::sinh_cosh;
fn sinh_cosh(cos);
fn sinh_cosh_mut;
fn sinh_cosh_round;
fn sinh_cosh_ref -> SinhCoshIncomplete;
}
math_op1_float! {
xmpfr::sech;
fn sech();
fn sech_mut;
fn sech_round;
fn sech_ref -> SechIncomplete;
}
math_op1_float! {
xmpfr::csch;
fn csch();
fn csch_mut;
fn csch_round;
fn csch_ref -> CschIncomplete;
}
math_op1_float! {
xmpfr::coth;
fn coth();
fn coth_mut;
fn coth_round;
fn coth_ref -> CothIncomplete;
}
math_op1_float! {
xmpfr::asinh;
fn asinh();
fn asinh_mut;
fn asinh_round;
fn asinh_ref -> AsinhIncomplete;
}
math_op1_float! {
xmpfr::acosh;
fn acosh();
fn acosh_mut;
fn acosh_round;
fn acosh_ref -> AcoshIncomplete;
}
math_op1_float! {
xmpfr::atanh;
fn atanh();
fn atanh_mut;
fn atanh_round;
fn atanh_ref -> AtanhIncomplete;
}
math_op0! {
fn factorial(n: u32) -> FactorialIncomplete;
}
math_op1_float! {
xmpfr::log1p;
fn ln_1p();
fn ln_1p_mut;
fn ln_1p_round;
fn ln_1p_ref -> Ln1pIncomplete;
}
math_op1_float! {
xmpfr::expm1;
fn exp_m1();
fn exp_m1_mut;
fn exp_m1_round;
fn exp_m1_ref -> ExpM1Incomplete;
}
math_op1_float! {
xmpfr::eint;
fn eint();
fn eint_mut;
fn eint_round;
fn eint_ref -> EintIncomplete;
}
math_op1_float! {
xmpfr::li2;
fn li2();
fn li2_mut;
fn li2_round;
fn li2_ref -> Li2Incomplete;
}
math_op1_float! {
xmpfr::gamma;
fn gamma();
fn gamma_mut;
fn gamma_round;
fn gamma_ref -> GammaIncomplete;
}
math_op2_float! {
xmpfr::gamma_inc;
fn gamma_inc(x);
fn gamma_inc_mut;
fn gamma_inc_round;
fn gamma_inc_ref -> GammaIncIncomplete;
}
math_op1_float! {
xmpfr::lngamma;
fn ln_gamma();
fn ln_gamma_mut;
fn ln_gamma_round;
fn ln_gamma_ref -> LnGammaIncomplete;
}
#[inline]
pub fn ln_abs_gamma(mut self) -> (Self, Ordering) {
let sign = self.ln_abs_gamma_round(Default::default()).0;
(self, sign)
}
#[inline]
pub fn ln_abs_gamma_mut(&mut self) -> Ordering {
self.ln_abs_gamma_round(Default::default()).0
}
#[inline]
pub fn ln_abs_gamma_round(&mut self, round: Round) -> (Ordering, Ordering) {
let mut sign: c_int = 0;
let sign_ptr: *mut c_int = &mut sign;
let ret = unsafe {
mpfr::lgamma(
self.as_raw_mut(),
sign_ptr,
self.as_raw(),
raw_round(round),
)
};
let sign_ord =
if sign < 0 { Ordering::Less } else { Ordering::Greater };
(sign_ord, ordering1(ret))
}
#[inline]
pub fn ln_abs_gamma_ref(&self) -> LnAbsGammaIncomplete<'_> {
LnAbsGammaIncomplete { ref_self: self }
}
math_op1_float! {
xmpfr::digamma;
fn digamma();
fn digamma_mut;
fn digamma_round;
fn digamma_ref -> DigammaIncomplete;
}
math_op1_float! {
xmpfr::zeta;
fn zeta();
fn zeta_mut;
fn zeta_round;
fn zeta_ref -> ZetaIncomplete;
}
math_op0! {
fn zeta_u(u: u32) -> ZetaUIncomplete;
}
math_op1_float! {
xmpfr::erf;
fn erf();
fn erf_mut;
fn erf_round;
fn erf_ref -> ErfIncomplete;
}
math_op1_float! {
xmpfr::erfc;
fn erfc();
fn erfc_mut;
fn erfc_round;
fn erfc_ref -> ErfcIncomplete;
}
math_op1_float! {
xmpfr::j0;
fn j0();
fn j0_mut;
fn j0_round;
fn j0_ref -> J0Incomplete;
}
math_op1_float! {
xmpfr::j1;
fn j1();
fn j1_mut;
fn j1_round;
fn j1_ref -> J1Incomplete;
}
math_op1_float! {
xmpfr::jn;
fn jn(n: i32);
fn jn_mut;
fn jn_round;
fn jn_ref -> JnIncomplete;
}
math_op1_float! {
xmpfr::y0;
fn y0();
fn y0_mut;
fn y0_round;
fn y0_ref -> Y0Incomplete;
}
math_op1_float! {
xmpfr::y1;
fn y1();
fn y1_mut;
fn y1_round;
fn y1_ref -> Y1Incomplete;
}
math_op1_float! {
xmpfr::yn;
fn yn(n: i32);
fn yn_mut;
fn yn_round;
fn yn_ref -> YnIncomplete;
}
math_op2_float! {
xmpfr::agm;
fn agm(other);
fn agm_mut;
fn agm_round;
fn agm_ref -> AgmIncomplete;
}
math_op2_float! {
xmpfr::hypot;
fn hypot(other);
fn hypot_mut;
fn hypot_round;
fn hypot_ref -> HypotIncomplete;
}
math_op1_float! {
xmpfr::ai;
fn ai();
fn ai_mut;
fn ai_round;
fn ai_ref -> AiIncomplete;
}
math_op1_no_round! {
xmpfr::rint_ceil;
fn ceil();
fn ceil_mut;
fn ceil_ref -> CeilIncomplete;
}
math_op1_no_round! {
xmpfr::rint_floor;
fn floor();
fn floor_mut;
fn floor_ref -> FloorIncomplete;
}
math_op1_no_round! {
xmpfr::rint_round;
fn round();
fn round_mut;
fn round_ref -> RoundIncomplete;
}
math_op1_no_round! {
xmpfr::rint_roundeven;
fn round_even();
fn round_even_mut;
fn round_even_ref -> RoundEvenIncomplete;
}
math_op1_no_round! {
xmpfr::rint_trunc;
fn trunc();
fn trunc_mut;
fn trunc_ref -> TruncIncomplete;
}
math_op1_no_round! {
xmpfr::frac;
fn fract();
fn fract_mut;
fn fract_ref -> FractIncomplete;
}
math_op1_2_float! {
xmpfr::modf;
fn trunc_fract(fract);
fn trunc_fract_mut;
fn trunc_fract_round;
fn trunc_fract_ref -> TruncFractIncomplete;
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_bits<'a, 'b>(
rng: &'a mut RandState<'b>,
) -> RandomBitsIncomplete<'a, 'b>
where
'b: 'a,
{
RandomBitsIncomplete { rng }
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_cont<'a, 'b>(rng: &'a mut RandState<'b>) -> RandomCont<'a, 'b>
where
'b: 'a,
{
RandomCont { rng }
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_normal<'a, 'b>(
rng: &'a mut RandState<'b>,
) -> RandomNormal<'a, 'b>
where
'b: 'a,
{
RandomNormal { rng }
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_exp<'a, 'b>(rng: &'a mut RandState<'b>) -> RandomExp<'a, 'b>
where
'b: 'a,
{
RandomExp { rng }
}
}
#[derive(Debug)]
pub struct SumIncomplete<'a, I>
where
I: Iterator<Item = &'a Float>,
{
values: I,
}
impl<'a, I> AssignRound<SumIncomplete<'a, I>> for Float
where
I: Iterator<Item = &'a Self>,
{
type Round = Round;
type Ordering = Ordering;
fn assign_round(
&mut self,
src: SumIncomplete<'a, I>,
round: Round,
) -> Ordering {
let refs = src
.values
.map(|r| -> *const mpfr_t { r.as_raw() })
.collect::<Vec<_>>();
let tab = cast_ptr!(refs.as_ptr(), *mut mpfr_t);
let n = cast(refs.len());
let ret =
unsafe { mpfr::sum(self.as_raw_mut(), tab, n, raw_round(round)) };
ordering1(ret)
}
}
impl<'a, I> Add<SumIncomplete<'a, I>> for Float
where
I: Iterator<Item = &'a Self>,
{
type Output = Self;
#[inline]
fn add(mut self, rhs: SumIncomplete<'a, I>) -> Self {
self.add_assign_round(rhs, Default::default());
self
}
}
impl<'a, I> AddAssign<SumIncomplete<'a, I>> for Float
where
I: Iterator<Item = &'a Self>,
{
#[inline]
fn add_assign(&mut self, rhs: SumIncomplete<'a, I>) {
self.add_assign_round(rhs, Default::default());
}
}
impl<'a, I> AddAssignRound<SumIncomplete<'a, I>> for Float
where
I: Iterator<Item = &'a Self>,
{
type Round = Round;
type Ordering = Ordering;
fn add_assign_round(
&mut self,
src: SumIncomplete<'a, I>,
round: Round,
) -> Ordering {
let capacity = match src.values.size_hint() {
(lower, None) => lower + 1,
(_, Some(upper)) => upper + 1,
};
let mut refs = Vec::<*const mpfr_t>::with_capacity(capacity);
refs.push(self.as_raw());
refs.extend(src.values.map(|r| -> *const mpfr_t { r.as_raw() }));
let tab = cast_ptr!(refs.as_ptr(), *mut mpfr_t);
let n = cast(refs.len());
let ret =
unsafe { mpfr::sum(self.as_raw_mut(), tab, n, raw_round(round)) };
ordering1(ret)
}
}
#[derive(Debug)]
pub struct DotIncomplete<'a, I>
where
I: Iterator<Item = (&'a Float, &'a Float)>,
{
values: I,
}
fn exact_prods<'a, I>(i: I) -> Vec<Float>
where
I: Iterator<Item = (&'a Float, &'a Float)>,
{
i.map(|(a, b)| {
let prec = a.prec().checked_add(b.prec()).expect("overflow");
Float::with_val(prec, a * b)
})
.collect()
}
impl<'a, I> AssignRound<DotIncomplete<'a, I>> for Float
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
type Round = Round;
type Ordering = Ordering;
fn assign_round(
&mut self,
src: DotIncomplete<'a, I>,
round: Round,
) -> Ordering {
let prods = exact_prods(src.values);
let sum = Float::sum(prods.iter());
self.assign_round(sum, round)
}
}
impl<'a, I> Add<DotIncomplete<'a, I>> for Float
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
type Output = Self;
#[inline]
fn add(mut self, rhs: DotIncomplete<'a, I>) -> Self {
self.add_assign_round(rhs, Default::default());
self
}
}
impl<'a, I> AddAssign<DotIncomplete<'a, I>> for Float
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
#[inline]
fn add_assign(&mut self, rhs: DotIncomplete<'a, I>) {
self.add_assign_round(rhs, Default::default());
}
}
impl<'a, I> AddAssignRound<DotIncomplete<'a, I>> for Float
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
type Round = Round;
type Ordering = Ordering;
fn add_assign_round(
&mut self,
src: DotIncomplete<'a, I>,
round: Round,
) -> Ordering {
let prods = exact_prods(src.values);
let sum = Float::sum(prods.iter());
self.add_assign_round(sum, round)
}
}
ref_math_op0_float! {
xmpfr::ui_pow_ui; struct UPowUIncomplete { base: u32, exponent: u32 }
}
ref_math_op0_float! {
xmpfr::si_pow_ui; struct IPowUIncomplete { base: i32, exponent: u32 }
}
ref_math_op1_float! { xmpfr::sqr; struct SquareIncomplete {} }
ref_math_op1_float! { xmpfr::sqrt; struct SqrtIncomplete {} }
ref_math_op0_float! { xmpfr::sqrt_ui; struct SqrtUIncomplete { u: u32 } }
ref_math_op1_float! { xmpfr::rec_sqrt; struct RecipSqrtIncomplete {} }
ref_math_op1_float! { xmpfr::cbrt; struct CbrtIncomplete {} }
ref_math_op1_float! { xmpfr::rootn_ui; struct RootIncomplete { k: u32 } }
ref_math_op1_float! { xmpfr::abs; struct AbsIncomplete {} }
ref_math_op1_float! { xmpfr::signum; struct SignumIncomplete {} }
ref_math_op2_float! { xmpfr::copysign; struct CopysignIncomplete { y } }
#[derive(Debug)]
pub struct ClampIncomplete<'a, Min, Max>
where
Float: PartialOrd<Min>
+ PartialOrd<Max>
+ AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ AssignRound<&'a Max, Round = Round, Ordering = Ordering>,
{
ref_self: &'a Float,
min: &'a Min,
max: &'a Max,
}
impl<'a, Min, Max> AssignRound<ClampIncomplete<'a, Min, Max>> for Float
where
Self: PartialOrd<Min>
+ PartialOrd<Max>
+ AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ AssignRound<&'a Max, Round = Round, Ordering = Ordering>,
{
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(
&mut self,
src: ClampIncomplete<'a, Min, Max>,
round: Round,
) -> Ordering {
if src.ref_self.lt(src.min) {
let dir = self.assign_round(src.min, round);
if (*self).gt(src.max) {
let dir2 = self.assign_round(src.max, round);
assert!(
dir == dir2 && !(*self).lt(src.min),
"minimum larger than maximum"
);
dir
} else {
dir
}
} else if src.ref_self.gt(src.max) {
let dir = self.assign_round(src.max, round);
if (*self).lt(src.min) {
let dir2 = self.assign_round(src.min, round);
assert!(
dir == dir2 && !(*self).gt(src.max),
"minimum larger than maximum"
);
dir
} else {
dir
}
} else {
self.assign_round(src.ref_self, round)
}
}
}
ref_math_op1_float! { xmpfr::recip; struct RecipIncomplete {} }
ref_math_op2_float! { xmpfr::min; struct MinIncomplete { other } }
ref_math_op2_float! { xmpfr::max; struct MaxIncomplete { other } }
ref_math_op2_float! { xmpfr::dim; struct PositiveDiffIncomplete { other } }
ref_math_op1_float! { xmpfr::log; struct LnIncomplete {} }
ref_math_op0_float! { xmpfr::log_ui; struct LnUIncomplete { u: u32 } }
ref_math_op1_float! { xmpfr::log2; struct Log2Incomplete {} }
ref_math_op1_float! { xmpfr::log10; struct Log10Incomplete {} }
ref_math_op1_float! { xmpfr::exp; struct ExpIncomplete {} }
ref_math_op1_float! { xmpfr::exp2; struct Exp2Incomplete {} }
ref_math_op1_float! { xmpfr::exp10; struct Exp10Incomplete {} }
ref_math_op1_float! { xmpfr::sin; struct SinIncomplete {} }
ref_math_op1_float! { xmpfr::cos; struct CosIncomplete {} }
ref_math_op1_float! { xmpfr::tan; struct TanIncomplete {} }
ref_math_op1_2_float! { xmpfr::sin_cos; struct SinCosIncomplete {} }
ref_math_op1_float! { xmpfr::sec; struct SecIncomplete {} }
ref_math_op1_float! { xmpfr::csc; struct CscIncomplete {} }
ref_math_op1_float! { xmpfr::cot; struct CotIncomplete {} }
ref_math_op1_float! { xmpfr::acos; struct AcosIncomplete {} }
ref_math_op1_float! { xmpfr::asin; struct AsinIncomplete {} }
ref_math_op1_float! { xmpfr::atan; struct AtanIncomplete {} }
ref_math_op2_float! { xmpfr::atan2; struct Atan2Incomplete { x } }
ref_math_op1_float! { xmpfr::cosh; struct CoshIncomplete {} }
ref_math_op1_float! { xmpfr::sinh; struct SinhIncomplete {} }
ref_math_op1_float! { xmpfr::tanh; struct TanhIncomplete {} }
ref_math_op1_2_float! { xmpfr::sinh_cosh; struct SinhCoshIncomplete {} }
ref_math_op1_float! { xmpfr::sech; struct SechIncomplete {} }
ref_math_op1_float! { xmpfr::csch; struct CschIncomplete {} }
ref_math_op1_float! { xmpfr::coth; struct CothIncomplete {} }
ref_math_op1_float! { xmpfr::acosh; struct AcoshIncomplete {} }
ref_math_op1_float! { xmpfr::asinh; struct AsinhIncomplete {} }
ref_math_op1_float! { xmpfr::atanh; struct AtanhIncomplete {} }
ref_math_op0_float! { xmpfr::fac_ui; struct FactorialIncomplete { n: u32 } }
ref_math_op1_float! { xmpfr::log1p; struct Ln1pIncomplete {} }
ref_math_op1_float! { xmpfr::expm1; struct ExpM1Incomplete {} }
ref_math_op1_float! { xmpfr::eint; struct EintIncomplete {} }
ref_math_op1_float! { xmpfr::li2; struct Li2Incomplete {} }
ref_math_op1_float! { xmpfr::gamma; struct GammaIncomplete {} }
ref_math_op2_float! { xmpfr::gamma_inc; struct GammaIncIncomplete { x } }
ref_math_op1_float! { xmpfr::lngamma; struct LnGammaIncomplete {} }
pub struct LnAbsGammaIncomplete<'a> {
ref_self: &'a Float,
}
impl AssignRound<LnAbsGammaIncomplete<'_>> for (&mut Float, &mut Ordering) {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(
&mut self,
src: LnAbsGammaIncomplete<'_>,
round: Round,
) -> Ordering {
let mut sign: c_int = 0;
let sign_ptr: *mut c_int = &mut sign;
let ret = unsafe {
mpfr::lgamma(
self.0.as_raw_mut(),
sign_ptr,
src.ref_self.as_raw(),
raw_round(round),
)
};
*self.1 = if sign < 0 { Ordering::Less } else { Ordering::Greater };
ordering1(ret)
}
}
impl AssignRound<LnAbsGammaIncomplete<'_>> for (Float, Ordering) {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(
&mut self,
src: LnAbsGammaIncomplete<'_>,
round: Round,
) -> Ordering {
(&mut self.0, &mut self.1).assign_round(src, round)
}
}
impl Assign<LnAbsGammaIncomplete<'_>> for (&mut Float, &mut Ordering) {
#[inline]
fn assign(&mut self, src: LnAbsGammaIncomplete<'_>) {
self.assign_round(src, Default::default());
}
}
impl Assign<LnAbsGammaIncomplete<'_>> for (Float, Ordering) {
#[inline]
fn assign(&mut self, src: LnAbsGammaIncomplete<'_>) {
(&mut self.0, &mut self.1).assign_round(src, Default::default());
}
}
ref_math_op1_float! { xmpfr::digamma; struct DigammaIncomplete {} }
ref_math_op1_float! { xmpfr::zeta; struct ZetaIncomplete {} }
ref_math_op0_float! { xmpfr::zeta_ui; struct ZetaUIncomplete { u: u32 } }
ref_math_op1_float! { xmpfr::erf; struct ErfIncomplete {} }
ref_math_op1_float! { xmpfr::erfc; struct ErfcIncomplete {} }
ref_math_op1_float! { xmpfr::j0; struct J0Incomplete {} }
ref_math_op1_float! { xmpfr::j1; struct J1Incomplete {} }
ref_math_op1_float! { xmpfr::jn; struct JnIncomplete { n: i32 } }
ref_math_op1_float! { xmpfr::y0; struct Y0Incomplete {} }
ref_math_op1_float! { xmpfr::y1; struct Y1Incomplete {} }
ref_math_op1_float! { xmpfr::yn; struct YnIncomplete { n: i32 } }
ref_math_op2_float! { xmpfr::agm; struct AgmIncomplete { other } }
ref_math_op2_float! { xmpfr::hypot; struct HypotIncomplete { other } }
ref_math_op1_float! { xmpfr::ai; struct AiIncomplete {} }
ref_math_op1_float! { xmpfr::rint_ceil; struct CeilIncomplete {} }
ref_math_op1_float! { xmpfr::rint_floor; struct FloorIncomplete {} }
ref_math_op1_float! { xmpfr::rint_round; struct RoundIncomplete {} }
ref_math_op1_float! { xmpfr::rint_roundeven; struct RoundEvenIncomplete {} }
ref_math_op1_float! { xmpfr::rint_trunc; struct TruncIncomplete {} }
ref_math_op1_float! { xmpfr::frac; struct FractIncomplete {} }
ref_math_op1_2_float! { xmpfr::modf; struct TruncFractIncomplete {} }
#[cfg(feature = "rand")]
pub struct RandomBitsIncomplete<'a, 'b>
where
'b: 'a,
{
rng: &'a mut RandState<'b>,
}
#[cfg(feature = "rand")]
impl Assign<RandomBitsIncomplete<'_, '_>> for Float {
#[inline]
fn assign(&mut self, src: RandomBitsIncomplete<'_, '_>) {
unsafe {
let err = mpfr::urandomb(self.as_raw_mut(), src.rng.as_raw_mut());
assert_eq!(self.is_nan(), err != 0);
}
}
}
#[cfg(feature = "rand")]
pub struct RandomCont<'a, 'b>
where
'b: 'a,
{
rng: &'a mut RandState<'b>,
}
#[cfg(feature = "rand")]
impl AssignRound<RandomCont<'_, '_>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(
&mut self,
src: RandomCont<'_, '_>,
round: Round,
) -> Ordering {
let ret = unsafe {
mpfr::urandom(
self.as_raw_mut(),
src.rng.as_raw_mut(),
raw_round(round),
)
};
ordering1(ret)
}
}
#[cfg(feature = "rand")]
pub struct RandomNormal<'a, 'b>
where
'b: 'a,
{
rng: &'a mut RandState<'b>,
}
#[cfg(feature = "rand")]
impl AssignRound<RandomNormal<'_, '_>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(
&mut self,
src: RandomNormal<'_, '_>,
round: Round,
) -> Ordering {
let ret = unsafe {
mpfr::nrandom(
self.as_raw_mut(),
src.rng.as_raw_mut(),
raw_round(round),
)
};
ordering1(ret)
}
}
#[cfg(feature = "rand")]
pub struct RandomExp<'a, 'b>
where
'b: 'a,
{
rng: &'a mut RandState<'b>,
}
#[cfg(feature = "rand")]
impl AssignRound<RandomExp<'_, '_>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(
&mut self,
src: RandomExp<'_, '_>,
round: Round,
) -> Ordering {
let ret = unsafe {
mpfr::erandom(
self.as_raw_mut(),
src.rng.as_raw_mut(),
raw_round(round),
)
};
ordering1(ret)
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct BorrowFloat<'a> {
inner: mpfr_t,
phantom: PhantomData<&'a Float>,
}
impl Deref for BorrowFloat<'_> {
type Target = Float;
#[inline]
fn deref(&self) -> &Float {
let ptr = cast_ptr!(&self.inner, Float);
unsafe { &*ptr }
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum ExpFormat {
Exp,
Point,
ExpOrPoint,
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct Format {
pub radix: i32,
pub precision: Option<usize>,
pub round: Round,
pub to_upper: bool,
pub exp: ExpFormat,
}
impl Default for Format {
fn default() -> Format {
Format {
radix: 10,
precision: None,
round: Round::default(),
to_upper: false,
exp: ExpFormat::ExpOrPoint,
}
}
}
pub(crate) fn append_to_string(s: &mut String, f: &Float, format: Format) {
use std::fmt::Write;
if f.is_zero() {
s.push_str(if f.is_sign_negative() { "-0.0" } else { "0.0" });
return;
}
if f.is_infinite() {
s.push_str(match (format.radix > 10, f.is_sign_negative()) {
(false, false) => "inf",
(false, true) => "-inf",
(true, false) => "@inf@",
(true, true) => "-@inf@",
});
return;
}
if f.is_nan() {
s.push_str(match (format.radix > 10, f.is_sign_negative()) {
(false, false) => "NaN",
(false, true) => "-NaN",
(true, false) => "@NaN@",
(true, true) => "-@NaN@",
});
return;
}
let digits =
format.precision.map(|x| if x == 1 { 2 } else { x }).unwrap_or(0);
let mut exp: mpfr::exp_t;
let c_buf;
let negative;
let slice;
unsafe {
exp = mem::uninitialized();
c_buf = mpfr::get_str(
ptr::null_mut(),
&mut exp,
cast(format.radix),
digits,
f.as_raw(),
raw_round(format.round),
);
let c_str = CStr::from_ptr(c_buf);
let c_bytes = c_str.to_bytes();
negative = c_bytes[0] == b'-';
let bytes = if negative { &c_bytes[1..] } else { c_bytes };
slice = str::from_utf8(bytes).expect("mpfr string not utf-8");
}
if negative {
s.push('-');
}
let digits_start = s.len();
s.push_str(&slice[0..1]);
s.push('.');
s.push_str(&slice[1..]);
if format.to_upper {
s[digits_start..].make_ascii_uppercase();
}
exp = exp.checked_sub(1).expect("overflow");
if exp != 0 {
s.push(if format.radix > 10 {
'@'
} else if format.to_upper {
'E'
} else {
'e'
});
write!(s, "{}", exp).unwrap();
}
}
#[derive(Debug)]
pub enum ParseIncomplete {
CString { c_string: CString, radix: i32 },
Special(Special),
NegNan,
}
impl AssignRound<ParseIncomplete> for Float {
type Round = Round;
type Ordering = Ordering;
fn assign_round(&mut self, src: ParseIncomplete, round: Round) -> Ordering {
let (c_string, radix) = match src {
ParseIncomplete::CString { c_string, radix } => (c_string, radix),
ParseIncomplete::Special(special) => {
self.assign(special);
return Ordering::Equal;
}
ParseIncomplete::NegNan => {
self.assign(Special::Nan);
self.neg_assign();
return Ordering::Equal;
}
};
let mut c_str_end: *const c_char = ptr::null();
let ret = unsafe {
mpfr::strtofr(
self.as_raw_mut(),
c_string.as_ptr(),
cast_ptr_mut!(&mut c_str_end, *mut c_char),
cast(radix),
raw_round(round),
)
};
let nul =
cast_ptr!(c_string.as_bytes_with_nul().last().unwrap(), c_char);
assert_eq!(c_str_end, nul);
ordering1(ret)
}
}
macro_rules! parse_error {
($kind:expr) => {
Err(ParseFloatError { kind: $kind })
};
}
fn parse(
mut bytes: &[u8],
radix: i32,
) -> Result<ParseIncomplete, ParseFloatError> {
assert!(radix >= 2 && radix <= 36, "radix out of range");
let bradix: u8 = cast(radix);
let small_bound = b'a' - 10 + bradix;
let capital_bound = b'A' - 10 + bradix;
let digit_bound = b'0' + bradix;
bytes = misc::trim_start(bytes);
bytes = misc::trim_end(bytes);
if bytes.is_empty() {
parse_error!(ParseErrorKind::NoDigits)?;
}
let mut has_sign = false;
let mut has_minus = false;
if bytes[0] == b'+' || bytes[0] == b'-' {
has_sign = true;
has_minus = bytes[0] == b'-';
bytes = misc::trim_start(&bytes[1..]);
if bytes.is_empty() {
parse_error!(ParseErrorKind::NoDigits)?;
}
}
if let Some(special) = parse_special(bytes, radix, has_minus) {
return special;
}
let mut v = Vec::with_capacity(bytes.len() + 2);
if has_minus {
v.push(b'-');
}
let mut has_digits = false;
let mut has_point = false;
let mut exp = false;
for &b in bytes {
let b = if radix <= 10 && (b == b'e' || b == b'E') { b'@' } else { b };
let valid_digit = match b {
b'.' if exp => parse_error!(ParseErrorKind::PointInExp)?,
b'.' if has_point => parse_error!(ParseErrorKind::TooManyPoints)?,
b'.' => {
v.push(b'.');
has_point = true;
continue;
}
b'@' if exp => parse_error!(ParseErrorKind::TooManyExp)?,
b'@' if !has_digits => {
parse_error!(ParseErrorKind::SignifNoDigits)?
}
b'@' => {
v.push(b'@');
exp = true;
has_sign = false;
has_digits = false;
continue;
}
b'+' if exp && !has_sign && !has_digits => {
has_sign = true;
continue;
}
b'-' if exp && !has_sign && !has_digits => {
v.push(b'-');
has_sign = true;
continue;
}
b'_' if has_digits => continue,
b' ' | b'\t' | b'\n' | 0x0b | 0x0c | 0x0d => continue,
b'0'..=b'9' => exp || b < digit_bound,
b'a'..=b'z' => !exp && b < small_bound,
b'A'..=b'Z' => !exp && b < capital_bound,
_ => false,
};
if !valid_digit {
parse_error!(ParseErrorKind::InvalidDigit)?;
}
v.push(b);
has_digits = true;
}
if !has_digits {
if exp {
parse_error!(ParseErrorKind::ExpNoDigits)?;
} else {
parse_error!(ParseErrorKind::NoDigits)?;
}
}
let c_string = unsafe { CString::from_vec_unchecked(v) };
Ok(ParseIncomplete::CString { c_string, radix })
}
fn parse_special(
bytes: &[u8],
radix: i32,
negative: bool,
) -> Option<Result<ParseIncomplete, ParseFloatError>> {
let small = if radix <= 10 { Some(()) } else { None };
let inf10: &[&[u8]] = &[b"inf", b"infinity"];
let inf: &[&[u8]] = &[b"@inf@", b"@infinity@"];
if let Some(after_inf) = small
.and_then(|()| misc::skip_lcase_match(bytes, inf10))
.or_else(|| misc::skip_lcase_match(bytes, inf))
.map(misc::trim_start)
{
if !after_inf.is_empty() {
return Some(parse_error!(ParseErrorKind::InvalidDigit));
}
return if negative {
Some(Ok(ParseIncomplete::Special(Special::NegInfinity)))
} else {
Some(Ok(ParseIncomplete::Special(Special::Infinity)))
};
}
let nan10: &[&[u8]] = &[b"nan", b"+nan"];
let nan: &[&[u8]] = &[b"@nan@", b"+@nan@"];
if let Some(after_nan) = small
.and_then(|()| misc::skip_lcase_match(bytes, nan10))
.or_else(|| misc::skip_lcase_match(bytes, nan))
.map(misc::trim_start)
{
let trailing = if let Some(after_extra) =
skip_nan_extra(after_nan).map(misc::trim_start)
{
after_extra
} else {
after_nan
};
if !trailing.is_empty() {
return Some(parse_error!(ParseErrorKind::InvalidDigit));
}
return if negative {
Some(Ok(ParseIncomplete::NegNan))
} else {
Some(Ok(ParseIncomplete::Special(Special::Nan)))
};
}
None
}
fn skip_nan_extra(bytes: &[u8]) -> Option<&[u8]> {
let mut iter = bytes.iter().enumerate();
match iter.next() {
Some((_, &b'(')) => {}
_ => return None,
}
for (i, &b) in iter {
match b {
b')' => return Some(&bytes[i + 1..]),
b'0'..=b'9'
| b'a'..=b'z'
| b'A'..=b'Z'
| b'_'
| b' '
| b'\t'
| b'\n'
| 0x0b
| 0x0c
| 0x0d => {}
_ => return None,
}
}
None
}
#[derive(Debug)]
pub struct ParseFloatError {
kind: ParseErrorKind,
}
#[derive(Debug)]
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 ieee_storage_bits_for_prec(prec: u32) -> Option<u32> {
match prec {
11 => return Some(16),
24 => return Some(32),
53 => return Some(64),
_ => {}
}
if prec < 113 {
return None;
}
let estimate = prec - 4 * prec.leading_zeros() + 113;
let k = (estimate + 16) & !31;
let p = k - cast::<_, u32>((f64::from(k).log2() * 4.0).round()) + 13;
if p == prec {
Some(k)
} else {
None
}
}