#[cfg(feature = "rand")]
use crate::rand::MutRandState;
#[cfg(feature = "rational")]
use crate::Rational;
use crate::{
ext::xmpfr::{self, ordering1, raw_round},
float::{
self,
arith::{AddMulIncomplete, MulAddMulIncomplete, MulSubMulIncomplete, SubMulFromIncomplete},
OrdFloat, Round, SmallFloat, Special,
},
misc::{self, UnwrappedAs, UnwrappedCast},
ops::{AddAssignRound, AssignRound, DivRounding, NegAssign},
Assign,
};
use az::{Az, CheckedCast, SaturatingCast, WrappingAs};
use core::{
cmp::Ordering,
fmt::{Display, Formatter, Result as FmtResult},
i32,
marker::PhantomData,
mem::{ManuallyDrop, MaybeUninit},
num::FpCategory,
ops::{Add, AddAssign, Deref},
slice, str, u32,
};
use gmp_mpfr_sys::{
gmp::{self, limb_t},
mpfr::{self, exp_t, mpfr_t},
};
use libc::c_char;
use std::{
error::Error,
ffi::{CStr, CString},
};
#[cfg(feature = "complex")]
use {crate::complex::big::BorrowComplex, gmp_mpfr_sys::mpc::mpc_t};
#[cfg(feature = "integer")]
use {
crate::{integer::big::BorrowInteger, Integer},
gmp_mpfr_sys::{gmp::mpz_t, mpfr::prec_t},
};
#[repr(transparent)]
pub struct Float {
inner: mpfr_t,
}
impl Float {
#[inline]
pub(crate) fn inner(&self) -> &mpfr_t {
&self.inner
}
#[inline]
pub(crate) unsafe fn inner_mut(&mut self) -> &mut mpfr_t {
&mut self.inner
}
#[inline]
pub(crate) fn inner_data(&self) -> &[limb_t] {
if self.is_normal() {
let prec = self.inner.prec.unwrapped_as::<usize>();
let limbs = prec.div_ceil(gmp::LIMB_BITS.az::<usize>());
unsafe { slice::from_raw_parts(self.inner.d, limbs) }
} else {
&[]
}
}
}
static_assert_same_layout!(Float, mpfr_t);
static_assert_same_layout!(BorrowFloat<'_>, mpfr_t);
macro_rules! ref_math_op0_float {
($($rest:tt)*) => {
ref_math_op0_round! {
Float, Round, Round::Nearest, Ordering;
$($rest)*
}
};
}
macro_rules! ref_math_op1_float {
($($rest:tt)*) => {
ref_math_op1_round! {
Float, Round, Round::Nearest, Ordering;
$($rest)*
}
};
}
macro_rules! ref_math_op1_2_float {
($($rest:tt)*) => {
ref_math_op1_2_round! {
Float, Round, Round::Nearest, (Ordering, Ordering);
$($rest)*
}
};
}
macro_rules! ref_math_op2_float {
($($rest:tt)*) => {
ref_math_op2_round! {
Float, Round, Round::Nearest, Ordering;
$($rest)*
}
};
}
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]
pub(crate) fn new_nan(prec: u32) -> Self {
assert!(
prec >= float::prec_min() && prec <= float::prec_max(),
"precision out of range"
);
let mut ret = MaybeUninit::uninit();
xmpfr::write_new_nan(&mut ret, prec.unwrapped_cast());
unsafe { ret.assume_init() }
}
#[inline]
pub fn prec(&self) -> u32 {
xmpfr::get_prec(self).unwrapped_cast()
}
#[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"
);
xmpfr::prec_round(self, prec.unwrapped_cast(), round)
}
#[inline]
pub unsafe fn from_raw(raw: mpfr_t) -> Self {
Float { inner: raw }
}
#[inline]
pub fn into_raw(self) -> mpfr_t {
let m = ManuallyDrop::new(self);
m.inner
}
#[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
}
#[inline]
pub fn parse<S: AsRef<[u8]>>(src: S) -> Result<ParseIncomplete, ParseFloatError> {
parse(src.as_ref(), 10)
}
#[inline]
pub fn parse_radix<S: AsRef<[u8]>>(
src: S,
radix: i32,
) -> Result<ParseIncomplete, ParseFloatError> {
parse(src.as_ref(), radix)
}
#[cfg(feature = "integer")]
#[inline]
pub fn to_integer(&self) -> Option<Integer> {
self.checked_cast()
}
#[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, exp.unwrapped_cast()))
}
#[cfg(feature = "rational")]
#[inline]
pub fn to_rational(&self) -> Option<Rational> {
self.checked_cast()
}
#[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() {
None
} else {
Some(xmpfr::get_si(self, round).saturating_cast())
}
}
#[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() {
None
} else {
Some(xmpfr::get_ui(self, round).saturating_cast())
}
}
#[inline]
pub fn to_f32(&self) -> f32 {
self.to_f32_round(Round::Nearest)
}
#[inline]
pub fn to_f32_round(&self, round: Round) -> f32 {
xmpfr::get_f32(self, round)
}
#[inline]
pub fn to_f64(&self) -> f64 {
self.to_f64_round(Round::Nearest)
}
#[inline]
pub fn to_f64_round(&self, round: Round) -> f64 {
xmpfr::get_f64(self, 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 mut sf = SmallFloat::from(0.0f32);
assert_eq!(sf.prec(), 24);
unsafe {
xmpfr::set(sf.as_nonreallocating_float(), self, round);
}
let (f, exp) = xmpfr::get_f64_2exp(&*sf, Round::Zero);
(f as f32, exp.unwrapped_cast())
}
#[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 (f, exp) = xmpfr::get_f64_2exp(self, round);
(f, exp.unwrapped_cast())
}
#[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 {
let mut s = String::new();
let format = Format {
radix,
precision: num_digits,
round,
..Format::default()
};
append_to_string(&mut s, self, format);
s
}
#[inline]
pub fn to_sign_string_exp(
&self,
radix: i32,
num_digits: Option<usize>,
) -> (bool, String, Option<i32>) {
self.to_sign_string_exp_round(radix, num_digits, Round::Nearest)
}
pub fn to_sign_string_exp_round(
&self,
radix: i32,
num_digits: Option<usize>,
round: Round,
) -> (bool, String, Option<i32>) {
assert!(radix >= 2 && radix <= 36, "radix {} out of range", radix);
let sign = self.is_sign_negative();
if self.is_zero() {
return (sign, String::from("0"), None);
}
if self.is_infinite() {
let s = String::from(if radix > 10 { "@inf@" } else { "inf" });
return (sign, s, None);
}
if self.is_nan() {
let s = String::from(if radix > 10 { "@NaN@" } else { "NaN" });
return (sign, s, None);
}
let neg_self;
let (f, round) = if sign {
neg_self = self.as_neg();
let reverse_round = match round {
Round::Up => Round::Down,
Round::Down => Round::Up,
unchanged => unchanged,
};
(&*neg_self, reverse_round)
} else {
(self, round)
};
let format = Format {
radix,
precision: num_digits,
round,
..Format::default()
};
let size = req_digits(f, format) + 1;
let mut s = String::with_capacity(size);
let digits = format
.precision
.map(|x| if x == 1 { 2 } else { x })
.unwrap_or(0);
let exp: exp_t;
unsafe {
let vec = s.as_mut_vec();
let write_ptr = vec.as_mut_ptr();
let mut maybe_exp = MaybeUninit::uninit();
let c_buf = mpfr::get_str(
write_ptr as *mut c_char,
maybe_exp.as_mut_ptr(),
format.radix.unwrapped_cast(),
digits,
f.as_raw(),
raw_round(format.round),
);
assert_eq!(c_buf, write_ptr as *mut c_char);
exp = maybe_exp.assume_init();
let c_len = CStr::from_ptr(write_ptr as *mut c_char).to_bytes().len();
assert!(c_len < size, "buffer overflow");
vec.set_len(c_len);
}
let exp = exp.unwrapped_cast();
(sign, s, Some(exp))
}
pub fn as_neg(&self) -> BorrowFloat<'_> {
let mut raw = self.inner;
raw.sign = -raw.sign;
if self.is_nan() {
xmpfr::set_nanflag();
}
unsafe { BorrowFloat::from_raw(raw) }
}
pub fn as_abs(&self) -> BorrowFloat<'_> {
let mut raw = self.inner;
raw.sign = 1;
if self.is_nan() {
xmpfr::set_nanflag();
}
unsafe { BorrowFloat::from_raw(raw) }
}
#[inline]
pub fn as_ord(&self) -> &OrdFloat {
unsafe { &*cast_ptr!(self, OrdFloat) }
}
#[cfg(feature = "complex")]
pub fn as_complex(&self) -> BorrowComplex<'_> {
let raw_complex = mpc_t {
re: self.inner,
im: mpfr_t {
prec: self.inner.prec,
sign: 1,
exp: xmpfr::EXP_ZERO,
d: self.inner.d,
},
};
unsafe { BorrowComplex::from_raw(raw_complex) }
}
#[inline]
pub fn is_integer(&self) -> bool {
xmpfr::integer_p(self)
}
#[inline]
pub fn is_nan(&self) -> bool {
xmpfr::nan_p(self)
}
#[inline]
pub fn is_infinite(&self) -> bool {
xmpfr::inf_p(self)
}
#[inline]
pub fn is_finite(&self) -> bool {
xmpfr::number_p(self)
}
#[inline]
pub fn is_zero(&self) -> bool {
xmpfr::zero_p(self)
}
#[inline]
pub fn is_normal(&self) -> bool {
xmpfr::regular_p(self)
}
#[inline]
pub fn classify(&self) -> FpCategory {
if xmpfr::nan_p(self) {
FpCategory::Nan
} else if xmpfr::inf_p(self) {
FpCategory::Infinite
} else if xmpfr::zero_p(self) {
FpCategory::Zero
} else {
FpCategory::Normal
}
}
#[inline]
pub fn cmp0(&self) -> Option<Ordering> {
if self.is_nan() {
None
} else {
Some(xmpfr::sgn(self))
}
}
#[inline]
pub fn cmp_abs(&self, other: &Self) -> Option<Ordering> {
if xmpfr::unordered_p(self, other) {
None
} else {
Some(xmpfr::cmpabs(self, other))
}
}
#[inline]
pub fn get_exp(&self) -> Option<i32> {
if self.is_normal() {
Some(xmpfr::get_exp(self).unwrapped_cast())
} else {
None
}
}
pub fn clamp_exp(
&mut self,
dir: Ordering,
round: Round,
exp_min: i32,
exp_max: i32,
) -> Option<Ordering> {
unsafe {
let save_emin = mpfr::get_emin();
if mpfr::set_emin(exp_min.checked_cast()?) != 0 {
return None;
}
let save_emax = mpfr::get_emax();
if exp_max
.checked_cast()
.map(|x| mpfr::set_emax(x) != 0)
.unwrap_or(true)
{
mpfr::set_emin(save_emin);
return None;
}
let dir = xmpfr::check_range(self, dir, round);
mpfr::set_emax(save_emax);
mpfr::set_emin(save_emin);
Some(dir)
}
}
#[cfg(feature = "integer")]
#[inline]
pub fn get_significand(&self) -> Option<BorrowInteger<'_>> {
if self.is_normal() {
let limb_bits = prec_t::from(gmp::LIMB_BITS);
let limbs = (self.inner.prec - 1) / limb_bits + 1;
let raw_int = mpz_t {
alloc: limbs.unwrapped_cast(),
size: limbs.unwrapped_cast(),
d: self.inner.d,
};
Some(unsafe { BorrowInteger::from_raw(raw_int) })
} else {
None
}
}
#[inline]
pub fn is_sign_positive(&self) -> bool {
!self.is_sign_negative()
}
#[inline]
pub fn is_sign_negative(&self) -> bool {
xmpfr::signbit(self)
}
#[inline]
pub fn next_toward(&mut self, to: &Self) {
xmpfr::nexttoward(self, to);
}
#[inline]
pub fn next_up(&mut self) {
xmpfr::nextabove(self);
}
#[inline]
pub fn next_down(&mut self) {
xmpfr::nextbelow(self);
}
#[inline]
pub fn subnormalize_ieee(&mut self) -> &mut Self {
self.subnormalize_ieee_round(Ordering::Equal, Round::Nearest);
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, Round::Nearest);
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 = exp_t::from(normal_exp_min);
let sub_exp_min = exp_min
.checked_sub((self.prec() - 1).unwrapped_as::<exp_t>())
.expect("overflow");
let exp = xmpfr::get_exp(self);
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 }
}
#[inline]
pub fn remainder(mut self, divisor: &Self) -> Self {
self.remainder_round(divisor, Round::Nearest);
self
}
#[inline]
pub fn remainder_mut(&mut self, divisor: &Self) {
self.remainder_round(divisor, Round::Nearest);
}
#[inline]
pub fn remainder_round(&mut self, divisor: &Self, round: Round) -> Ordering {
xmpfr::remainder(self, (), divisor, round)
}
#[inline]
pub fn remainder_from(&mut self, dividend: &Self) {
self.remainder_from_round(dividend, Round::Nearest);
}
#[inline]
pub fn remainder_from_round(&mut self, dividend: &Self, round: Round) -> Ordering {
xmpfr::remainder(self, dividend, (), round)
}
#[inline]
pub fn remainder_ref<'a>(&'a self, divisor: &'a Self) -> RemainderIncomplete<'_> {
RemainderIncomplete {
ref_self: self,
divisor,
}
}
#[inline]
pub fn mul_add(mut self, mul: &Self, add: &Self) -> Self {
self.mul_add_round(mul, add, Round::Nearest);
self
}
#[inline]
pub fn mul_add_mut(&mut self, mul: &Self, add: &Self) {
self.mul_add_round(mul, add, Round::Nearest);
}
#[inline]
pub fn mul_add_round(&mut self, mul: &Self, add: &Self, round: Round) -> Ordering {
xmpfr::fma(self, (), mul, add, round)
}
#[inline]
pub fn mul_add_ref<'a>(&'a self, mul: &'a Self, add: &'a Self) -> AddMulIncomplete<'a> {
self * mul + add
}
#[inline]
pub fn mul_sub(mut self, mul: &Self, sub: &Self) -> Self {
self.mul_sub_round(mul, sub, Round::Nearest);
self
}
#[inline]
pub fn mul_sub_mut(&mut self, mul: &Self, sub: &Self) {
self.mul_sub_round(mul, sub, Round::Nearest);
}
#[inline]
pub fn mul_sub_round(&mut self, mul: &Self, sub: &Self, round: Round) -> Ordering {
xmpfr::fms(self, (), mul, sub, round)
}
#[inline]
pub fn mul_sub_ref<'a>(&'a self, mul: &'a Self, sub: &'a Self) -> SubMulFromIncomplete<'a> {
self * mul - sub
}
#[inline]
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, Round::Nearest);
self
}
#[inline]
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, Round::Nearest);
}
#[inline]
pub fn mul_add_mul_round(
&mut self,
mul: &Self,
add_mul1: &Self,
add_mul2: &Self,
round: Round,
) -> Ordering {
xmpfr::fmma(self, (), mul, add_mul1, add_mul2, round)
}
#[inline]
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
}
#[inline]
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, Round::Nearest);
self
}
#[inline]
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, Round::Nearest);
}
#[inline]
pub fn mul_sub_mul_round(
&mut self,
mul: &Self,
sub_mul1: &Self,
sub_mul2: &Self,
round: Round,
) -> Ordering {
xmpfr::fmms(self, (), mul, sub_mul1, sub_mul2, round)
}
#[inline]
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
}
#[inline]
pub fn u_exp(u: u32, exp: i32) -> UExpIncomplete {
UExpIncomplete { u, exp }
}
#[inline]
pub fn i_exp(i: i32, exp: i32) -> IExpIncomplete {
IExpIncomplete { i, exp }
}
#[inline]
pub fn u_pow_u(base: u32, exponent: u32) -> UPowUIncomplete {
UPowUIncomplete { base, exponent }
}
#[inline]
pub fn i_pow_u(base: i32, exponent: u32) -> IPowUIncomplete {
IPowUIncomplete { base, exponent }
}
#[inline]
pub fn square(mut self) -> Self {
self.square_round(Round::Nearest);
self
}
#[inline]
pub fn square_mut(&mut self) {
self.square_round(Round::Nearest);
}
#[inline]
pub fn square_round(&mut self, round: Round) -> Ordering {
xmpfr::sqr(self, (), round)
}
#[inline]
pub fn square_ref(&self) -> SquareIncomplete<'_> {
SquareIncomplete { ref_self: self }
}
#[inline]
pub fn sqrt(mut self) -> Self {
self.sqrt_round(Round::Nearest);
self
}
#[inline]
pub fn sqrt_mut(&mut self) {
self.sqrt_round(Round::Nearest);
}
#[inline]
pub fn sqrt_round(&mut self, round: Round) -> Ordering {
xmpfr::sqrt(self, (), round)
}
#[inline]
pub fn sqrt_ref(&self) -> SqrtIncomplete<'_> {
SqrtIncomplete { ref_self: self }
}
#[inline]
pub fn sqrt_u(u: u32) -> SqrtUIncomplete {
SqrtUIncomplete { u }
}
#[inline]
pub fn recip_sqrt(mut self) -> Self {
self.recip_sqrt_round(Round::Nearest);
self
}
#[inline]
pub fn recip_sqrt_mut(&mut self) {
self.recip_sqrt_round(Round::Nearest);
}
#[inline]
pub fn recip_sqrt_round(&mut self, round: Round) -> Ordering {
xmpfr::rec_sqrt(self, (), round)
}
#[inline]
pub fn recip_sqrt_ref(&self) -> RecipSqrtIncomplete<'_> {
RecipSqrtIncomplete { ref_self: self }
}
#[inline]
pub fn cbrt(mut self) -> Self {
self.cbrt_round(Round::Nearest);
self
}
#[inline]
pub fn cbrt_mut(&mut self) {
self.cbrt_round(Round::Nearest);
}
#[inline]
pub fn cbrt_round(&mut self, round: Round) -> Ordering {
xmpfr::cbrt(self, (), round)
}
#[inline]
pub fn cbrt_ref(&self) -> CbrtIncomplete<'_> {
CbrtIncomplete { ref_self: self }
}
#[inline]
pub fn root(mut self, k: u32) -> Self {
self.root_round(k, Round::Nearest);
self
}
#[inline]
pub fn root_mut(&mut self, k: u32) {
self.root_round(k, Round::Nearest);
}
#[inline]
pub fn root_round(&mut self, k: u32, round: Round) -> Ordering {
xmpfr::rootn_ui(self, (), k, round)
}
#[inline]
pub fn root_ref(&self, k: u32) -> RootIncomplete<'_> {
RootIncomplete { ref_self: self, k }
}
#[inline]
pub fn abs(mut self) -> Self {
self.abs_mut();
self
}
#[inline]
pub fn abs_mut(&mut self) {
xmpfr::abs(self, (), Round::Nearest);
}
#[inline]
pub fn abs_ref(&self) -> AbsIncomplete<'_> {
AbsIncomplete { ref_self: self }
}
#[inline]
pub fn signum(mut self) -> Self {
self.signum_mut();
self
}
#[inline]
pub fn signum_mut(&mut self) {
xmpfr::signum(self, (), Round::Nearest);
}
#[inline]
pub fn signum_ref(&self) -> SignumIncomplete<'_> {
SignumIncomplete { ref_self: self }
}
#[inline]
pub fn copysign(mut self, y: &Self) -> Self {
self.copysign_mut(y);
self
}
#[inline]
pub fn copysign_mut(&mut self, y: &Self) {
xmpfr::copysign(self, (), y, Round::Nearest);
}
#[inline]
pub fn copysign_ref<'a>(&'a self, y: &'a Self) -> CopysignIncomplete<'_> {
CopysignIncomplete { ref_self: self, y }
}
#[inline]
pub fn clamp<Min, Max>(mut self, min: &Min, max: &Max) -> Self
where
Self: PartialOrd<Min>
+ PartialOrd<Max>
+ for<'a> AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ for<'a> AssignRound<&'a Max, Round = Round, Ordering = Ordering>,
{
self.clamp_round(min, max, Round::Nearest);
self
}
#[inline]
pub fn clamp_mut<Min, Max>(&mut self, min: &Min, max: &Max)
where
Self: PartialOrd<Min>
+ PartialOrd<Max>
+ for<'a> AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ for<'a> AssignRound<&'a Max, Round = Round, Ordering = Ordering>,
{
self.clamp_round(min, max, Round::Nearest);
}
pub fn clamp_round<Min, Max>(&mut self, min: &Min, max: &Max, round: Round) -> Ordering
where
Self: PartialOrd<Min>
+ PartialOrd<Max>
+ for<'a> AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ for<'a> AssignRound<&'a 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() {
xmpfr::set_nanflag();
}
Ordering::Equal
}
}
#[inline]
pub fn clamp_ref<'min, 'max, Min, Max>(
&self,
min: &'min Min,
max: &'max Max,
) -> ClampIncomplete<'_, 'min, 'max, Min, Max>
where
Self: PartialOrd<Min>
+ PartialOrd<Max>
+ for<'a> AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ for<'a> AssignRound<&'a Max, Round = Round, Ordering = Ordering>,
{
ClampIncomplete {
ref_self: self,
min,
max,
}
}
#[inline]
pub fn recip(mut self) -> Self {
self.recip_round(Round::Nearest);
self
}
#[inline]
pub fn recip_mut(&mut self) {
self.recip_round(Round::Nearest);
}
#[inline]
pub fn recip_round(&mut self, round: Round) -> Ordering {
xmpfr::recip(self, (), round)
}
#[inline]
pub fn recip_ref(&self) -> RecipIncomplete<'_> {
RecipIncomplete { ref_self: self }
}
#[inline]
pub fn min(mut self, other: &Self) -> Self {
self.min_round(other, Round::Nearest);
self
}
#[inline]
pub fn min_mut(&mut self, other: &Self) {
self.min_round(other, Round::Nearest);
}
#[inline]
pub fn min_round(&mut self, other: &Self, round: Round) -> Ordering {
xmpfr::min(self, (), other, round)
}
#[inline]
pub fn min_ref<'a>(&'a self, other: &'a Self) -> MinIncomplete<'_> {
MinIncomplete {
ref_self: self,
other,
}
}
#[inline]
pub fn max(mut self, other: &Self) -> Self {
self.max_round(other, Round::Nearest);
self
}
#[inline]
pub fn max_mut(&mut self, other: &Self) {
self.max_round(other, Round::Nearest);
}
#[inline]
pub fn max_round(&mut self, other: &Self, round: Round) -> Ordering {
xmpfr::max(self, (), other, round)
}
#[inline]
pub fn max_ref<'a>(&'a self, other: &'a Self) -> MaxIncomplete<'_> {
MaxIncomplete {
ref_self: self,
other,
}
}
#[inline]
pub fn positive_diff(mut self, other: &Self) -> Self {
self.positive_diff_round(other, Round::Nearest);
self
}
#[inline]
pub fn positive_diff_mut(&mut self, other: &Self) {
self.positive_diff_round(other, Round::Nearest);
}
#[inline]
pub fn positive_diff_round(&mut self, other: &Self, round: Round) -> Ordering {
xmpfr::dim(self, (), other, round)
}
#[inline]
pub fn positive_diff_ref<'a>(&'a self, other: &'a Self) -> PositiveDiffIncomplete<'_> {
PositiveDiffIncomplete {
ref_self: self,
other,
}
}
#[inline]
pub fn ln(mut self) -> Self {
self.ln_round(Round::Nearest);
self
}
#[inline]
pub fn ln_mut(&mut self) {
self.ln_round(Round::Nearest);
}
#[inline]
pub fn ln_round(&mut self, round: Round) -> Ordering {
xmpfr::log(self, (), round)
}
#[inline]
pub fn ln_ref(&self) -> LnIncomplete<'_> {
LnIncomplete { ref_self: self }
}
#[inline]
pub fn ln_u(u: u32) -> LnUIncomplete {
LnUIncomplete { u }
}
#[inline]
pub fn log2(mut self) -> Self {
self.log2_round(Round::Nearest);
self
}
#[inline]
pub fn log2_mut(&mut self) {
self.log2_round(Round::Nearest);
}
#[inline]
pub fn log2_round(&mut self, round: Round) -> Ordering {
xmpfr::log2(self, (), round)
}
#[inline]
pub fn log2_ref(&self) -> Log2Incomplete<'_> {
Log2Incomplete { ref_self: self }
}
#[inline]
pub fn log10(mut self) -> Self {
self.log10_round(Round::Nearest);
self
}
#[inline]
pub fn log10_mut(&mut self) {
self.log10_round(Round::Nearest);
}
#[inline]
pub fn log10_round(&mut self, round: Round) -> Ordering {
xmpfr::log10(self, (), round)
}
#[inline]
pub fn log10_ref(&self) -> Log10Incomplete<'_> {
Log10Incomplete { ref_self: self }
}
#[inline]
pub fn exp(mut self) -> Self {
self.exp_round(Round::Nearest);
self
}
#[inline]
pub fn exp_mut(&mut self) {
self.exp_round(Round::Nearest);
}
#[inline]
pub fn exp_round(&mut self, round: Round) -> Ordering {
xmpfr::exp(self, (), round)
}
#[inline]
pub fn exp_ref(&self) -> ExpIncomplete<'_> {
ExpIncomplete { ref_self: self }
}
#[inline]
pub fn exp2(mut self) -> Self {
self.exp2_round(Round::Nearest);
self
}
#[inline]
pub fn exp2_mut(&mut self) {
self.exp2_round(Round::Nearest);
}
#[inline]
pub fn exp2_round(&mut self, round: Round) -> Ordering {
xmpfr::exp2(self, (), round)
}
#[inline]
pub fn exp2_ref(&self) -> Exp2Incomplete<'_> {
Exp2Incomplete { ref_self: self }
}
#[inline]
pub fn exp10(mut self) -> Self {
self.exp10_round(Round::Nearest);
self
}
#[inline]
pub fn exp10_mut(&mut self) {
self.exp10_round(Round::Nearest);
}
#[inline]
pub fn exp10_round(&mut self, round: Round) -> Ordering {
xmpfr::exp10(self, (), round)
}
#[inline]
pub fn exp10_ref(&self) -> Exp10Incomplete<'_> {
Exp10Incomplete { ref_self: self }
}
#[inline]
pub fn sin(mut self) -> Self {
self.sin_round(Round::Nearest);
self
}
#[inline]
pub fn sin_mut(&mut self) {
self.sin_round(Round::Nearest);
}
#[inline]
pub fn sin_round(&mut self, round: Round) -> Ordering {
xmpfr::sin(self, (), round)
}
#[inline]
pub fn sin_ref(&self) -> SinIncomplete<'_> {
SinIncomplete { ref_self: self }
}
#[inline]
pub fn cos(mut self) -> Self {
self.cos_round(Round::Nearest);
self
}
#[inline]
pub fn cos_mut(&mut self) {
self.cos_round(Round::Nearest);
}
#[inline]
pub fn cos_round(&mut self, round: Round) -> Ordering {
xmpfr::cos(self, (), round)
}
#[inline]
pub fn cos_ref(&self) -> CosIncomplete<'_> {
CosIncomplete { ref_self: self }
}
#[inline]
pub fn tan(mut self) -> Self {
self.tan_round(Round::Nearest);
self
}
#[inline]
pub fn tan_mut(&mut self) {
self.tan_round(Round::Nearest);
}
#[inline]
pub fn tan_round(&mut self, round: Round) -> Ordering {
xmpfr::tan(self, (), round)
}
#[inline]
pub fn tan_ref(&self) -> TanIncomplete<'_> {
TanIncomplete { ref_self: self }
}
#[inline]
pub fn sin_cos(mut self, mut cos: Self) -> (Self, Self) {
self.sin_cos_round(&mut cos, Round::Nearest);
(self, cos)
}
#[inline]
pub fn sin_cos_mut(&mut self, cos: &mut Self) {
self.sin_cos_round(cos, Round::Nearest);
}
#[inline]
pub fn sin_cos_round(&mut self, cos: &mut Self, round: Round) -> (Ordering, Ordering) {
xmpfr::sin_cos(self, cos, (), round)
}
#[inline]
pub fn sin_cos_ref(&self) -> SinCosIncomplete<'_> {
SinCosIncomplete { ref_self: self }
}
#[inline]
pub fn sec(mut self) -> Self {
self.sec_round(Round::Nearest);
self
}
#[inline]
pub fn sec_mut(&mut self) {
self.sec_round(Round::Nearest);
}
#[inline]
pub fn sec_round(&mut self, round: Round) -> Ordering {
xmpfr::sec(self, (), round)
}
#[inline]
pub fn sec_ref(&self) -> SecIncomplete<'_> {
SecIncomplete { ref_self: self }
}
#[inline]
pub fn csc(mut self) -> Self {
self.csc_round(Round::Nearest);
self
}
#[inline]
pub fn csc_mut(&mut self) {
self.csc_round(Round::Nearest);
}
#[inline]
pub fn csc_round(&mut self, round: Round) -> Ordering {
xmpfr::csc(self, (), round)
}
#[inline]
pub fn csc_ref(&self) -> CscIncomplete<'_> {
CscIncomplete { ref_self: self }
}
#[inline]
pub fn cot(mut self) -> Self {
self.cot_round(Round::Nearest);
self
}
#[inline]
pub fn cot_mut(&mut self) {
self.cot_round(Round::Nearest);
}
#[inline]
pub fn cot_round(&mut self, round: Round) -> Ordering {
xmpfr::cot(self, (), round)
}
#[inline]
pub fn cot_ref(&self) -> CotIncomplete<'_> {
CotIncomplete { ref_self: self }
}
#[inline]
pub fn asin(mut self) -> Self {
self.asin_round(Round::Nearest);
self
}
#[inline]
pub fn asin_mut(&mut self) {
self.asin_round(Round::Nearest);
}
#[inline]
pub fn asin_round(&mut self, round: Round) -> Ordering {
xmpfr::asin(self, (), round)
}
#[inline]
pub fn asin_ref(&self) -> AsinIncomplete<'_> {
AsinIncomplete { ref_self: self }
}
#[inline]
pub fn acos(mut self) -> Self {
self.acos_round(Round::Nearest);
self
}
#[inline]
pub fn acos_mut(&mut self) {
self.acos_round(Round::Nearest);
}
#[inline]
pub fn acos_round(&mut self, round: Round) -> Ordering {
xmpfr::acos(self, (), round)
}
#[inline]
pub fn acos_ref(&self) -> AcosIncomplete<'_> {
AcosIncomplete { ref_self: self }
}
#[inline]
pub fn atan(mut self) -> Self {
self.atan_round(Round::Nearest);
self
}
#[inline]
pub fn atan_mut(&mut self) {
self.atan_round(Round::Nearest);
}
#[inline]
pub fn atan_round(&mut self, round: Round) -> Ordering {
xmpfr::atan(self, (), round)
}
#[inline]
pub fn atan_ref(&self) -> AtanIncomplete<'_> {
AtanIncomplete { ref_self: self }
}
#[inline]
pub fn atan2(mut self, x: &Self) -> Self {
self.atan2_round(x, Round::Nearest);
self
}
#[inline]
pub fn atan2_mut(&mut self, x: &Self) {
self.atan2_round(x, Round::Nearest);
}
#[inline]
pub fn atan2_round(&mut self, x: &Self, round: Round) -> Ordering {
xmpfr::atan2(self, (), x, round)
}
#[inline]
pub fn atan2_ref<'a>(&'a self, x: &'a Self) -> Atan2Incomplete<'_> {
Atan2Incomplete { ref_self: self, x }
}
#[inline]
pub fn sinh(mut self) -> Self {
self.sinh_round(Round::Nearest);
self
}
#[inline]
pub fn sinh_mut(&mut self) {
self.sinh_round(Round::Nearest);
}
#[inline]
pub fn sinh_round(&mut self, round: Round) -> Ordering {
xmpfr::sinh(self, (), round)
}
#[inline]
pub fn sinh_ref(&self) -> SinhIncomplete<'_> {
SinhIncomplete { ref_self: self }
}
#[inline]
pub fn cosh(mut self) -> Self {
self.cosh_round(Round::Nearest);
self
}
#[inline]
pub fn cosh_mut(&mut self) {
self.cosh_round(Round::Nearest);
}
#[inline]
pub fn cosh_round(&mut self, round: Round) -> Ordering {
xmpfr::cosh(self, (), round)
}
#[inline]
pub fn cosh_ref(&self) -> CoshIncomplete<'_> {
CoshIncomplete { ref_self: self }
}
#[inline]
pub fn tanh(mut self) -> Self {
self.tanh_round(Round::Nearest);
self
}
#[inline]
pub fn tanh_mut(&mut self) {
self.tanh_round(Round::Nearest);
}
#[inline]
pub fn tanh_round(&mut self, round: Round) -> Ordering {
xmpfr::tanh(self, (), round)
}
#[inline]
pub fn tanh_ref(&self) -> TanhIncomplete<'_> {
TanhIncomplete { ref_self: self }
}
#[inline]
pub fn sinh_cosh(mut self, mut cos: Self) -> (Self, Self) {
self.sinh_cosh_round(&mut cos, Round::Nearest);
(self, cos)
}
#[inline]
pub fn sinh_cosh_mut(&mut self, cos: &mut Self) {
self.sinh_cosh_round(cos, Round::Nearest);
}
#[inline]
pub fn sinh_cosh_round(&mut self, cos: &mut Self, round: Round) -> (Ordering, Ordering) {
xmpfr::sinh_cosh(self, cos, (), round)
}
#[inline]
pub fn sinh_cosh_ref(&self) -> SinhCoshIncomplete<'_> {
SinhCoshIncomplete { ref_self: self }
}
#[inline]
pub fn sech(mut self) -> Self {
self.sech_round(Round::Nearest);
self
}
#[inline]
pub fn sech_mut(&mut self) {
self.sech_round(Round::Nearest);
}
#[inline]
pub fn sech_round(&mut self, round: Round) -> Ordering {
xmpfr::sech(self, (), round)
}
#[inline]
pub fn sech_ref(&self) -> SechIncomplete<'_> {
SechIncomplete { ref_self: self }
}
#[inline]
pub fn csch(mut self) -> Self {
self.csch_round(Round::Nearest);
self
}
#[inline]
pub fn csch_mut(&mut self) {
self.csch_round(Round::Nearest);
}
#[inline]
pub fn csch_round(&mut self, round: Round) -> Ordering {
xmpfr::csch(self, (), round)
}
#[inline]
pub fn csch_ref(&self) -> CschIncomplete<'_> {
CschIncomplete { ref_self: self }
}
#[inline]
pub fn coth(mut self) -> Self {
self.coth_round(Round::Nearest);
self
}
#[inline]
pub fn coth_mut(&mut self) {
self.coth_round(Round::Nearest);
}
#[inline]
pub fn coth_round(&mut self, round: Round) -> Ordering {
xmpfr::coth(self, (), round)
}
#[inline]
pub fn coth_ref(&self) -> CothIncomplete<'_> {
CothIncomplete { ref_self: self }
}
#[inline]
pub fn asinh(mut self) -> Self {
self.asinh_round(Round::Nearest);
self
}
#[inline]
pub fn asinh_mut(&mut self) {
self.asinh_round(Round::Nearest);
}
#[inline]
pub fn asinh_round(&mut self, round: Round) -> Ordering {
xmpfr::asinh(self, (), round)
}
#[inline]
pub fn asinh_ref(&self) -> AsinhIncomplete<'_> {
AsinhIncomplete { ref_self: self }
}
#[inline]
pub fn acosh(mut self) -> Self {
self.acosh_round(Round::Nearest);
self
}
#[inline]
pub fn acosh_mut(&mut self) {
self.acosh_round(Round::Nearest);
}
#[inline]
pub fn acosh_round(&mut self, round: Round) -> Ordering {
xmpfr::acosh(self, (), round)
}
#[inline]
pub fn acosh_ref(&self) -> AcoshIncomplete<'_> {
AcoshIncomplete { ref_self: self }
}
#[inline]
pub fn atanh(mut self) -> Self {
self.atanh_round(Round::Nearest);
self
}
#[inline]
pub fn atanh_mut(&mut self) {
self.atanh_round(Round::Nearest);
}
#[inline]
pub fn atanh_round(&mut self, round: Round) -> Ordering {
xmpfr::atanh(self, (), round)
}
#[inline]
pub fn atanh_ref(&self) -> AtanhIncomplete<'_> {
AtanhIncomplete { ref_self: self }
}
#[inline]
pub fn factorial(n: u32) -> FactorialIncomplete {
FactorialIncomplete { n }
}
#[inline]
pub fn ln_1p(mut self) -> Self {
self.ln_1p_round(Round::Nearest);
self
}
#[inline]
pub fn ln_1p_mut(&mut self) {
self.ln_1p_round(Round::Nearest);
}
#[inline]
pub fn ln_1p_round(&mut self, round: Round) -> Ordering {
xmpfr::log1p(self, (), round)
}
#[inline]
pub fn ln_1p_ref(&self) -> Ln1pIncomplete<'_> {
Ln1pIncomplete { ref_self: self }
}
#[inline]
pub fn exp_m1(mut self) -> Self {
self.exp_m1_round(Round::Nearest);
self
}
#[inline]
pub fn exp_m1_mut(&mut self) {
self.exp_m1_round(Round::Nearest);
}
#[inline]
pub fn exp_m1_round(&mut self, round: Round) -> Ordering {
xmpfr::expm1(self, (), round)
}
#[inline]
pub fn exp_m1_ref(&self) -> ExpM1Incomplete<'_> {
ExpM1Incomplete { ref_self: self }
}
#[inline]
pub fn eint(mut self) -> Self {
self.eint_round(Round::Nearest);
self
}
#[inline]
pub fn eint_mut(&mut self) {
self.eint_round(Round::Nearest);
}
#[inline]
pub fn eint_round(&mut self, round: Round) -> Ordering {
xmpfr::eint(self, (), round)
}
#[inline]
pub fn eint_ref(&self) -> EintIncomplete<'_> {
EintIncomplete { ref_self: self }
}
#[inline]
pub fn li2(mut self) -> Self {
self.li2_round(Round::Nearest);
self
}
#[inline]
pub fn li2_mut(&mut self) {
self.li2_round(Round::Nearest);
}
#[inline]
pub fn li2_round(&mut self, round: Round) -> Ordering {
xmpfr::li2(self, (), round)
}
#[inline]
pub fn li2_ref(&self) -> Li2Incomplete<'_> {
Li2Incomplete { ref_self: self }
}
#[inline]
pub fn gamma(mut self) -> Self {
self.gamma_round(Round::Nearest);
self
}
#[inline]
pub fn gamma_mut(&mut self) {
self.gamma_round(Round::Nearest);
}
#[inline]
pub fn gamma_round(&mut self, round: Round) -> Ordering {
xmpfr::gamma(self, (), round)
}
#[inline]
pub fn gamma_ref(&self) -> GammaIncomplete<'_> {
GammaIncomplete { ref_self: self }
}
#[inline]
pub fn gamma_inc(mut self, x: &Self) -> Self {
self.gamma_inc_round(x, Round::Nearest);
self
}
#[inline]
pub fn gamma_inc_mut(&mut self, x: &Self) {
self.gamma_inc_round(x, Round::Nearest);
}
#[inline]
pub fn gamma_inc_round(&mut self, x: &Self, round: Round) -> Ordering {
xmpfr::gamma_inc(self, (), x, round)
}
#[inline]
pub fn gamma_inc_ref<'a>(&'a self, x: &'a Self) -> GammaIncIncomplete<'_> {
GammaIncIncomplete { ref_self: self, x }
}
#[inline]
pub fn ln_gamma(mut self) -> Self {
self.ln_gamma_round(Round::Nearest);
self
}
#[inline]
pub fn ln_gamma_mut(&mut self) {
self.ln_gamma_round(Round::Nearest);
}
#[inline]
pub fn ln_gamma_round(&mut self, round: Round) -> Ordering {
xmpfr::lngamma(self, (), round)
}
#[inline]
pub fn ln_gamma_ref(&self) -> LnGammaIncomplete<'_> {
LnGammaIncomplete { ref_self: self }
}
#[inline]
pub fn ln_abs_gamma(mut self) -> (Self, 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) {
xmpfr::lgamma(self, (), round)
}
#[inline]
pub fn ln_abs_gamma_ref(&self) -> LnAbsGammaIncomplete<'_> {
LnAbsGammaIncomplete { ref_self: self }
}
#[inline]
pub fn digamma(mut self) -> Self {
self.digamma_round(Round::Nearest);
self
}
#[inline]
pub fn digamma_mut(&mut self) {
self.digamma_round(Round::Nearest);
}
#[inline]
pub fn digamma_round(&mut self, round: Round) -> Ordering {
xmpfr::digamma(self, (), round)
}
#[inline]
pub fn digamma_ref(&self) -> DigammaIncomplete<'_> {
DigammaIncomplete { ref_self: self }
}
#[inline]
pub fn zeta(mut self) -> Self {
self.zeta_round(Round::Nearest);
self
}
#[inline]
pub fn zeta_mut(&mut self) {
self.zeta_round(Round::Nearest);
}
#[inline]
pub fn zeta_round(&mut self, round: Round) -> Ordering {
xmpfr::zeta(self, (), round)
}
#[inline]
pub fn zeta_ref(&self) -> ZetaIncomplete<'_> {
ZetaIncomplete { ref_self: self }
}
#[inline]
pub fn zeta_u(u: u32) -> ZetaUIncomplete {
ZetaUIncomplete { u }
}
#[inline]
pub fn erf(mut self) -> Self {
self.erf_round(Round::Nearest);
self
}
#[inline]
pub fn erf_mut(&mut self) {
self.erf_round(Round::Nearest);
}
#[inline]
pub fn erf_round(&mut self, round: Round) -> Ordering {
xmpfr::erf(self, (), round)
}
#[inline]
pub fn erf_ref(&self) -> ErfIncomplete<'_> {
ErfIncomplete { ref_self: self }
}
#[inline]
pub fn erfc(mut self) -> Self {
self.erfc_round(Round::Nearest);
self
}
#[inline]
pub fn erfc_mut(&mut self) {
self.erfc_round(Round::Nearest);
}
#[inline]
pub fn erfc_round(&mut self, round: Round) -> Ordering {
xmpfr::erfc(self, (), round)
}
#[inline]
pub fn erfc_ref(&self) -> ErfcIncomplete<'_> {
ErfcIncomplete { ref_self: self }
}
#[inline]
pub fn j0(mut self) -> Self {
self.j0_round(Round::Nearest);
self
}
#[inline]
pub fn j0_mut(&mut self) {
self.j0_round(Round::Nearest);
}
#[inline]
pub fn j0_round(&mut self, round: Round) -> Ordering {
xmpfr::j0(self, (), round)
}
#[inline]
pub fn j0_ref(&self) -> J0Incomplete<'_> {
J0Incomplete { ref_self: self }
}
#[inline]
pub fn j1(mut self) -> Self {
self.j1_round(Round::Nearest);
self
}
#[inline]
pub fn j1_mut(&mut self) {
self.j1_round(Round::Nearest);
}
#[inline]
pub fn j1_round(&mut self, round: Round) -> Ordering {
xmpfr::j1(self, (), round)
}
#[inline]
pub fn j1_ref(&self) -> J1Incomplete<'_> {
J1Incomplete { ref_self: self }
}
#[inline]
pub fn jn(mut self, n: i32) -> Self {
self.jn_round(n, Round::Nearest);
self
}
#[inline]
pub fn jn_mut(&mut self, n: i32) {
self.jn_round(n, Round::Nearest);
}
#[inline]
pub fn jn_round(&mut self, n: i32, round: Round) -> Ordering {
xmpfr::jn(self, (), n, round)
}
#[inline]
pub fn jn_ref(&self, n: i32) -> JnIncomplete<'_> {
JnIncomplete { ref_self: self, n }
}
#[inline]
pub fn y0(mut self) -> Self {
self.y0_round(Round::Nearest);
self
}
#[inline]
pub fn y0_mut(&mut self) {
self.y0_round(Round::Nearest);
}
#[inline]
pub fn y0_round(&mut self, round: Round) -> Ordering {
xmpfr::y0(self, (), round)
}
#[inline]
pub fn y0_ref(&self) -> Y0Incomplete<'_> {
Y0Incomplete { ref_self: self }
}
#[inline]
pub fn y1(mut self) -> Self {
self.y1_round(Round::Nearest);
self
}
#[inline]
pub fn y1_mut(&mut self) {
self.y1_round(Round::Nearest);
}
#[inline]
pub fn y1_round(&mut self, round: Round) -> Ordering {
xmpfr::y1(self, (), round)
}
#[inline]
pub fn y1_ref(&self) -> Y1Incomplete<'_> {
Y1Incomplete { ref_self: self }
}
#[inline]
pub fn yn(mut self, n: i32) -> Self {
self.yn_round(n, Round::Nearest);
self
}
#[inline]
pub fn yn_mut(&mut self, n: i32) {
self.yn_round(n, Round::Nearest);
}
#[inline]
pub fn yn_round(&mut self, n: i32, round: Round) -> Ordering {
xmpfr::yn(self, (), n, round)
}
#[inline]
pub fn yn_ref(&self, n: i32) -> YnIncomplete<'_> {
YnIncomplete { ref_self: self, n }
}
#[inline]
pub fn agm(mut self, other: &Self) -> Self {
self.agm_round(other, Round::Nearest);
self
}
#[inline]
pub fn agm_mut(&mut self, other: &Self) {
self.agm_round(other, Round::Nearest);
}
#[inline]
pub fn agm_round(&mut self, other: &Self, round: Round) -> Ordering {
xmpfr::agm(self, (), other, round)
}
#[inline]
pub fn agm_ref<'a>(&'a self, other: &'a Self) -> AgmIncomplete<'_> {
AgmIncomplete {
ref_self: self,
other,
}
}
#[inline]
pub fn hypot(mut self, other: &Self) -> Self {
self.hypot_round(other, Round::Nearest);
self
}
#[inline]
pub fn hypot_mut(&mut self, other: &Self) {
self.hypot_round(other, Round::Nearest);
}
#[inline]
pub fn hypot_round(&mut self, other: &Self, round: Round) -> Ordering {
xmpfr::hypot(self, (), other, round)
}
#[inline]
pub fn hypot_ref<'a>(&'a self, other: &'a Self) -> HypotIncomplete<'_> {
HypotIncomplete {
ref_self: self,
other,
}
}
#[inline]
pub fn ai(mut self) -> Self {
self.ai_round(Round::Nearest);
self
}
#[inline]
pub fn ai_mut(&mut self) {
self.ai_round(Round::Nearest);
}
#[inline]
pub fn ai_round(&mut self, round: Round) -> Ordering {
xmpfr::ai(self, (), round)
}
#[inline]
pub fn ai_ref(&self) -> AiIncomplete<'_> {
AiIncomplete { ref_self: self }
}
#[inline]
pub fn ceil(mut self) -> Self {
self.ceil_mut();
self
}
#[inline]
pub fn ceil_mut(&mut self) {
xmpfr::rint_ceil(self, (), Round::Nearest);
}
#[inline]
pub fn ceil_ref(&self) -> CeilIncomplete<'_> {
CeilIncomplete { ref_self: self }
}
#[inline]
pub fn floor(mut self) -> Self {
self.floor_mut();
self
}
#[inline]
pub fn floor_mut(&mut self) {
xmpfr::rint_floor(self, (), Round::Nearest);
}
#[inline]
pub fn floor_ref(&self) -> FloorIncomplete<'_> {
FloorIncomplete { ref_self: self }
}
#[inline]
pub fn round(mut self) -> Self {
self.round_mut();
self
}
#[inline]
pub fn round_mut(&mut self) {
xmpfr::rint_round(self, (), Round::Nearest);
}
#[inline]
pub fn round_ref(&self) -> RoundIncomplete<'_> {
RoundIncomplete { ref_self: self }
}
#[inline]
pub fn round_even(mut self) -> Self {
self.round_even_mut();
self
}
#[inline]
pub fn round_even_mut(&mut self) {
xmpfr::rint_roundeven(self, (), Round::Nearest);
}
#[inline]
pub fn round_even_ref(&self) -> RoundEvenIncomplete<'_> {
RoundEvenIncomplete { ref_self: self }
}
#[inline]
pub fn trunc(mut self) -> Self {
self.trunc_mut();
self
}
#[inline]
pub fn trunc_mut(&mut self) {
xmpfr::rint_trunc(self, (), Round::Nearest);
}
#[inline]
pub fn trunc_ref(&self) -> TruncIncomplete<'_> {
TruncIncomplete { ref_self: self }
}
#[inline]
pub fn fract(mut self) -> Self {
self.fract_mut();
self
}
#[inline]
pub fn fract_mut(&mut self) {
xmpfr::frac(self, (), Round::Nearest);
}
#[inline]
pub fn fract_ref(&self) -> FractIncomplete<'_> {
FractIncomplete { ref_self: self }
}
#[inline]
pub fn trunc_fract(mut self, mut fract: Self) -> (Self, Self) {
self.trunc_fract_round(&mut fract, Round::Nearest);
(self, fract)
}
#[inline]
pub fn trunc_fract_mut(&mut self, fract: &mut Self) {
self.trunc_fract_round(fract, Round::Nearest);
}
#[inline]
pub fn trunc_fract_round(&mut self, fract: &mut Self, round: Round) -> (Ordering, Ordering) {
xmpfr::modf(self, fract, (), round)
}
#[inline]
pub fn trunc_fract_ref(&self) -> TruncFractIncomplete<'_> {
TruncFractIncomplete { ref_self: self }
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_bits(rng: &mut dyn MutRandState) -> RandomBitsIncomplete {
RandomBitsIncomplete { rng }
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_cont(rng: &mut dyn MutRandState) -> RandomContIncomplete {
RandomContIncomplete { rng }
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_normal(rng: &mut dyn MutRandState) -> RandomNormalIncomplete {
RandomNormalIncomplete { rng }
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_exp(rng: &mut dyn MutRandState) -> RandomExpIncomplete {
RandomExpIncomplete { 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 {
xmpfr::sum(self, src.values, round)
}
}
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, Round::Nearest);
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, Round::Nearest);
}
}
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 {
xmpfr::sum_including_old(self, src.values, round)
}
}
#[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, Round::Nearest);
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, Round::Nearest);
}
}
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_op2_float! { xmpfr::remainder; struct RemainderIncomplete { divisor } }
ref_math_op0_float! { xmpfr::ui_2exp; struct UExpIncomplete { u: u32, exp: i32 } }
ref_math_op0_float! { xmpfr::si_2exp; struct IExpIncomplete { i: i32, exp: i32 } }
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<'s, 'min, 'max, Min, Max>
where
Float: PartialOrd<Min>
+ PartialOrd<Max>
+ for<'a> AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ for<'a> AssignRound<&'a Max, Round = Round, Ordering = Ordering>,
{
ref_self: &'s Float,
min: &'min Min,
max: &'max Max,
}
impl<Min, Max> AssignRound<ClampIncomplete<'_, '_, '_, Min, Max>> for Float
where
Self: PartialOrd<Min>
+ PartialOrd<Max>
+ for<'a> AssignRound<&'a Min, Round = Round, Ordering = Ordering>
+ for<'a> AssignRound<&'a Max, Round = Round, Ordering = Ordering>,
{
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(&mut self, src: ClampIncomplete<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 (sign_ord, ord) = xmpfr::lgamma(self.0, src.ref_self, round);
*self.1 = sign_ord;
ord
}
}
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, Round::Nearest);
}
}
impl Assign<LnAbsGammaIncomplete<'_>> for (Float, Ordering) {
#[inline]
fn assign(&mut self, src: LnAbsGammaIncomplete<'_>) {
(&mut self.0, &mut self.1).assign_round(src, Round::Nearest);
}
}
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> {
rng: &'a mut dyn MutRandState,
}
#[cfg(feature = "rand")]
impl Assign<RandomBitsIncomplete<'_>> for Float {
#[inline]
fn assign(&mut self, src: RandomBitsIncomplete) {
xmpfr::urandomb(self, src.rng);
}
}
#[cfg(feature = "rand")]
pub struct RandomContIncomplete<'a> {
rng: &'a mut dyn MutRandState,
}
#[cfg(feature = "rand")]
impl AssignRound<RandomContIncomplete<'_>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(&mut self, src: RandomContIncomplete, round: Round) -> Ordering {
xmpfr::urandom(self, src.rng, round)
}
}
#[cfg(feature = "rand")]
pub struct RandomNormalIncomplete<'a> {
rng: &'a mut dyn MutRandState,
}
#[cfg(feature = "rand")]
impl AssignRound<RandomNormalIncomplete<'_>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(&mut self, src: RandomNormalIncomplete, round: Round) -> Ordering {
xmpfr::nrandom(self, src.rng, round)
}
}
#[cfg(feature = "rand")]
pub struct RandomExpIncomplete<'a> {
rng: &'a mut dyn MutRandState,
}
#[cfg(feature = "rand")]
impl AssignRound<RandomExpIncomplete<'_>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(&mut self, src: RandomExpIncomplete, round: Round) -> Ordering {
xmpfr::erandom(self, src.rng, round)
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct BorrowFloat<'a> {
inner: ManuallyDrop<Float>,
phantom: PhantomData<&'a Float>,
}
impl BorrowFloat<'_> {
unsafe fn from_raw<'a>(raw: mpfr_t) -> BorrowFloat<'a> {
BorrowFloat {
inner: ManuallyDrop::new(Float::from_raw(raw)),
phantom: PhantomData,
}
}
}
impl Deref for BorrowFloat<'_> {
type Target = Float;
#[inline]
fn deref(&self) -> &Float {
&*self.inner
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum ExpFormat {
Exp,
Point,
}
#[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 {
#[inline]
fn default() -> Format {
Format {
radix: 10,
precision: None,
round: Round::default(),
to_upper: false,
exp: ExpFormat::Point,
}
}
}
pub(crate) fn req_chars(f: &Float, format: Format, extra: usize) -> usize {
assert!(
format.radix >= 2 && format.radix <= 36,
"radix {} out of range",
format.radix
);
let size_no_sign = if f.is_zero() {
1
} else if f.is_infinite() || f.is_nan() {
if format.radix > 10 {
5
} else {
3
}
} else {
let digits = req_digits(f, format);
let log2_radix = f64::from(format.radix).log2();
#[allow(clippy::approx_constant)]
const LOG10_2: f64 = 0.301_029_995_663_981_2f64;
let exp = (xmpfr::get_exp(f).az::<f64>() / log2_radix - 1.0).abs();
let exp_digits = (exp * LOG10_2).ceil().az::<usize>() + 2;
digits.checked_add(2 + exp_digits).expect("overflow")
};
let size = if f.is_sign_negative() {
size_no_sign.checked_add(1).expect("overflow")
} else {
size_no_sign
};
size.checked_add(extra).expect("overflow")
}
pub(crate) fn req_digits(f: &Float, format: Format) -> usize {
let digits = format
.precision
.map(|x| if x == 1 { 2 } else { x })
.unwrap_or(0);
let log2_radix = f64::from(format.radix).log2();
if digits > 0 {
digits
} else {
let p = if (format.radix.wrapping_as::<u32>()).is_power_of_two() {
f.prec() - 1
} else {
f.prec()
};
let m = (f64::from(p) / log2_radix).ceil().az::<u32>();
m.unwrapped_as::<usize>().checked_add(2).expect("overflow")
}
}
pub(crate) fn append_to_string(s: &mut String, f: &Float, format: Format) {
use core::fmt::Write;
if f.is_zero() {
s.push_str(if f.is_sign_negative() { "-0" } else { "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 size = req_chars(f, format, 0);
s.reserve(size);
let reserved_ptr = s.as_ptr();
let radix_with_case = if format.to_upper {
-format.radix
} else {
format.radix
};
let digits = format
.precision
.map(|x| if x == 1 { 2 } else { x })
.unwrap_or(0);
let mut exp: exp_t;
unsafe {
let vec = s.as_mut_vec();
let write_ptr = vec.as_mut_ptr().add(vec.len());
let mut maybe_exp = MaybeUninit::uninit();
let c_buf = mpfr::get_str(
write_ptr as *mut c_char,
maybe_exp.as_mut_ptr(),
radix_with_case.unwrapped_cast(),
digits,
f.as_raw(),
raw_round(format.round),
);
assert_eq!(c_buf, write_ptr as *mut c_char);
exp = maybe_exp.assume_init();
let c_len = CStr::from_ptr(write_ptr as *mut c_char).to_bytes().len();
assert!(c_len + 1 < size, "buffer overflow");
let added_sign = *write_ptr == b'-';
let added_digits = c_len - if added_sign { 1 } else { 0 };
let digits_before_point = if format.exp == ExpFormat::Exp
|| exp <= 0
|| exp.unwrapped_as::<usize>() > added_digits
{
exp = exp.checked_sub(1).expect("overflow");
1
} else {
let e = exp.wrapping_as::<usize>();
exp = 0;
e
};
let bytes_before_point = digits_before_point + if added_sign { 1 } else { 0 };
if bytes_before_point == c_len {
vec.set_len(vec.len() + c_len)
} else {
let point_ptr = write_ptr.add(bytes_before_point);
point_ptr.copy_to(point_ptr.offset(1), c_len - bytes_before_point);
*point_ptr = b'.';
vec.set_len(vec.len() + c_len + 1);
}
}
if format.exp == ExpFormat::Exp || exp != 0 {
s.push(if format.radix > 10 {
'@'
} else if format.to_upper {
'E'
} else {
'e'
});
write!(s, "{}", exp).unwrap();
}
debug_assert_eq!(reserved_ptr, s.as_ptr());
}
#[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 = MaybeUninit::uninit();
let ret = unsafe {
mpfr::strtofr(
self.as_raw_mut(),
c_string.as_ptr(),
c_str_end.as_mut_ptr(),
radix.unwrapped_cast(),
raw_round(round),
)
};
let nul = cast_ptr!(c_string.as_bytes_with_nul().last().unwrap(), c_char);
assert_eq!(unsafe { c_str_end.assume_init() } as *const c_char, 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", radix);
let bradix = radix.unwrapped_as::<u8>();
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() {
return 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() {
return 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 => return parse_error!(ParseErrorKind::PointInExp),
b'.' if has_point => return parse_error!(ParseErrorKind::TooManyPoints),
b'.' => {
v.push(b'.');
has_point = true;
continue;
}
b'@' if exp => return parse_error!(ParseErrorKind::TooManyExp),
b'@' if !has_digits => return 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 {
return parse_error!(ParseErrorKind::InvalidDigit);
}
v.push(b);
has_digits = true;
}
if !has_digits {
if exp {
return parse_error!(ParseErrorKind::ExpNoDigits);
} else {
return 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 ParseFloatError {
fn desc(&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 Error for ParseFloatError {
fn description(&self) -> &str {
self.desc()
}
}
impl Display for ParseFloatError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
Display::fmt(self.desc(), f)
}
}
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 || prec > u32::max_value() - 146 {
return None;
}
let estimate = prec - 4 * prec.leading_zeros() + 113;
let k = (estimate + 16) & !31;
let p = k - (f64::from(k).log2() * 4.0).round().unwrapped_as::<u32>() + 13;
if p == prec {
Some(k)
} else {
None
}
}
impl PartialOrd<UExpIncomplete> for Float {
#[inline]
fn partial_cmp(&self, other: &UExpIncomplete) -> Option<Ordering> {
if self.is_nan() {
None
} else {
Some(xmpfr::cmp_u32_2exp(self, other.u, other.exp))
}
}
}
impl PartialOrd<IExpIncomplete> for Float {
#[inline]
fn partial_cmp(&self, other: &IExpIncomplete) -> Option<Ordering> {
if self.is_nan() {
None
} else {
Some(xmpfr::cmp_i32_2exp(self, other.i, other.exp))
}
}
}
#[cfg(test)]
mod tests {
use super::ieee_storage_bits_for_prec;
#[test]
fn check_ieee_storage_bits() {
assert_eq!(ieee_storage_bits_for_prec(0), None);
assert_eq!(ieee_storage_bits_for_prec(11), Some(16));
assert_eq!(ieee_storage_bits_for_prec(24), Some(32));
assert_eq!(ieee_storage_bits_for_prec(53), Some(64));
assert_eq!(ieee_storage_bits_for_prec(83), None); assert_eq!(ieee_storage_bits_for_prec(113), Some(128));
assert_eq!(ieee_storage_bits_for_prec(144), Some(160));
assert_eq!(ieee_storage_bits_for_prec(237), Some(256));
assert_eq!(
ieee_storage_bits_for_prec(u32::max_value() - 178),
Some(u32::max_value() - 63)
);
assert_eq!(ieee_storage_bits_for_prec(u32::max_value() - 145), None);
assert_eq!(
ieee_storage_bits_for_prec(u32::max_value() - 146),
Some(u32::max_value() - 31)
);
assert_eq!(ieee_storage_bits_for_prec(u32::max_value() - 147), None);
assert_eq!(ieee_storage_bits_for_prec(u32::max_value() - 114), None);
assert_eq!(ieee_storage_bits_for_prec(u32::max_value()), None);
}
}