#![deny(rustdoc::broken_intra_doc_links)]
use crate::{
core::{
errors::{
ErrorsRawRealToInteger, ErrorsTryFromf64, ErrorsValidationRawComplex,
ErrorsValidationRawReal, capture_backtrace,
},
traits::{
raw::{
RawComplexTrait, RawRealTrait, RawScalarHyperbolic, RawScalarPow, RawScalarTrait,
RawScalarTrigonometric,
},
validation::{FpChecks, ValidationPolicyReal},
},
},
functions::{Conjugate, NegAssign, Rounding, Sign},
};
use duplicate::duplicate_item;
use rug::{
float::Constant as MpfrConstant,
ops::{CompleteRound, Pow},
};
use std::{
cmp::Ordering,
hash::{Hash, Hasher},
num::FpCategory,
ops::Neg,
};
#[duplicate_item(
T;
[rug::Float];
[rug::Complex];
)]
impl RawScalarTrigonometric for T {
#[duplicate_item(
unchecked_method method;
[unchecked_sin] [sin];
[unchecked_asin] [asin];
[unchecked_cos] [cos];
[unchecked_acos] [acos];
[unchecked_tan] [tan];
[unchecked_atan] [atan];)]
#[inline(always)]
fn unchecked_method(self) -> Self {
T::method(self)
}
}
#[duplicate_item(
T;
[rug::Float];
[rug::Complex];
)]
impl RawScalarHyperbolic for T {
#[duplicate_item(
unchecked_method method;
[unchecked_sinh] [sinh];
[unchecked_asinh] [asinh];
[unchecked_cosh] [cosh];
[unchecked_acosh] [acosh];
[unchecked_tanh] [tanh];
[unchecked_atanh] [atanh];)]
#[inline(always)]
fn unchecked_method(self) -> Self {
T::method(self)
}
}
#[duplicate_item(
T;
[rug::Float];
[rug::Complex];
)]
impl RawScalarPow for T {
#[duplicate_item(
unchecked_method exponent_type;
[unchecked_pow_exponent_i8] [i8];
[unchecked_pow_exponent_i16] [i16];
[unchecked_pow_exponent_i32] [i32];
[unchecked_pow_exponent_i64] [i64];
[unchecked_pow_exponent_i128] [i128];
[unchecked_pow_exponent_isize] [isize];
[unchecked_pow_exponent_u8] [u8];
[unchecked_pow_exponent_u16] [u16];
[unchecked_pow_exponent_u32] [u32];
[unchecked_pow_exponent_u64] [u64];
[unchecked_pow_exponent_u128] [u128];
[unchecked_pow_exponent_usize] [usize];
)]
#[inline(always)]
fn unchecked_method(self, exponent: &exponent_type) -> Self {
T::pow(self, exponent)
}
}
impl RawScalarTrait for rug::Float {
type ValidationErrors = ErrorsValidationRawReal<rug::Float>;
fn raw_zero(precision: u32) -> Self {
rug::Float::with_val(precision, 0.)
}
fn is_zero(&self) -> bool {
rug::Float::is_zero(self)
}
fn raw_one(precision: u32) -> Self {
rug::Float::with_val(precision, 1.)
}
#[duplicate_item(
unchecked_method method;
[unchecked_reciprocal] [recip];
[unchecked_exp] [exp];
[unchecked_sqrt] [sqrt];
[unchecked_ln] [ln];
[unchecked_log2] [log2];
[unchecked_log10] [log10];
)]
#[inline(always)]
fn unchecked_method(self) -> Self {
rug::Float::method(self)
}
#[inline(always)]
fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
rug::Float::mul_add(self, b, c)
}
#[inline(always)]
fn compute_hash<H: Hasher>(&self, state: &mut H) {
debug_assert!(
self.is_finite(),
"Hashing a non-finite rug::Float value (i.e., NaN or Infinity) may lead to inconsistent results."
);
self.prec().hash(state);
if self.is_zero() {
rug::Float::with_val(self.prec(), 0.0)
.to_string_radix(10, None)
.hash(state);
} else {
self.to_string_radix(10, None).hash(state)
}
}
}
impl RawRealTrait for rug::Float {
type RawComplex = rug::Complex;
#[inline(always)]
fn unchecked_abs(self) -> rug::Float {
rug::Float::abs(self)
}
#[inline(always)]
fn unchecked_atan2(self, denominator: &Self) -> Self {
rug::Float::atan2(self, denominator)
}
#[inline(always)]
fn unchecked_pow_exponent_real(self, exponent: &Self) -> Self {
rug::Float::pow(self, exponent)
}
#[inline(always)]
fn unchecked_hypot(self, other: &Self) -> Self {
rug::Float::hypot(self, other)
}
#[inline(always)]
fn unchecked_ln_1p(self) -> Self {
rug::Float::ln_1p(self)
}
#[inline(always)]
fn unchecked_exp_m1(self) -> Self {
rug::Float::exp_m1(self)
}
#[inline(always)]
fn unchecked_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self) {
self.mul_add_mul_mut(mul, add_mul1, add_mul2);
}
#[inline(always)]
fn unchecked_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self) {
self.mul_sub_mul_mut(mul, sub_mul1, sub_mul2);
}
#[inline(always)]
fn raw_total_cmp(&self, other: &Self) -> Ordering {
rug::Float::total_cmp(self, other)
}
#[inline(always)]
fn raw_clamp(self, min: &Self, max: &Self) -> Self {
rug::Float::clamp(self, min, max)
}
#[inline(always)]
fn raw_classify(&self) -> FpCategory {
rug::Float::classify(self)
}
#[inline(always)]
fn raw_two(precision: u32) -> Self {
rug::Float::with_val(precision, 2.)
}
#[inline(always)]
fn raw_one_div_2(precision: u32) -> Self {
rug::Float::with_val(precision, 0.5)
}
#[inline(always)]
fn raw_pi(precision: u32) -> Self {
rug::Float::with_val(precision, MpfrConstant::Pi)
}
#[inline(always)]
fn raw_two_pi(precision: u32) -> Self {
rug::Float::with_val(precision, MpfrConstant::Pi) * 2
}
#[inline(always)]
fn raw_pi_div_2(precision: u32) -> Self {
rug::Float::with_val(precision, MpfrConstant::Pi) / 2
}
#[inline(always)]
fn raw_max_finite(precision: u32) -> Self {
let one = rug::Float::with_val(precision, 1);
let eps = rug::Float::with_val(precision, rug::Float::u_pow_u(2, precision)).recip();
let significand = one - &eps;
let max_exp = rug::float::exp_max() - 1;
significand * rug::Float::with_val(precision, rug::Float::u_pow_u(2, max_exp as u32))
}
#[inline(always)]
fn raw_min_finite(precision: u32) -> Self {
Self::raw_max_finite(precision).neg()
}
#[inline(always)]
fn raw_epsilon(precision: u32) -> Self {
rug::Float::u_pow_u(2, precision - 1)
.complete(precision)
.recip()
}
#[inline(always)]
fn raw_ln_2(precision: u32) -> Self {
rug::Float::with_val(precision, MpfrConstant::Log2)
}
#[inline(always)]
fn raw_ln_10(precision: u32) -> Self {
let ln2 = rug::Float::with_val(precision, MpfrConstant::Log2);
let log2_10 = rug::Float::with_val(precision, 10).log2();
ln2 * log2_10
}
#[inline(always)]
fn raw_log10_2(precision: u32) -> Self {
rug::Float::with_val(precision, 2.).log10()
}
#[inline(always)]
fn raw_log2_10(precision: u32) -> Self {
rug::Float::with_val(precision, 10.).log2()
}
#[inline(always)]
fn raw_log2_e(precision: u32) -> Self {
rug::Float::with_val(precision, MpfrConstant::Log2).recip()
}
#[inline(always)]
fn raw_log10_e(precision: u32) -> Self {
let ln2 = rug::Float::with_val(precision, MpfrConstant::Log2);
let log2_10 = rug::Float::with_val(precision, 10).log2();
(ln2 * log2_10).recip()
}
#[inline(always)]
fn raw_e(precision: u32) -> Self {
rug::Float::with_val(precision, 1.).exp()
}
#[inline(always)]
fn try_new_raw_real_from_f64<RealPolicy: ValidationPolicyReal<Value = Self>>(
value: f64,
) -> Result<Self, ErrorsTryFromf64<Self>> {
let precision = RealPolicy::PRECISION;
const F64_PRECISION: u32 = 53;
if precision < F64_PRECISION {
let placeholder = rug::Float::with_val(precision, value);
return Err(ErrorsTryFromf64::NonRepresentableExactly {
value_in: value,
value_converted_from_f64: placeholder,
precision,
backtrace: capture_backtrace(),
});
}
let value_rug = rug::Float::with_val(precision, value);
let validated =
RealPolicy::validate(value_rug).map_err(|e| ErrorsTryFromf64::Output { source: e })?;
Ok(validated)
}
#[inline(always)]
fn precision(&self) -> u32 {
rug::Float::prec(self)
}
#[inline(always)]
fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<rug::Float, usize>> {
if !self.is_finite() {
return Err(ErrorsRawRealToInteger::NotFinite {
value: self,
backtrace: capture_backtrace(),
});
}
let truncation = self.clone().trunc();
let out_of_range = || ErrorsRawRealToInteger::OutOfRange {
value: self,
min: usize::MIN,
max: usize::MAX,
backtrace: capture_backtrace(),
};
let truncation_as_rug_integer = truncation.to_integer().ok_or_else(out_of_range.clone())?;
truncation_as_rug_integer
.to_usize()
.ok_or_else(out_of_range)
}
}
impl RawScalarTrait for rug::Complex {
type ValidationErrors = ErrorsValidationRawComplex<ErrorsValidationRawReal<rug::Float>>;
fn raw_zero(precision: u32) -> Self {
rug::Complex::with_val(precision, (0., 0.))
}
fn is_zero(&self) -> bool {
rug::Complex::is_zero(self)
}
fn raw_one(precision: u32) -> Self {
rug::Complex::with_val(precision, (1., 0.))
}
#[duplicate_item(
unchecked_method method;
[unchecked_reciprocal] [recip];
[unchecked_exp] [exp];
[unchecked_sqrt] [sqrt];
[unchecked_ln] [ln];
[unchecked_log10] [log10];
)]
#[inline(always)]
fn unchecked_method(self) -> Self {
rug::Complex::method(self)
}
#[inline(always)]
fn unchecked_log2(self) -> Self {
let ln_2 = rug::Float::with_val(self.real().prec(), 2.).ln();
rug::Complex::ln(self) / ln_2
}
#[inline(always)]
fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
rug::Complex::mul_add(self, b, c)
}
fn compute_hash<H: Hasher>(&self, state: &mut H) {
self.raw_real_part().compute_hash(state);
self.raw_imag_part().compute_hash(state);
}
}
impl Conjugate for rug::Complex {
#[inline(always)]
fn conjugate(self) -> Self {
rug::Complex::conj(self)
}
}
impl RawComplexTrait for rug::Complex {
type RawReal = rug::Float;
fn new_unchecked_raw_complex(real: rug::Float, imag: rug::Float) -> Self {
debug_assert_eq!(
real.prec(),
imag.prec(),
"Different precision between real and imaginary part!"
);
rug::Complex::with_val(real.prec(), (real, imag))
}
fn mut_raw_real_part(&mut self) -> &mut rug::Float {
self.mut_real()
}
fn mut_raw_imag_part(&mut self) -> &mut rug::Float {
self.mut_imag()
}
#[inline(always)]
fn unchecked_abs(self) -> rug::Float {
rug::Complex::abs(self).into_real_imag().0
}
#[inline(always)]
fn raw_real_part(&self) -> &rug::Float {
self.real()
}
#[inline(always)]
fn raw_imag_part(&self) -> &rug::Float {
self.imag()
}
#[inline(always)]
fn unchecked_arg(self) -> rug::Float {
rug::Complex::arg(self).into_real_imag().0
}
#[inline(always)]
fn unchecked_pow_exponent_real(self, exponent: &rug::Float) -> Self {
rug::Complex::pow(self, exponent)
}
}
impl FpChecks for rug::Float {
fn is_finite(&self) -> bool {
rug::Float::is_finite(self)
}
fn is_infinite(&self) -> bool {
rug::Float::is_infinite(self)
}
fn is_nan(&self) -> bool {
rug::Float::is_nan(self)
}
fn is_normal(&self) -> bool {
rug::Float::is_normal(self)
}
}
impl FpChecks for rug::Complex {
#[inline(always)]
fn is_finite(&self) -> bool {
self.real().is_finite() && self.imag().is_finite()
}
#[inline(always)]
fn is_infinite(&self) -> bool {
!self.is_nan() && (self.real().is_infinite() || self.imag().is_infinite())
}
#[inline(always)]
fn is_nan(&self) -> bool {
self.real().is_nan() || self.imag().is_nan()
}
#[inline(always)]
fn is_normal(&self) -> bool {
self.real().is_normal() && self.imag().is_normal()
}
}
#[duplicate_item(
T;
[rug::Float];
[rug::Complex];
)]
impl NegAssign for T {
fn neg_assign(&mut self) {
<T as rug::ops::NegAssign>::neg_assign(self);
}
}
impl Sign for rug::Float {
#[inline(always)]
fn kernel_copysign(self, sign: &Self) -> Self {
self.copysign(sign)
}
#[inline(always)]
fn kernel_is_sign_negative(&self) -> bool {
self.is_sign_negative()
}
#[inline(always)]
fn kernel_is_sign_positive(&self) -> bool {
self.is_sign_positive()
}
#[inline(always)]
fn kernel_signum(self) -> Self {
self.signum()
}
}
impl Rounding for rug::Float {
#[inline(always)]
fn kernel_ceil(self) -> Self {
self.ceil()
}
#[inline(always)]
fn kernel_floor(self) -> Self {
self.floor()
}
#[inline(always)]
fn kernel_fract(self) -> Self {
self.fract()
}
#[inline(always)]
fn kernel_round(self) -> Self {
self.round()
}
#[inline(always)]
fn kernel_round_ties_even(self) -> Self {
self.round_even()
}
#[inline(always)]
fn kernel_trunc(self) -> Self {
self.trunc()
}
}