#![deny(rustdoc::broken_intra_doc_links)]
use crate::{
ComplexScalarGetParts, Constants, RealScalar,
core::errors::{ErrorsTryFromf64, ErrorsValidationRawComplex},
kernels::{ComplexValidated, NumKernelStrictFinite, RealValidated},
scalars::AbsoluteTolerance,
};
use num::Complex;
use rug::ops::CompleteRound;
use std::marker::PhantomData;
use try_create::{IntoInner, TryNew};
pub type RugStrictFinite<const PRECISION: u32> = NumKernelStrictFinite<rug::Float, PRECISION>;
pub type RealRugStrictFinite<const PRECISION: u32> = RealValidated<RugStrictFinite<PRECISION>>;
pub type ComplexRugStrictFinite<const PRECISION: u32> =
ComplexValidated<RugStrictFinite<PRECISION>>;
impl<const PRECISION: u32> TryFrom<Complex<f64>> for ComplexRugStrictFinite<PRECISION> {
type Error = ErrorsValidationRawComplex<ErrorsTryFromf64<rug::Float>>;
fn try_from(value: Complex<f64>) -> Result<Self, Self::Error> {
let real_part = RealRugStrictFinite::<PRECISION>::try_from_f64(value.re);
let imag_part = RealRugStrictFinite::<PRECISION>::try_from_f64(value.im);
match (real_part, imag_part) {
(Ok(real_part), Ok(imag_part)) => Ok(Self {
value: rug::Complex::with_val(
PRECISION,
(real_part.into_inner(), imag_part.into_inner()),
),
_phantom: PhantomData,
}),
(Err(error_real_part), Ok(_)) => Err(ErrorsValidationRawComplex::InvalidRealPart {
source: Box::new(error_real_part),
}),
(Ok(_), Err(error_imaginary_part)) => {
Err(ErrorsValidationRawComplex::InvalidImaginaryPart {
source: Box::new(error_imaginary_part),
})
}
(Err(error_real_part), Err(error_imaginary_part)) => {
Err(ErrorsValidationRawComplex::InvalidBothParts {
real_error: Box::new(error_real_part),
imag_error: Box::new(error_imaginary_part),
})
}
}
}
}
impl<const PRECISION: u32> approx::AbsDiffEq for RealRugStrictFinite<PRECISION> {
type Epsilon = AbsoluteTolerance<Self>;
#[inline]
fn default_epsilon() -> Self::Epsilon {
AbsoluteTolerance::epsilon()
}
#[inline]
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
let diff = (self.as_ref() - other.as_ref()).complete(PRECISION);
diff.abs() <= *epsilon.as_ref().as_ref()
}
}
impl<const PRECISION: u32> approx::RelativeEq for RealRugStrictFinite<PRECISION> {
#[inline]
fn default_max_relative() -> Self::Epsilon {
let eps = Self::epsilon();
let eight = rug::Float::with_val(PRECISION, 8);
let scaled = Self::try_new(eps.into_inner() * eight)
.expect("default_max_relative: validation failed unexpectedly");
AbsoluteTolerance::try_new(scaled)
.expect("default_max_relative: AbsoluteTolerance validation failed")
}
#[inline]
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
let diff = (self.as_ref() - other.as_ref()).complete(PRECISION).abs();
if diff <= *epsilon.as_ref().as_ref() {
return true;
}
let abs_self = self.as_ref().clone().abs();
let abs_other = other.as_ref().clone().abs();
let largest = if abs_self > abs_other {
abs_self
} else {
abs_other
};
diff <= (max_relative.as_ref().as_ref() * &largest).complete(PRECISION)
}
}
impl<const PRECISION: u32> approx::AbsDiffEq for ComplexRugStrictFinite<PRECISION> {
type Epsilon = AbsoluteTolerance<RealRugStrictFinite<PRECISION>>;
#[inline]
fn default_epsilon() -> Self::Epsilon {
AbsoluteTolerance::epsilon()
}
#[inline]
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
let real_diff = (self.raw_real_part() - other.raw_real_part()).complete(PRECISION);
let imag_diff = (self.raw_imag_part() - other.raw_imag_part()).complete(PRECISION);
let eps = epsilon.as_ref().as_ref();
real_diff.abs() <= *eps && imag_diff.abs() <= *eps
}
}
impl<const PRECISION: u32> approx::RelativeEq for ComplexRugStrictFinite<PRECISION> {
#[inline]
fn default_max_relative() -> Self::Epsilon {
RealRugStrictFinite::<PRECISION>::default_max_relative()
}
#[inline]
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
let real_self = self.real_part();
let real_other = other.real_part();
if !real_self.relative_eq(&real_other, epsilon.clone(), max_relative.clone()) {
return false;
}
let imag_self = self.imag_part();
let imag_other = other.imag_part();
imag_self.relative_eq(&imag_other, epsilon, max_relative)
}
}
#[cfg(test)]
mod approx_tests {
use super::*;
use crate::scalars::AbsoluteTolerance;
use approx::{AbsDiffEq, assert_abs_diff_eq, assert_abs_diff_ne, assert_relative_eq};
use rug::Float;
use try_create::TryNew;
const PRECISION: u32 = 100;
mod real_rug {
use super::*;
#[test]
fn abs_diff_eq_equal_values() {
let a =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
let b =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
assert_abs_diff_eq!(a, b);
}
#[test]
fn abs_diff_eq_close_values() {
let a =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
let mut b_val = Float::with_val(PRECISION, 1.0);
b_val += Float::with_val(PRECISION, 1e-25);
let b = RealRugStrictFinite::<PRECISION>::try_new(b_val).unwrap();
let eps_val =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1e-20))
.unwrap();
let eps = AbsoluteTolerance::try_new(eps_val).unwrap();
assert_abs_diff_eq!(a, b, epsilon = eps);
}
#[test]
fn abs_diff_ne_different_values() {
let a =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
let b =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 2.0)).unwrap();
assert_abs_diff_ne!(a, b);
}
#[test]
fn default_epsilon_is_machine_epsilon() {
let eps = RealRugStrictFinite::<PRECISION>::default_epsilon();
let expected =
AbsoluteTolerance::try_new(RealRugStrictFinite::<PRECISION>::epsilon()).unwrap();
assert_eq!(*eps.as_ref(), *expected.as_ref());
}
#[test]
fn relative_eq_close_values() {
let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 100.0))
.unwrap();
let eps = RealRugStrictFinite::<PRECISION>::epsilon();
let mut b_val = Float::with_val(PRECISION, 100.0);
b_val += eps.as_ref();
let b = RealRugStrictFinite::<PRECISION>::try_new(b_val).unwrap();
assert_relative_eq!(a, b);
}
#[test]
fn relative_eq_with_custom_tolerance() {
let a =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.001))
.unwrap();
let max_rel_val =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.01))
.unwrap();
let max_rel = AbsoluteTolerance::try_new(max_rel_val).unwrap();
let eps = RealRugStrictFinite::<PRECISION>::default_epsilon();
assert_relative_eq!(a, b, epsilon = eps, max_relative = max_rel);
}
}
mod complex_rug {
use super::*;
#[test]
fn abs_diff_eq_equal_values() {
let a = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
PRECISION,
(
Float::with_val(PRECISION, 1.0),
Float::with_val(PRECISION, 2.0),
),
))
.unwrap();
let b = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
PRECISION,
(
Float::with_val(PRECISION, 1.0),
Float::with_val(PRECISION, 2.0),
),
))
.unwrap();
assert_abs_diff_eq!(a, b);
}
#[test]
fn abs_diff_eq_close_values() {
let a = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
PRECISION,
(
Float::with_val(PRECISION, 1.0),
Float::with_val(PRECISION, 2.0),
),
))
.unwrap();
let b = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
PRECISION,
(
Float::with_val(PRECISION, 1.0) + Float::with_val(PRECISION, 1e-25),
Float::with_val(PRECISION, 2.0) + Float::with_val(PRECISION, 1e-25),
),
))
.unwrap();
let eps_val =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1e-20))
.unwrap();
let eps = AbsoluteTolerance::try_new(eps_val).unwrap();
assert_abs_diff_eq!(a, b, epsilon = eps);
}
#[test]
fn abs_diff_ne_different_values() {
let a = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
PRECISION,
(
Float::with_val(PRECISION, 1.0),
Float::with_val(PRECISION, 2.0),
),
))
.unwrap();
let b = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
PRECISION,
(
Float::with_val(PRECISION, 3.0),
Float::with_val(PRECISION, 4.0),
),
))
.unwrap();
assert_abs_diff_ne!(a, b);
}
#[test]
fn relative_eq_close_values() {
let a = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
PRECISION,
(
Float::with_val(PRECISION, 100.0),
Float::with_val(PRECISION, 200.0),
),
))
.unwrap();
let eps = RealRugStrictFinite::<PRECISION>::epsilon();
let b = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
PRECISION,
(
Float::with_val(PRECISION, 100.0) + eps.as_ref(),
Float::with_val(PRECISION, 200.0) + eps.as_ref(),
),
))
.unwrap();
assert_relative_eq!(a, b);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
ComplexRugStrictFinite, ComplexScalarConstructors, ComplexScalarGetParts,
ComplexScalarMutateParts, ComplexScalarSetParts, Constants, Max, Min, RawRealTrait,
core::{
errors::{ErrorsRawRealToInteger, ErrorsValidationRawReal},
traits::validation::FpChecks,
},
functions::{
ACos, ACosH, ACosHErrors, ACosHInputErrors, ACosRealErrors, ACosRealInputErrors, ASin,
ASinRealErrors, ASinRealInputErrors, ATan, ATan2, ATan2Errors, ATanComplexErrors,
ATanComplexInputErrors, ATanH, ATanHErrors, ATanHInputErrors, Abs, Clamp, Exp,
ExpErrors, Hypot, Ln, Log2, LogarithmComplexErrors, LogarithmComplexInputErrors,
NegAssign, Pow, PowComplexBaseRealExponentErrors, PowIntExponentErrors,
PowIntExponentInputErrors, PowRealBaseRealExponentErrors, Reciprocal, ReciprocalErrors,
Sign, Sqrt, SqrtRealErrors, TotalCmp,
},
};
use num::{One, Zero};
use rug::{Float, float::Constant as MpfrConstant, ops::Pow as RugPow};
use std::{cmp::Ordering, ops::Neg};
use try_create::{TryNew, TryNewValidated};
const PRECISION: u32 = 53;
mod fp_checks {
use super::*;
use rug::Float;
#[test]
fn is_finite() {
let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
assert!(real.is_finite());
let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::INFINITY));
assert!(real.is_err());
let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
53,
(Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
))
.unwrap();
assert!(complex.is_finite());
let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
53,
(Float::with_val(53, f64::INFINITY), Float::with_val(53, 1.0)),
));
assert!(complex.is_err());
}
#[test]
fn is_infinite() {
let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
assert!(!real.is_infinite());
let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::INFINITY));
assert!(real.is_err());
let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
53,
(Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
))
.unwrap();
assert!(!complex.is_infinite());
let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
53,
(Float::with_val(53, f64::INFINITY), Float::with_val(53, 1.0)),
));
assert!(complex.is_err());
}
#[test]
fn is_nan() {
let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
assert!(!real.is_nan());
let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::NAN));
assert!(matches!(real, Err(ErrorsValidationRawReal::IsNaN { .. })));
let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
53,
(Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
))
.unwrap();
assert!(!complex.is_nan());
let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
53,
(Float::with_val(53, f64::NAN), Float::with_val(53, 1.0)),
));
assert!(matches!(
complex,
Err(ErrorsValidationRawComplex::InvalidRealPart {
source: box ErrorsValidationRawReal::IsNaN { .. },
})
));
}
#[test]
fn is_normal() {
let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
assert!(real.is_normal());
let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
assert!(!real.is_normal());
let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
53,
(Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
))
.unwrap();
assert!(complex.is_normal());
let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
53,
(Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
))
.unwrap();
assert!(!complex.is_normal());
}
}
mod abs {
use super::*;
mod real {
use super::*;
#[test]
fn abs_valid() {
let value =
RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, -4.0)).unwrap();
let expected_result =
RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 4.0)).unwrap();
assert_eq!(value.clone().try_abs().unwrap(), expected_result);
assert_eq!(value.abs(), expected_result);
}
#[test]
fn abs_zero() {
let value =
RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
let expected_result =
RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
assert_eq!(value.clone().try_abs().unwrap(), expected_result);
assert_eq!(value.abs(), expected_result);
}
}
mod complex {
use super::*;
#[test]
fn abs_valid() {
let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
53,
(rug::Float::with_val(53, 3.0), rug::Float::with_val(53, 4.0)),
))
.unwrap();
let expected_result =
RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 5.0)).unwrap();
assert_eq!(value.clone().try_abs().unwrap(), expected_result);
assert_eq!(value.abs(), expected_result);
}
#[test]
fn abs_zero() {
let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
53,
(rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
))
.unwrap();
let expected_result =
RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
assert_eq!(value.clone().try_abs().unwrap(), expected_result);
assert_eq!(value.abs(), expected_result);
}
}
}
mod max_min {
use super::*;
#[test]
fn test_realrug_max() {
let value =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
let other =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
let expected =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
assert_eq!(Max::max_by_ref(&value, &other), &expected);
let neg_value =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
.unwrap();
let neg_other =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
.unwrap();
let neg_expected =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
.unwrap();
assert_eq!(Max::max_by_ref(&neg_value, &neg_other), &neg_expected);
}
#[test]
fn test_realrug_min() {
let value =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
let other =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
let expected =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
assert_eq!(Min::min_by_ref(&value, &other), &expected);
let neg_value =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
.unwrap();
let neg_other =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
.unwrap();
let neg_expected =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
.unwrap();
assert_eq!(Min::min_by_ref(&neg_value, &neg_other), &neg_expected);
}
}
mod builders {
use super::*;
mod real {
use super::*;
#[test]
fn try_new_nan() {
let nan = rug::Float::with_val(PRECISION, f64::NAN);
let err = RealRugStrictFinite::<PRECISION>::try_new(nan).unwrap_err();
assert!(matches!(err, ErrorsValidationRawReal::IsNaN { .. }));
}
#[test]
fn try_new_pos_infinity() {
let pos_infinity = rug::Float::with_val(PRECISION, f64::INFINITY);
let err = RealRugStrictFinite::<PRECISION>::try_new(pos_infinity).unwrap_err();
assert!(matches!(err, ErrorsValidationRawReal::IsPosInfinity { .. }));
}
#[test]
fn try_new_neg_infinity() {
let neg_infinity = rug::Float::with_val(PRECISION, f64::NEG_INFINITY);
let err = RealRugStrictFinite::<PRECISION>::try_new(neg_infinity).unwrap_err();
assert!(matches!(err, ErrorsValidationRawReal::IsNegInfinity { .. }));
}
}
mod complex {
use super::*;
#[test]
fn real_part() {
let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (1.23, 4.56)),
)
.unwrap();
assert_eq!(c1.real_part(), 1.23);
let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (-7.89, 0.12)),
)
.unwrap();
assert_eq!(c2.real_part(), -7.89);
let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (0.0, 10.0)),
)
.unwrap();
assert_eq!(c3.real_part(), 0.0);
let c_nan_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (f64::NAN, 5.0)),
)
.unwrap_err();
assert!(matches!(
c_nan_re,
ErrorsValidationRawComplex::InvalidRealPart {
source: box ErrorsValidationRawReal::IsNaN { .. }
}
));
let c_inf_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (f64::INFINITY, 5.0)),
)
.unwrap_err();
assert!(matches!(
c_inf_re,
ErrorsValidationRawComplex::InvalidRealPart {
source: box ErrorsValidationRawReal::IsPosInfinity { .. }
}
));
let c_neg_inf_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (f64::NEG_INFINITY, 5.0)),
)
.unwrap_err();
assert!(matches!(
c_neg_inf_re,
ErrorsValidationRawComplex::InvalidRealPart {
source: box ErrorsValidationRawReal::IsNegInfinity { .. }
}
));
}
#[test]
fn imag_part() {
let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (1.23, 4.56)),
)
.unwrap();
assert_eq!(c1.imag_part(), 4.56);
let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (-7.89, 0.12)),
)
.unwrap();
assert_eq!(c2.imag_part(), 0.12);
let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (10.0, 0.0)),
)
.unwrap();
assert_eq!(c3.imag_part(), 0.0);
let c_nan_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (5.0, f64::NAN)),
)
.unwrap_err();
assert!(matches!(
c_nan_im,
ErrorsValidationRawComplex::InvalidImaginaryPart {
source: box ErrorsValidationRawReal::IsNaN { .. }
}
));
let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (5.0, f64::INFINITY)),
)
.unwrap_err();
assert!(matches!(
c_inf_im,
ErrorsValidationRawComplex::InvalidImaginaryPart {
source: box ErrorsValidationRawReal::IsPosInfinity { .. }
}
));
let c_neg_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (5.0, f64::NEG_INFINITY)),
)
.unwrap_err();
assert!(matches!(
c_neg_inf_im,
ErrorsValidationRawComplex::InvalidImaginaryPart {
source: box ErrorsValidationRawReal::IsNegInfinity { .. }
}
));
}
#[test]
fn try_new_complex() {
let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
let i1 = RealRugStrictFinite::<PRECISION>::try_from_f64(4.56).unwrap();
let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
r1.as_ref().clone(),
i1.as_ref().clone(),
)
.unwrap();
assert_eq!(c1.real_part(), r1);
assert_eq!(c1.imag_part(), i1);
let r2 = RealRugStrictFinite::<PRECISION>::try_from_f64(-7.89).unwrap();
let i2 = RealRugStrictFinite::<PRECISION>::try_from_f64(-0.12).unwrap();
let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
r2.as_ref().clone(),
i2.as_ref().clone(),
)
.unwrap();
assert_eq!(c2.real_part(), r2);
assert_eq!(c2.imag_part(), i2);
let r3 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
let i3 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
r3.as_ref().clone(),
i3.as_ref().clone(),
)
.unwrap();
assert_eq!(c3.real_part(), r3);
assert_eq!(c3.real_part(), i3);
assert!(c3.is_zero());
let c_nan_re = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
Float::with_val(PRECISION, f64::NAN),
Float::with_val(PRECISION, 5.0),
)
.unwrap_err();
assert!(matches!(
c_nan_re,
ErrorsValidationRawComplex::InvalidRealPart { .. }
));
let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
Float::with_val(PRECISION, 10.0),
Float::with_val(PRECISION, f64::INFINITY),
)
.unwrap_err();
assert!(matches!(
c_inf_im,
ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
));
let c_nan_re_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
Float::with_val(PRECISION, f64::NAN),
Float::with_val(PRECISION, f64::INFINITY),
)
.unwrap_err();
assert!(matches!(
c_nan_re_inf_im,
ErrorsValidationRawComplex::InvalidBothParts { .. }
));
}
#[test]
fn try_from_complexf64() {
let c1_in = num::Complex::new(1.23, 4.56);
let c1 = ComplexRugStrictFinite::<PRECISION>::try_from(c1_in).unwrap();
assert_eq!(c1.real_part(), c1_in.re);
assert_eq!(c1.imag_part(), c1_in.im);
let c2_in = num::Complex::new(-7.89, -0.12);
let c2 = ComplexRugStrictFinite::<PRECISION>::try_from(c2_in).unwrap();
assert_eq!(c2.real_part(), c2_in.re);
assert_eq!(c2.imag_part(), c2_in.im);
let c3_in = num::Complex::new(0., 0.);
let c3 = ComplexRugStrictFinite::<PRECISION>::try_from(c3_in).unwrap();
assert_eq!(c3.real_part(), c3_in.re);
assert_eq!(c3.imag_part(), c3_in.im);
let c_nan_re =
ComplexRugStrictFinite::<PRECISION>::try_from(num::Complex::new(f64::NAN, 5.0))
.unwrap_err();
assert!(matches!(
c_nan_re,
ErrorsValidationRawComplex::InvalidRealPart { .. }
));
let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_from(num::Complex::new(
10.0,
f64::INFINITY,
))
.unwrap_err();
assert!(matches!(
c_inf_im,
ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
));
let c_nan_re_inf_im = ComplexRugStrictFinite::<PRECISION>::try_from(
num::Complex::new(f64::NAN, f64::INFINITY),
)
.unwrap_err();
assert!(matches!(
c_nan_re_inf_im,
ErrorsValidationRawComplex::InvalidBothParts { .. }
));
}
#[test]
fn try_new_pure_real() {
let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
let c1 =
ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(r1.as_ref().clone())
.unwrap();
assert_eq!(c1.real_part(), r1);
assert!(c1.imag_part().is_zero());
let c_nan = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
Float::with_val(PRECISION, f64::NAN),
)
.unwrap_err();
assert!(matches!(
c_nan,
ErrorsValidationRawComplex::InvalidRealPart {
source: box ErrorsValidationRawReal::IsNaN { .. }
}
));
}
#[test]
fn try_new_pure_imaginary() {
let i1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
i1.as_ref().clone(),
)
.unwrap();
assert!(c1.real_part().is_zero());
assert_eq!(c1.imag_part(), i1);
let c_nan = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
Float::with_val(PRECISION, f64::NAN),
)
.unwrap_err();
assert!(matches!(
c_nan,
ErrorsValidationRawComplex::InvalidImaginaryPart {
source: box ErrorsValidationRawReal::IsNaN { .. }
}
));
}
#[test]
fn add_to_real_part() {
let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (1.0, 2.0)),
)
.unwrap();
c.add_to_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
assert_eq!(c.real_part(), 4.0);
assert_eq!(c.imag_part(), 2.0);
c.add_to_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0).unwrap());
assert_eq!(c.real_part(), -1.0);
assert_eq!(c.imag_part(), 2.0);
}
#[test]
fn add_to_imaginary_part() {
let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (1.0, 2.0)),
)
.unwrap();
c.add_to_imaginary_part(
&RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(),
);
assert_eq!(c.real_part(), 1.0);
assert_eq!(c.imag_part(), 5.0);
c.add_to_imaginary_part(
&RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap(),
);
assert_eq!(c.real_part(), 1.0);
assert_eq!(c.imag_part(), 1.0);
}
#[test]
fn multiply_real_part() {
let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (1.0, 2.0)),
)
.unwrap();
c.multiply_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
assert_eq!(c.real_part(), 3.0);
assert_eq!(c.imag_part(), 2.0);
c.multiply_real_part(
&RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap(),
);
assert_eq!(c.real_part(), -6.0);
assert_eq!(c.imag_part(), 2.0);
}
#[test]
fn multiply_imaginary_part() {
let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (1.0, 2.0)),
)
.unwrap();
c.multiply_imaginary_part(
&RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(),
);
assert_eq!(c.real_part(), 1.0);
assert_eq!(c.imag_part(), 6.0);
c.multiply_imaginary_part(
&RealRugStrictFinite::<PRECISION>::try_from_f64(-0.5).unwrap(),
);
assert_eq!(c.real_part(), 1.0);
assert_eq!(c.imag_part(), -3.0);
}
#[test]
fn set_real_part() {
let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (1.0, 2.0)),
)
.unwrap();
c.set_real_part(RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
assert_eq!(c.real_part(), 3.0);
assert_eq!(c.imag_part(), 2.0);
c.set_real_part(RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap());
assert_eq!(c.real_part(), -4.0);
assert_eq!(c.imag_part(), 2.0);
}
#[test]
fn set_imaginary_part() {
let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (1.0, 2.0)),
)
.unwrap();
c.set_imaginary_part(RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
assert_eq!(c.real_part(), 1.0);
assert_eq!(c.imag_part(), 3.0);
c.set_imaginary_part(RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap());
assert_eq!(c.real_part(), 1.0);
assert_eq!(c.imag_part(), -4.0);
}
}
}
mod mul {
use super::*;
mod real {
use super::*;
#[test]
fn multiply_ref() {
let r1 = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
PRECISION, 3.0,
))
.unwrap();
let r2 = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
PRECISION, 4.0,
))
.unwrap();
let result = r1 * &r2;
assert_eq!(
result,
RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
PRECISION, 12.0
))
.unwrap()
);
}
}
mod complex {
use super::*;
#[test]
fn multiply_ref() {
let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (1.0, 2.0)),
)
.unwrap();
let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (3.0, 4.0)),
)
.unwrap();
let result = c1 * &c2;
assert_eq!(
result,
ComplexRugStrictFinite::<PRECISION>::try_new_validated(rug::Complex::with_val(
PRECISION,
(-5.0, 10.0),
))
.unwrap()
); }
#[test]
fn complex_times_real() {
let r = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
PRECISION, 2.0,
))
.unwrap();
let c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (3.0, 4.0)),
)
.unwrap();
let result_expected = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (6.0, 8.0)),
)
.unwrap();
let result = c.clone() * &r;
assert_eq!(&result, &result_expected);
let result = c.clone() * r.clone();
assert_eq!(&result, &result_expected);
let mut result = c.clone();
result *= &r;
assert_eq!(&result, &result_expected);
let mut result = c.clone();
result *= r;
assert_eq!(&result, &result_expected);
}
#[test]
fn real_times_complex() {
let r = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
PRECISION, 2.0,
))
.unwrap();
let c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (3.0, 4.0)),
)
.unwrap();
let result_expected = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
rug::Complex::with_val(PRECISION, (6.0, 8.0)),
)
.unwrap();
let result = &r * c.clone();
assert_eq!(&result, &result_expected);
let result = r * c.clone();
assert_eq!(&result, &result_expected);
}
}
}
mod arithmetic {
use super::*;
mod real {
use super::*;
#[test]
fn neg_assign() {
let mut a = rug::Float::with_val(PRECISION, 1.);
a.neg_assign();
let a_expected = rug::Float::with_val(PRECISION, -1.);
assert_eq!(a, a_expected);
let mut b = RealRugStrictFinite::<PRECISION>::one();
b.neg_assign();
let b_expected = RealRugStrictFinite::<PRECISION>::try_new_validated(
rug::Float::with_val(PRECISION, -1.),
)
.unwrap();
assert_eq!(&b, &b_expected);
}
#[test]
#[should_panic(expected = "Division failed validation")]
fn div_by_zero() {
let one = RealRugStrictFinite::<PRECISION>::one();
let zero = RealRugStrictFinite::<PRECISION>::zero();
let _ = &one / &zero;
}
#[test]
#[should_panic(expected = "Division failed validation")]
fn div_assign_by_zero() {
let mut num = RealRugStrictFinite::<PRECISION>::one();
let zero_ref = &RealRugStrictFinite::<PRECISION>::zero();
num /= zero_ref;
}
}
mod complex {
use super::*;
#[test]
fn neg_assign() {
let re = rug::Float::with_val(PRECISION, 1.);
let im = rug::Float::with_val(PRECISION, 2.);
let mut num = rug::Complex::with_val(PRECISION, (re, im));
num.neg_assign();
let expected = rug::Complex::with_val(
PRECISION,
(
rug::Float::with_val(PRECISION, -1.),
rug::Float::with_val(PRECISION, -2.),
),
);
assert_eq!(&num, &expected);
let mut num = ComplexRugStrictFinite::<PRECISION>::try_new_validated(num).unwrap();
let expected = num.clone().neg();
num.neg_assign();
assert_eq!(&num, &expected);
}
#[test]
#[should_panic(expected = "Division failed validation")]
fn div_by_zero() {
let one = ComplexRugStrictFinite::<PRECISION>::one();
let zero = ComplexRugStrictFinite::<PRECISION>::zero();
let _ = &one / &zero;
}
#[test]
#[should_panic(expected = "Division failed validation")]
fn div_assign_by_zero() {
let mut num = ComplexRugStrictFinite::<PRECISION>::one();
let zero_ref = &ComplexRugStrictFinite::<PRECISION>::zero();
num /= zero_ref;
}
}
}
mod real_scalar_methods {
use super::*;
#[test]
fn epsilon() {
let eps = RealRugStrictFinite::<PRECISION>::epsilon();
assert!(eps.is_finite() && eps > RealRugStrictFinite::<PRECISION>::zero());
let expected_eps_val =
rug::Float::with_val(PRECISION, 2.0).pow(1i32 - PRECISION as i32);
let expected_eps = RealRugStrictFinite::<PRECISION>::try_new(expected_eps_val).unwrap();
assert_eq!(eps, expected_eps, "Epsilon value mismatch");
}
#[test]
fn clamp_ref() {
let val = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap();
let min_val = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
let max_val = RealRugStrictFinite::<PRECISION>::try_from_f64(10.0).unwrap();
assert_eq!(val.clone().clamp_ref(&min_val, &max_val), val);
assert_eq!(
RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0)
.unwrap()
.clamp_ref(&min_val, &max_val),
min_val
);
assert_eq!(
RealRugStrictFinite::<PRECISION>::try_from_f64(15.0)
.unwrap()
.clamp_ref(&min_val, &max_val),
max_val
);
}
#[test]
fn hypot() {
let a = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap();
let b = RealRugStrictFinite::<PRECISION>::try_from_f64(4.0).unwrap();
let expected = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap();
assert_eq!(a.hypot(&b), expected);
}
#[test]
fn signum() {
assert_eq!(
RealRugStrictFinite::<PRECISION>::try_from_f64(5.0)
.unwrap()
.kernel_signum(),
RealRugStrictFinite::<PRECISION>::one()
);
assert_eq!(
RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0)
.unwrap()
.kernel_signum(),
RealRugStrictFinite::<PRECISION>::negative_one()
);
assert_eq!(
RealRugStrictFinite::<PRECISION>::zero().kernel_signum(),
RealRugStrictFinite::<PRECISION>::one()
);
}
#[test]
fn total_cmp() {
let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0).unwrap();
let r2 = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
assert_eq!(r1.total_cmp(&r1), Ordering::Equal);
assert_eq!(r1.total_cmp(&r2), Ordering::Less);
assert_eq!(r2.total_cmp(&r1), Ordering::Greater);
}
#[test]
fn mul_add_mul_mut() {
let mut a = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
let b = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(); let c = RealRugStrictFinite::<PRECISION>::try_from_f64(4.0).unwrap(); let d = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap(); a.kernel_mul_add_mul_mut(&b, &c, &d);
assert_eq!(
a,
RealRugStrictFinite::<PRECISION>::try_from_f64(26.0).unwrap()
);
}
#[test]
fn mul_sub_mul_mut() {
let mut a = RealRugStrictFinite::<PRECISION>::try_from_f64(10.0).unwrap();
let b = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap(); let c = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(); let d = RealRugStrictFinite::<PRECISION>::try_from_f64(4.0).unwrap(); a.kernel_mul_sub_mul_mut(&b, &c, &d);
assert_eq!(
a,
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
}
#[test]
fn test_real_rug_constants() {
let raw_float = |f: f64| Float::with_val(PRECISION, f);
let pi = RealRugStrictFinite::<PRECISION>::pi();
let expected_pi = Float::with_val(PRECISION, MpfrConstant::Pi);
assert_eq!(pi.as_ref(), &expected_pi);
let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
let expected_two_pi = Float::with_val(PRECISION, MpfrConstant::Pi) * 2;
assert_eq!(two_pi.as_ref(), &expected_two_pi);
let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
let expected_pi_div_2 = Float::with_val(PRECISION, MpfrConstant::Pi) / 2;
assert_eq!(pi_div_2.as_ref(), &expected_pi_div_2);
let e = RealRugStrictFinite::<PRECISION>::e();
let expected_e = raw_float(1.0).exp();
assert_eq!(e.as_ref(), &expected_e);
let log2_e = RealRugStrictFinite::<PRECISION>::log2_e();
let expected_log2_e = Float::with_val(PRECISION, MpfrConstant::Log2).recip();
assert_eq!(log2_e.as_ref(), &expected_log2_e);
let log10_e = RealRugStrictFinite::<PRECISION>::log10_e();
let ln2 = Float::with_val(PRECISION, MpfrConstant::Log2);
let log2_10 = raw_float(10.0).log2();
let expected_log10_e = (ln2 * log2_10).recip();
assert_eq!(log10_e.as_ref(), &expected_log10_e);
let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
let expected_ln_2 = Float::with_val(PRECISION, MpfrConstant::Log2);
assert_eq!(ln_2.as_ref(), &expected_ln_2);
let ln_10 = RealRugStrictFinite::<PRECISION>::ln_10();
let ln2 = Float::with_val(PRECISION, MpfrConstant::Log2);
let log2_10 = raw_float(10.0).log2();
let expected_ln_10 = ln2 * log2_10;
assert_eq!(ln_10.as_ref(), &expected_ln_10);
let log2_10 = RealRugStrictFinite::<PRECISION>::log2_10();
let expected_log2_10 = raw_float(10.0).log2();
assert_eq!(log2_10.as_ref(), &expected_log2_10);
let log10_2 = RealRugStrictFinite::<PRECISION>::log10_2();
let expected_log10_2 = raw_float(2.0).log10();
assert_eq!(log10_2.as_ref(), &expected_log10_2);
let max_finite = RealRugStrictFinite::<PRECISION>::max_finite();
let expected_max_finite = <rug::Float as RawRealTrait>::raw_max_finite(PRECISION);
assert_eq!(max_finite.as_ref(), &expected_max_finite);
let min_finite = RealRugStrictFinite::<PRECISION>::min_finite();
let expected_min_finite = <rug::Float as RawRealTrait>::raw_min_finite(PRECISION);
assert_eq!(min_finite.as_ref(), &expected_min_finite);
let epsilon = RealRugStrictFinite::<PRECISION>::epsilon();
let expected_epsilon = <rug::Float as RawRealTrait>::raw_epsilon(PRECISION);
assert_eq!(epsilon.as_ref(), &expected_epsilon);
assert_eq!(
RealRugStrictFinite::<PRECISION>::negative_one().as_ref(),
&raw_float(-1.0)
);
assert_eq!(
RealRugStrictFinite::<PRECISION>::two().as_ref(),
&raw_float(2.0)
);
assert_eq!(
RealRugStrictFinite::<PRECISION>::one_div_2().as_ref(),
&raw_float(0.5)
);
}
#[test]
fn test_real_rug_constants_mpfr_optimization() {
let pi = RealRugStrictFinite::<PRECISION>::pi();
let expected_pi = Float::with_val(PRECISION, MpfrConstant::Pi);
assert_eq!(pi.as_ref(), &expected_pi);
let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
let expected_ln_2 = Float::with_val(PRECISION, MpfrConstant::Log2);
assert_eq!(ln_2.as_ref(), &expected_ln_2);
let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
let expected_two_pi = Float::with_val(PRECISION, MpfrConstant::Pi) * 2;
assert_eq!(two_pi.as_ref(), &expected_two_pi);
let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
let expected_pi_div_2 = Float::with_val(PRECISION, MpfrConstant::Pi) / 2;
assert_eq!(pi_div_2.as_ref(), &expected_pi_div_2);
}
#[test]
fn test_real_rug_constants_precision_independence() {
type Real100 = RealRugStrictFinite<100>;
type Real200 = RealRugStrictFinite<200>;
type Real500 = RealRugStrictFinite<500>;
let pi_100 = Real100::pi();
let pi_200 = Real200::pi();
let pi_500 = Real500::pi();
let pi_100_f64 = pi_100.as_ref().to_f64();
let pi_200_f64 = pi_200.as_ref().to_f64();
let pi_500_f64 = pi_500.as_ref().to_f64();
let pi_expected = std::f64::consts::PI;
assert!((pi_100_f64 - pi_expected).abs() < 1e-15);
assert!((pi_200_f64 - pi_expected).abs() < 1e-15);
assert!((pi_500_f64 - pi_expected).abs() < 1e-15);
let e_100 = Real100::e();
let e_200 = Real200::e();
let e_100_f64 = e_100.as_ref().to_f64();
let e_200_f64 = e_200.as_ref().to_f64();
let e_expected = std::f64::consts::E;
assert!((e_100_f64 - e_expected).abs() < 1e-15);
assert!((e_200_f64 - e_expected).abs() < 1e-15);
}
#[test]
fn test_real_rug_constants_mathematical_relationships() {
let pi = RealRugStrictFinite::<PRECISION>::pi();
let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
let expected_two_pi = pi.as_ref() * Float::with_val(PRECISION, 2);
assert_eq!(two_pi.as_ref(), &expected_two_pi);
let expected_pi_div_2 = pi.as_ref() / Float::with_val(PRECISION, 2);
assert_eq!(pi_div_2.as_ref(), &expected_pi_div_2);
let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
let ln_10 = RealRugStrictFinite::<PRECISION>::ln_10();
let log2_e = RealRugStrictFinite::<PRECISION>::log2_e();
let log10_e = RealRugStrictFinite::<PRECISION>::log10_e();
let product = (log2_e.as_ref() * ln_2.as_ref()).complete(PRECISION);
let one = Float::with_val(PRECISION, 1);
let epsilon = Float::with_val(PRECISION, 1e-10);
let diff = (product - &one).abs();
assert!(diff < epsilon);
let product = (log10_e.as_ref() * ln_10.as_ref()).complete(PRECISION);
let diff = (product - &one).abs();
assert!(diff < epsilon);
}
#[test]
fn test_real_rug_constants_consistency() {
let pi1 = RealRugStrictFinite::<PRECISION>::pi();
let pi2 = RealRugStrictFinite::<PRECISION>::pi();
assert_eq!(pi1.as_ref(), pi2.as_ref());
let e1 = RealRugStrictFinite::<PRECISION>::e();
let e2 = RealRugStrictFinite::<PRECISION>::e();
assert_eq!(e1.as_ref(), e2.as_ref());
let ln2_1 = RealRugStrictFinite::<PRECISION>::ln_2();
let ln2_2 = RealRugStrictFinite::<PRECISION>::ln_2();
assert_eq!(ln2_1.as_ref(), ln2_2.as_ref());
let two_pi1 = RealRugStrictFinite::<PRECISION>::two_pi();
let two_pi2 = RealRugStrictFinite::<PRECISION>::two_pi();
assert_eq!(two_pi1.as_ref(), two_pi2.as_ref());
let pi_div_2_1 = RealRugStrictFinite::<PRECISION>::pi_div_2();
let pi_div_2_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
assert_eq!(pi_div_2_1.as_ref(), pi_div_2_2.as_ref());
}
}
mod scalar_constructors {
use super::*;
use crate::{
core::errors::ErrorsValidationRawReal,
functions::{
ATan2InputErrors, LogarithmRealErrors, LogarithmRealInputErrors,
PowComplexBaseRealExponentInputErrors, PowRealBaseRealExponentInputErrors,
ReciprocalInputErrors, SqrtRealInputErrors,
},
};
mod real {
use super::*;
#[test]
fn exp_overflow() {
let large_val = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0e60).unwrap(); let res_large = large_val.try_exp();
assert!(matches!(
res_large,
Err(ExpErrors::Output {
source: ErrorsValidationRawReal::IsPosInfinity { .. }
})
),);
}
#[test]
fn ln_domain_errors() {
let neg_val = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.0).unwrap();
assert!(matches!(
neg_val.try_ln(),
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::NegativeArgument { .. }
})
));
let zero_val = RealRugStrictFinite::<PRECISION>::zero();
assert!(matches!(
zero_val.try_ln(),
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::ZeroArgument { .. }
})
));
}
}
mod complex {
use super::*;
#[test]
fn log2_zero() {
let zero_val = ComplexRugStrictFinite::<PRECISION>::zero();
assert!(matches!(
zero_val.try_log2(),
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::ZeroArgument { .. }
})
));
}
}
mod pow {
use super::*;
mod real_base {
use super::*;
#[test]
fn negative_base_real_exponent_error() {
let base = RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap();
let exponent = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
let res = base.try_pow(&exponent);
assert!(matches!(
res,
Err(PowRealBaseRealExponentErrors::Input {
source: PowRealBaseRealExponentInputErrors::NegativeBase { .. }
})
));
}
#[test]
fn real_base_uint_exponent() {
let base = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
assert_eq!(
base.clone().try_pow(3u8).unwrap(),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().try_pow(3u16).unwrap(),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().try_pow(3u32).unwrap(),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().try_pow(3u64).unwrap(),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().try_pow(3u128).unwrap(),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().try_pow(3usize).unwrap(),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().pow(3u8),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().pow(3u16),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().pow(3u32),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().pow(3u64),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().pow(3u128),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().pow(3usize),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
}
#[test]
fn real_base_int_exponent() {
let base = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
assert_eq!(
base.clone().try_pow(3i8).unwrap(),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().try_pow(3i16).unwrap(),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().try_pow(3i32).unwrap(),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().try_pow(3i64).unwrap(),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().try_pow(3i128).unwrap(),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().try_pow(3isize).unwrap(),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().pow(3i8),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().pow(3i16),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().pow(3i32),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().pow(3i64),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().pow(3i128),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
assert_eq!(
base.clone().pow(3isize),
RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
);
}
#[test]
fn real_base_int_exponent_zero_neg_exp_error() {
let base = RealRugStrictFinite::<PRECISION>::zero();
let exponent: i32 = -2;
let res = base.try_pow(exponent);
assert!(matches!(
res,
Err(PowIntExponentErrors::Input {
source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
})
));
}
}
mod complex_base {
use super::*;
#[test]
fn complex_base_uint_exponent() {
let base = ComplexRugStrictFinite::<PRECISION>::try_new(
rug::Complex::with_val(PRECISION, (2.0, 3.0)),
)
.unwrap();
let expected_res = ComplexRugStrictFinite::<PRECISION>::try_new(
rug::Complex::with_val(PRECISION, (-46.0, 9.0)),
)
.unwrap();
assert_eq!(&base.clone().try_pow(3u8).unwrap(), &expected_res);
assert_eq!(&base.clone().try_pow(3u16).unwrap(), &expected_res);
assert_eq!(&base.clone().try_pow(3u32).unwrap(), &expected_res);
assert_eq!(&base.clone().try_pow(3u64).unwrap(), &expected_res);
assert_eq!(&base.clone().try_pow(3u128).unwrap(), &expected_res);
assert_eq!(&base.clone().try_pow(3usize).unwrap(), &expected_res);
assert_eq!(&base.clone().pow(3u8), &expected_res);
assert_eq!(&base.clone().pow(3u16), &expected_res);
assert_eq!(&base.clone().pow(3u32), &expected_res);
assert_eq!(&base.clone().pow(3u64), &expected_res);
assert_eq!(&base.clone().pow(3u128), &expected_res);
assert_eq!(&base.clone().pow(3usize), &expected_res);
}
#[test]
fn complex_base_int_exponent() {
let base = ComplexRugStrictFinite::<PRECISION>::try_new(
rug::Complex::with_val(PRECISION, (2.0, 3.0)),
)
.unwrap();
let expected_res = ComplexRugStrictFinite::<PRECISION>::try_new(
rug::Complex::with_val(PRECISION, (-46.0, 9.0)),
)
.unwrap();
assert_eq!(&base.clone().try_pow(3i8).unwrap(), &expected_res);
assert_eq!(&base.clone().try_pow(3i16).unwrap(), &expected_res);
assert_eq!(&base.clone().try_pow(3i32).unwrap(), &expected_res);
assert_eq!(&base.clone().try_pow(3i64).unwrap(), &expected_res);
assert_eq!(&base.clone().try_pow(3i128).unwrap(), &expected_res);
assert_eq!(&base.clone().try_pow(3isize).unwrap(), &expected_res);
assert_eq!(&base.clone().pow(3i8), &expected_res);
assert_eq!(&base.clone().pow(3i16), &expected_res);
assert_eq!(&base.clone().pow(3i32), &expected_res);
assert_eq!(&base.clone().pow(3i64), &expected_res);
assert_eq!(&base.clone().pow(3i128), &expected_res);
assert_eq!(&base.clone().pow(3isize), &expected_res);
}
#[test]
fn complex_zero_base_negative_real_exponent_error() {
let base = ComplexRugStrictFinite::<PRECISION>::zero();
let exponent = RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap();
let res = base.try_pow(&exponent);
assert!(matches!(
res,
Err(PowComplexBaseRealExponentErrors::Input {
source:
PowComplexBaseRealExponentInputErrors::ZeroBaseNegativeExponent { .. }
})
));
}
#[test]
fn complex_zero_base_zero_real_exponent() {
let base = ComplexRugStrictFinite::<PRECISION>::zero();
let exponent = RealRugStrictFinite::<PRECISION>::zero();
let res = base.try_pow(&exponent).unwrap();
assert_eq!(res, ComplexRugStrictFinite::<PRECISION>::one());
}
#[test]
fn complex_base_int_exponent_zero_neg_exp_error() {
let base = ComplexRugStrictFinite::<PRECISION>::zero();
let exponent: i32 = -2;
let res = base.try_pow(exponent);
assert!(matches!(
res,
Err(PowIntExponentErrors::Input {
source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
})
));
}
}
}
#[test]
fn reciprocal_real_rug_zero() {
let zero_val = RealRugStrictFinite::<PRECISION>::zero();
let res = zero_val.try_reciprocal();
assert!(matches!(
res,
Err(ReciprocalErrors::Input {
source: ReciprocalInputErrors::DivisionByZero { .. }
})
));
}
#[test]
fn reciprocal_complex_rug_zero() {
let zero_val = ComplexRugStrictFinite::<PRECISION>::zero();
let res = zero_val.try_reciprocal();
assert!(matches!(
res,
Err(ReciprocalErrors::Input {
source: ReciprocalInputErrors::DivisionByZero { .. }
})
));
}
#[test]
fn sqrt_real_rug_negative_input() {
let neg_val = RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap();
let res = neg_val.try_sqrt();
assert!(matches!(
res,
Err(SqrtRealErrors::Input {
source: SqrtRealInputErrors::NegativeValue { .. }
})
));
}
mod trigonometric {
use super::*;
#[test]
fn atan2_real_rug_zero_over_zero() {
let zero_val = RealRugStrictFinite::<PRECISION>::zero();
let res = zero_val.try_atan2(&RealRugStrictFinite::<PRECISION>::zero());
assert!(matches!(
res,
Err(ATan2Errors::Input {
source: ATan2InputErrors::ZeroOverZero { .. }
})
));
}
#[test]
fn asin_real_rug_out_of_domain() {
let val_gt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.5).unwrap();
assert!(matches!(
val_gt_1.try_asin(),
Err(ASinRealErrors::Input {
source: ASinRealInputErrors::OutOfDomain { .. }
})
));
let val_lt_neg1 = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.5).unwrap();
assert!(matches!(
val_lt_neg1.try_asin(),
Err(ASinRealErrors::Input {
source: ASinRealInputErrors::OutOfDomain { .. }
})
));
}
#[test]
fn acos_real_rug_out_of_domain() {
let val_gt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.5).unwrap();
assert!(matches!(
val_gt_1.try_acos(),
Err(ACosRealErrors::Input {
source: ACosRealInputErrors::OutOfDomain { .. }
})
));
let val_lt_neg1 = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.5).unwrap();
assert!(matches!(
val_lt_neg1.try_acos(),
Err(ACosRealErrors::Input {
source: ACosRealInputErrors::OutOfDomain { .. }
})
));
}
#[test]
fn atan_complex_rug_pole() {
let i_val = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
Float::with_val(PRECISION, 1.0),
)
.unwrap();
assert!(matches!(
i_val.try_atan(),
Err(ATanComplexErrors::Input {
source: ATanComplexInputErrors::ArgumentIsPole { .. }
})
));
let neg_i_val = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
Float::with_val(PRECISION, -1.0),
)
.unwrap();
assert!(matches!(
neg_i_val.try_atan(),
Err(ATanComplexErrors::Input {
source: ATanComplexInputErrors::ArgumentIsPole { .. }
})
));
}
}
mod hyperbolic {
use super::*;
mod real {
use super::*;
#[test]
fn atanh_real_rug_out_of_domain() {
let val_ge_1 = RealRugStrictFinite::<PRECISION>::one(); assert!(matches!(
val_ge_1.try_atanh(),
Err(ATanHErrors::Input {
source: ATanHInputErrors::OutOfDomain { .. }
})
));
let val_le_neg1 = RealRugStrictFinite::<PRECISION>::negative_one(); assert!(matches!(
val_le_neg1.try_atanh(),
Err(ATanHErrors::Input {
source: ATanHInputErrors::OutOfDomain { .. }
})
));
}
#[test]
fn acosh_real_rug_out_of_domain() {
let val_lt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
assert!(matches!(
val_lt_1.try_acosh(),
Err(ACosHErrors::Input {
source: ACosHInputErrors::OutOfDomain { .. }
})
));
}
}
mod complex {
use super::*;
#[test]
fn acosh_out_of_domain() {
let val_on_branch_cut = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
Float::with_val(PRECISION, 0.5),
)
.unwrap();
assert!(matches!(
val_on_branch_cut.try_acosh(),
Err(ACosHErrors::Input {
source: ACosHInputErrors::OutOfDomain { .. }
})
));
let val_on_branch_cut_neg =
ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(Float::with_val(
PRECISION, -5.0,
))
.unwrap();
assert!(matches!(
val_on_branch_cut_neg.try_acosh(),
Err(ACosHErrors::Input {
source: ACosHInputErrors::OutOfDomain { .. }
})
));
}
#[test]
fn atanh_out_of_domain() {
let val_ge_1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
Float::with_val(PRECISION, 1.0),
)
.unwrap();
assert!(matches!(
val_ge_1.try_atanh(),
Err(ATanHErrors::Input {
source: ATanHInputErrors::OutOfDomain { .. }
})
));
let val_le_neg1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
Float::with_val(PRECISION, -1.0),
)
.unwrap();
assert!(matches!(
val_le_neg1.try_atanh(),
Err(ATanHErrors::Input {
source: ATanHInputErrors::OutOfDomain { .. }
})
));
}
}
} }
mod summation {
use super::*;
const PRECISION: u32 = 53;
type RealValidated = RealRugStrictFinite<PRECISION>;
type ComplexValidated = ComplexRugStrictFinite<PRECISION>;
#[test]
fn sum_real() {
let values = vec![
RealValidated::try_from_f64(1.0).unwrap(),
RealValidated::try_from_f64(2.0).unwrap(),
RealValidated::try_from_f64(3.0).unwrap(),
RealValidated::try_from_f64(4.0).unwrap(),
RealValidated::try_from_f64(5.0).unwrap(),
];
let sum: RealValidated = values.into_iter().sum();
assert_eq!(sum, RealValidated::try_from_f64(15.0).unwrap());
}
#[test]
fn sum_real_compensated() {
let values = vec![
RealValidated::try_from_f64(1.0e100).unwrap(),
RealValidated::try_from_f64(1.0).unwrap(),
RealValidated::try_from_f64(-1.0e100).unwrap(),
];
let sum: RealValidated = values.into_iter().sum();
assert_eq!(sum, RealValidated::try_from_f64(1.0).unwrap());
}
#[test]
fn sum_complex() {
let values = vec![
ComplexValidated::try_new_complex(
rug::Float::with_val(PRECISION, 1.),
rug::Float::with_val(PRECISION, 2.),
)
.unwrap(),
ComplexValidated::try_new_complex(
rug::Float::with_val(PRECISION, 3.),
rug::Float::with_val(PRECISION, 4.),
)
.unwrap(),
ComplexValidated::try_new_complex(
rug::Float::with_val(PRECISION, 5.),
rug::Float::with_val(PRECISION, 6.),
)
.unwrap(),
];
let sum: ComplexValidated = values.into_iter().sum();
assert_eq!(
sum,
ComplexValidated::try_new_complex(
rug::Float::with_val(PRECISION, 9.),
rug::Float::with_val(PRECISION, 12.)
)
.unwrap()
);
}
#[test]
fn sum_complex_compensated() {
let values = [
ComplexValidated::try_new_complex(
rug::Float::with_val(PRECISION, 1.0e100),
rug::Float::with_val(PRECISION, -1.0e100),
)
.unwrap(),
ComplexValidated::try_new_complex(
rug::Float::with_val(PRECISION, 1.),
rug::Float::with_val(PRECISION, 2.),
)
.unwrap(),
ComplexValidated::try_new_complex(
rug::Float::with_val(PRECISION, -1.0e100),
rug::Float::with_val(PRECISION, 1.0e100),
)
.unwrap(),
];
let sum: ComplexValidated = values.iter().cloned().sum();
assert_eq!(
sum,
ComplexValidated::try_new_complex(
rug::Float::with_val(PRECISION, 1.),
rug::Float::with_val(PRECISION, 2.)
)
.unwrap()
);
}
}
mod random {
use super::*;
use crate::{RandomSampleFromF64, new_random_vec};
use rand::{RngExt, SeedableRng, distr::Uniform, rngs::StdRng};
const PRECISION: u32 = 53;
type RealValidated = RealRugStrictFinite<PRECISION>;
type ComplexValidated = ComplexRugStrictFinite<PRECISION>;
#[test]
fn test_random_real_validated() {
let seed = [42; 32];
let mut rng = StdRng::from_seed(seed);
let random_real: RealValidated = rng.random();
assert_eq!(random_real, 0.23713468825474326);
let mut rng2 = StdRng::from_seed(seed);
let random_real2: RealValidated = rng2.random();
assert_eq!(random_real, random_real2);
}
#[test]
fn test_random_complex_validated() {
let seed = [99; 32];
let mut rng = StdRng::from_seed(seed);
let random_complex: ComplexValidated = rng.random();
let real_part = random_complex.real_part();
let imag_part = random_complex.imag_part();
assert_eq!(real_part, 0.9995546882627792);
assert_eq!(imag_part, 0.08932180682540247);
let mut rng2 = StdRng::from_seed(seed);
let random_complex2: ComplexValidated = rng2.random();
assert_eq!(random_complex, random_complex2);
}
const SEED: [u8; 32] = [42; 32];
#[test]
fn test_sample_real_validated() {
let mut rng = StdRng::from_seed(SEED);
let dist = Uniform::new(-10.0, 10.0).unwrap();
let val = RealValidated::sample_from(&dist, &mut rng);
assert_eq!(val, -5.257306234905137);
let mut rng2 = StdRng::from_seed(SEED);
let val2 = RealValidated::sample_from(&dist, &mut rng2);
assert_eq!(val, val2);
}
#[test]
fn test_sample_complex_validated() {
let mut rng = StdRng::from_seed(SEED);
let dist = Uniform::new(-10.0, 10.0).unwrap();
let val = ComplexValidated::sample_from(&dist, &mut rng);
assert_eq!(val.real_part(), -5.257306234905137);
assert_eq!(val.imag_part(), 7.212119776268775);
let mut rng2 = StdRng::from_seed(SEED);
let val2 = ComplexValidated::sample_from(&dist, &mut rng2);
assert_eq!(val, val2);
}
#[test]
fn new_random_vec_real() {
let mut rng = StdRng::from_seed(SEED);
let dist = Uniform::new(-10.0, 10.0).unwrap();
let vec: Vec<RealValidated> = new_random_vec(3, &dist, &mut rng);
assert_eq!(vec.len(), 3);
assert_eq!(vec[0], -5.257306234905137);
assert_eq!(vec[1], 7.212119776268775);
assert_eq!(vec[2], -4.666248990558111);
let mut rng2 = StdRng::from_seed(SEED);
let vec2: Vec<RealValidated> = new_random_vec(3, &dist, &mut rng2);
assert_eq!(vec, vec2);
}
#[test]
fn new_random_vec_complex() {
let mut rng = StdRng::from_seed(SEED);
let dist = Uniform::new(-10.0, 10.0).unwrap();
let vec: Vec<ComplexValidated> = new_random_vec(3, &dist, &mut rng);
assert_eq!(vec.len(), 3);
assert_eq!(vec[0].real_part(), -5.257306234905137);
assert_eq!(vec[0].imag_part(), 7.212119776268775);
assert_eq!(vec[1].real_part(), -4.666248990558111);
assert_eq!(vec[1].imag_part(), 9.66047141517383);
assert_eq!(vec[2].real_part(), -9.04279551029691);
assert_eq!(vec[2].imag_part(), -1.026624649331671);
let mut rng2 = StdRng::from_seed(SEED);
let vec2: Vec<ComplexValidated> = new_random_vec(3, &dist, &mut rng2);
assert_eq!(vec, vec2);
}
}
mod hash_map_key_usage {
use super::*;
use rug::Float;
use std::collections::HashMap;
use try_create::TryNew;
const PRECISION: u32 = 128;
type RealRugValidated = RealRugStrictFinite<PRECISION>;
#[test]
fn test_rug_as_hashmap_key() {
let mut map = HashMap::new();
let key1 = RealRugValidated::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
let key2 = RealRugValidated::try_new(Float::with_val(PRECISION, 2.5)).unwrap();
map.insert(key1.clone(), "one_rug");
map.insert(key2.clone(), "two_point_five_rug");
assert_eq!(map.get(&key1), Some(&"one_rug"));
assert_eq!(map.len(), 2);
let old_value = map.insert(key1.clone(), "new_one_rug");
assert_eq!(old_value, Some("one_rug"));
assert_eq!(map.get(&key1), Some(&"new_one_rug"));
}
#[test]
fn test_hash_signed_zero() {
use crate::functions::Sign;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let val1 = RealRugValidated::try_new(Float::with_val(PRECISION, 0.0)).unwrap();
assert!(val1.kernel_is_sign_positive());
let val2 = RealRugValidated::try_new(Float::with_val(PRECISION, -0.0)).unwrap();
assert!(val2.kernel_is_sign_negative());
let mut hasher1 = DefaultHasher::new();
let mut hasher2 = DefaultHasher::new();
val1.hash(&mut hasher1);
val2.hash(&mut hasher2);
assert_eq!(hasher1.finish(), hasher2.finish());
assert_eq!(val1, val2); }
#[test]
fn test_complex_as_hashmap_key() {
use crate::ComplexRugStrictFinite;
type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
let mut map = HashMap::new();
let key1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
.unwrap();
let key2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (3.0, 4.0)))
.unwrap();
map.insert(key1.clone(), "one_plus_two_i_rug");
map.insert(key2.clone(), "three_plus_four_i_rug");
assert_eq!(map.get(&key1), Some(&"one_plus_two_i_rug"));
assert_eq!(map.len(), 2);
let old_value = map.insert(key1.clone(), "updated_complex_rug");
assert_eq!(old_value, Some("one_plus_two_i_rug"));
assert_eq!(map.get(&key1), Some(&"updated_complex_rug"));
}
#[test]
fn test_complex_hash_consistency() {
use crate::ComplexRugStrictFinite;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
let val1 =
ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.234, 5.678)))
.unwrap();
let val2 =
ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.234, 5.678)))
.unwrap();
let mut hasher1 = DefaultHasher::new();
let mut hasher2 = DefaultHasher::new();
val1.hash(&mut hasher1);
val2.hash(&mut hasher2);
assert_eq!(hasher1.finish(), hasher2.finish());
assert_eq!(val1, val2);
}
#[test]
fn test_complex_hash_signed_zero() {
use crate::ComplexRugStrictFinite;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
let val1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (0.0, 0.0)))
.unwrap();
let val2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (-0.0, 0.0)))
.unwrap();
let val3 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (0.0, -0.0)))
.unwrap();
let val4 =
ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (-0.0, -0.0)))
.unwrap();
assert_eq!(val1, val2);
assert_eq!(val1, val3);
assert_eq!(val1, val4);
let mut hasher1 = DefaultHasher::new();
let mut hasher2 = DefaultHasher::new();
let mut hasher3 = DefaultHasher::new();
let mut hasher4 = DefaultHasher::new();
val1.hash(&mut hasher1);
val2.hash(&mut hasher2);
val3.hash(&mut hasher3);
val4.hash(&mut hasher4);
let hash1 = hasher1.finish();
let hash2 = hasher2.finish();
let hash3 = hasher3.finish();
let hash4 = hasher4.finish();
assert_eq!(hash1, hash2);
assert_eq!(hash1, hash3);
assert_eq!(hash1, hash4);
}
#[test]
fn test_complex_hashset_operations() {
use crate::ComplexRugStrictFinite;
use std::collections::HashSet;
type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
let mut set = HashSet::new();
let val1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
.unwrap();
let val2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (3.0, 4.0)))
.unwrap();
let val1_duplicate =
ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
.unwrap();
assert!(set.insert(val1.clone()));
assert!(set.insert(val2.clone()));
assert!(!set.insert(val1_duplicate));
assert_eq!(set.len(), 2);
assert!(set.contains(&val1));
}
#[test]
fn test_complex_different_precision_different_hash() {
use crate::ComplexRugStrictFinite;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
const PRECISION_A: u32 = 64;
const PRECISION_B: u32 = 128;
let val1 = ComplexRugStrictFinite::<PRECISION_A>::try_new(rug::Complex::with_val(
PRECISION_A,
(1.0, 2.0),
))
.unwrap();
let val2 = ComplexRugStrictFinite::<PRECISION_B>::try_new(rug::Complex::with_val(
PRECISION_B,
(1.0, 2.0),
))
.unwrap();
let mut hasher1 = DefaultHasher::new();
let mut hasher2 = DefaultHasher::new();
val1.hash(&mut hasher1);
val2.hash(&mut hasher2);
let hash1 = hasher1.finish();
let hash2 = hasher2.finish();
assert_ne!(hash1, hash2);
}
}
mod rug_float {
mod from_f64 {
use crate::{RealRugStrictFinite, RealScalar};
const PRECISION: u32 = 100;
#[test]
fn test_from_f64_valid_constants() {
let pi = RealRugStrictFinite::<PRECISION>::from_f64(std::f64::consts::PI);
let pi_f64 = pi.as_ref().to_f64();
assert!((pi_f64 - std::f64::consts::PI).abs() < 1e-15);
let e = RealRugStrictFinite::<PRECISION>::from_f64(std::f64::consts::E);
let e_f64 = e.as_ref().to_f64();
assert!((e_f64 - std::f64::consts::E).abs() < 1e-15);
}
#[test]
fn test_from_f64_valid_simple_values() {
let x = RealRugStrictFinite::<PRECISION>::from_f64(42.0);
assert_eq!(x.as_ref().to_f64(), 42.0);
let y = RealRugStrictFinite::<PRECISION>::from_f64(-3.0);
assert_eq!(y.as_ref().to_f64(), -3.0);
let z = RealRugStrictFinite::<PRECISION>::from_f64(0.0);
assert_eq!(z.as_ref().to_f64(), 0.0);
}
#[test]
#[should_panic(expected = "RealScalar::from_f64() failed")]
fn test_from_f64_nan_panics() {
let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::NAN);
}
#[test]
#[should_panic(expected = "RealScalar::from_f64() failed")]
fn test_from_f64_infinity_panics() {
let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::INFINITY);
}
#[test]
#[should_panic(expected = "RealScalar::from_f64() failed")]
fn test_from_f64_neg_infinity_panics() {
let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::NEG_INFINITY);
}
#[test]
fn test_try_from_f64_exact_representation() {
use crate::core::errors::ErrorsTryFromf64;
assert!(
RealRugStrictFinite::<PRECISION>::try_from_f64(0.1).is_ok(),
"0.1 (as f64 approximation) should be accepted at 100-bit precision"
);
assert!(
RealRugStrictFinite::<PRECISION>::try_from_f64(0.3).is_ok(),
"0.3 (as f64 approximation) should be accepted at 100-bit precision"
);
assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).is_ok());
assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(2.5).is_ok());
assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).is_ok());
assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(f64::NAN).is_err());
assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(f64::INFINITY).is_err());
match RealRugStrictFinite::<52>::try_from_f64(0.5) {
Err(ErrorsTryFromf64::NonRepresentableExactly { precision, .. }) => {
assert_eq!(precision, 52, "Error should report precision 52");
}
_ => panic!("Should reject precision < 53"),
}
}
}
mod truncate_to_usize {
use crate::core::errors::ErrorsRawRealToInteger;
use crate::kernels::RawRealTrait;
use rug::Float;
const PRECISION: u32 = 128;
#[test]
fn test_rug_truncate_to_usize_valid() {
assert_eq!(
Float::with_val(PRECISION, 42.0)
.truncate_to_usize()
.unwrap(),
42
);
assert_eq!(
Float::with_val(PRECISION, 42.9)
.truncate_to_usize()
.unwrap(),
42
);
assert_eq!(
Float::with_val(PRECISION, 0.0).truncate_to_usize().unwrap(),
0
);
assert_eq!(
Float::with_val(PRECISION, usize::MAX)
.truncate_to_usize()
.unwrap(),
usize::MAX
);
}
#[test]
fn test_rug_truncate_to_usize_not_finite() {
assert!(matches!(
Float::with_val(PRECISION, f64::NAN).truncate_to_usize(),
Err(ErrorsRawRealToInteger::NotFinite { .. })
));
assert!(matches!(
Float::with_val(PRECISION, f64::INFINITY).truncate_to_usize(),
Err(ErrorsRawRealToInteger::NotFinite { .. })
));
assert!(matches!(
Float::with_val(PRECISION, f64::NEG_INFINITY).truncate_to_usize(),
Err(ErrorsRawRealToInteger::NotFinite { .. })
));
}
#[test]
fn test_rug_truncate_to_usize_out_of_range() {
assert!(matches!(
Float::with_val(PRECISION, -1.0).truncate_to_usize(),
Err(ErrorsRawRealToInteger::OutOfRange { .. })
));
let mut too_large = Float::with_val(PRECISION, usize::MAX);
too_large += 1;
assert!(matches!(
too_large.truncate_to_usize(),
Err(ErrorsRawRealToInteger::OutOfRange { .. })
));
}
}
}
mod truncate_to_usize {
use super::*;
use rug::Float;
use try_create::TryNew;
const PRECISION: u32 = 1000;
#[test]
fn test_positive_integers() {
let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 42.0))
.unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 42);
let value =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 1);
}
#[test]
fn test_positive_fractionals_truncate() {
let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 42.9))
.unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 42);
let value =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.9)).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 0);
}
#[test]
fn test_zero_cases() {
let value =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.0)).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 0);
}
#[test]
fn test_negative_values_error() {
let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
.unwrap();
let result = value.truncate_to_usize();
assert!(matches!(
result,
Err(ErrorsRawRealToInteger::OutOfRange { .. })
));
let value =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -10.5))
.unwrap();
let result = value.truncate_to_usize();
assert!(matches!(
result,
Err(ErrorsRawRealToInteger::OutOfRange { .. })
));
}
#[test]
fn test_large_values() {
let value =
RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1_000_000.0))
.unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 1_000_000);
let value = RealRugStrictFinite::<PRECISION>::try_new(
Float::with_val(PRECISION, 1e50), )
.unwrap();
let result = value.truncate_to_usize();
assert!(matches!(
result,
Err(ErrorsRawRealToInteger::OutOfRange { .. })
));
}
#[test]
fn test_high_precision_truncation() {
let value = RealRugStrictFinite::<PRECISION>::try_new(
Float::parse("42.99999999999999999999999999999")
.unwrap()
.complete(PRECISION),
)
.unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 42);
let value = RealRugStrictFinite::<PRECISION>::try_new(
Float::parse("0.99999999999999999999999999999")
.unwrap()
.complete(PRECISION),
)
.unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 0);
}
#[test]
fn test_conversion_from_f64() {
let value = RealRugStrictFinite::<PRECISION>::try_from_f64(42.7).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 42);
let value = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 0);
}
}
}