#![deny(rustdoc::broken_intra_doc_links)]
use crate::kernels::{
ComplexValidated, NumKernelStrictFinite, NumKernelStrictFiniteInDebug, RealValidated,
};
pub type Native64StrictFinite = NumKernelStrictFinite<f64, 53>;
pub type Native64StrictFiniteInDebug = NumKernelStrictFiniteInDebug<f64, 53>;
pub type RealNative64StrictFinite = RealValidated<Native64StrictFinite>;
pub type ComplexNative64StrictFinite = ComplexValidated<Native64StrictFinite>;
pub type RealNative64StrictFiniteInDebug = RealValidated<Native64StrictFiniteInDebug>;
pub type ComplexNative64StrictFiniteInDebug = ComplexValidated<Native64StrictFiniteInDebug>;
#[cfg(test)]
mod tests {
use super::*;
use crate::{
Clamp, ComplexScalarConstructors, ComplexScalarGetParts, ComplexScalarMutateParts,
ComplexScalarSetParts, Constants, ExpM1, FpChecks, Hypot, Ln1p, MulAddRef, RealScalar,
Rounding, Sign, TotalCmp,
core::errors::{ErrorsTryFromf64, ErrorsValidationRawComplex, ErrorsValidationRawReal},
functions::{
ACos, ACosH, ACosHErrors, ACosHInputErrors, ACosRealErrors, ACosRealInputErrors, ASin,
ASinH, ASinRealErrors, ASinRealInputErrors, ATan, ATan2, ATan2Errors,
ATanComplexErrors, ATanComplexInputErrors, ATanH, ATanHErrors, ATanHInputErrors, Abs,
Arg, Classify, Conjugate, Cos, CosH, Exp, ExpErrors, Ln, Log2, Log10,
LogarithmComplexErrors, LogarithmComplexInputErrors, Max, Min, NegAssign, Pow,
PowComplexBaseRealExponentErrors, PowIntExponentErrors, PowIntExponentInputErrors,
PowRealBaseRealExponentErrors, Reciprocal, ReciprocalErrors, Sin, SinH, Sqrt,
SqrtRealErrors, Tan, TanH,
},
};
use approx::assert_ulps_eq;
use num::{Complex, One, Zero};
use rand::RngExt;
use std::{
cmp::Ordering,
f64::consts::*,
num::FpCategory,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use try_create::{IntoInner, TryNew, TryNewValidated};
type RealValidated = RealNative64StrictFinite;
type ComplexValidated = ComplexNative64StrictFinite;
mod fp_checks {
use super::*;
#[test]
fn is_finite() {
let real = RealValidated::try_new(1.).unwrap();
assert!(real.is_finite());
let real = RealValidated::try_new(f64::INFINITY);
assert!(real.is_err());
let complex = ComplexValidated::try_new(Complex::new(1., 1.)).unwrap();
assert!(complex.is_finite());
let complex = ComplexValidated::try_new(Complex::new(f64::INFINITY, 1.));
assert!(complex.is_err());
}
#[test]
fn is_infinite() {
let real = RealValidated::try_new(1.).unwrap();
assert!(!real.is_infinite());
let real = RealValidated::try_new(f64::INFINITY);
assert!(real.is_err());
let complex = ComplexValidated::try_new(Complex::new(1., 1.)).unwrap();
assert!(!complex.is_infinite());
let complex = ComplexValidated::try_new(Complex::new(f64::INFINITY, 1.));
assert!(complex.is_err());
}
#[test]
fn is_nan() {
let real = RealValidated::try_new(1.).unwrap();
assert!(!real.is_nan());
let real = RealValidated::try_new(f64::NAN);
assert!(matches!(real, Err(ErrorsValidationRawReal::IsNaN { .. })));
let complex = ComplexValidated::try_new(Complex::new(1., 1.)).unwrap();
assert!(!complex.is_nan());
let complex = ComplexValidated::try_new(Complex::new(f64::NAN, 1.));
assert!(matches!(
complex,
Err(ErrorsValidationRawComplex::InvalidRealPart {
source: box ErrorsValidationRawReal::IsNaN { .. },
})
));
}
#[test]
fn is_normal() {
let real = RealValidated::try_new(1.).unwrap();
assert!(real.is_normal());
let real = RealValidated::try_new(0.).unwrap();
assert!(!real.is_normal());
let complex = ComplexValidated::try_new(Complex::new(1., 1.)).unwrap();
assert!(complex.is_normal());
let complex = ComplexValidated::try_new(Complex::new(0., 0.)).unwrap();
assert!(!complex.is_normal());
}
}
mod new_unchecked {
use super::*;
mod real {
use super::*;
#[test]
fn new_unchecked_valid_value() {
let x = unsafe { RealValidated::new_unchecked(3.) };
assert_eq!(*x.as_ref(), 3.);
}
#[test]
fn new_unchecked_zero() {
let x = unsafe { RealValidated::new_unchecked(0.0) };
assert!(x.is_zero());
}
#[test]
fn new_unchecked_negative() {
let x = unsafe { RealValidated::new_unchecked(-42.5) };
assert_eq!(*x.as_ref(), -42.5);
}
#[test]
fn new_unchecked_large_value() {
let x = unsafe { RealValidated::new_unchecked(f64::MAX) };
assert_eq!(*x.as_ref(), f64::MAX);
}
#[test]
fn new_unchecked_small_value() {
let x = unsafe { RealValidated::new_unchecked(f64::MIN) };
assert_eq!(*x.as_ref(), f64::MIN);
}
#[test]
fn new_unchecked_epsilon() {
let x = unsafe { RealValidated::new_unchecked(f64::EPSILON) };
assert_eq!(*x.as_ref(), f64::EPSILON);
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "new_unchecked() validation failed in debug mode")]
fn new_unchecked_nan_panics_in_debug() {
let _ = unsafe { RealValidated::new_unchecked(f64::NAN) };
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "new_unchecked() validation failed in debug mode")]
fn new_unchecked_infinity_panics_in_debug() {
let _ = unsafe { RealValidated::new_unchecked(f64::INFINITY) };
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "new_unchecked() validation failed in debug mode")]
fn new_unchecked_neg_infinity_panics_in_debug() {
let _ = unsafe { RealValidated::new_unchecked(f64::NEG_INFINITY) };
}
}
mod complex {
use super::*;
#[test]
fn new_unchecked_valid_value() {
let z = unsafe { ComplexValidated::new_unchecked(Complex::new(1.0, 2.0)) };
assert_eq!(z.real_part().into_inner(), 1.0);
assert_eq!(z.imag_part().into_inner(), 2.0);
}
#[test]
fn new_unchecked_zero() {
let z = unsafe { ComplexValidated::new_unchecked(Complex::new(0.0, 0.0)) };
assert!(z.is_zero());
}
#[test]
fn new_unchecked_real_only() {
let z = unsafe { ComplexValidated::new_unchecked(Complex::new(5.0, 0.0)) };
assert_eq!(z.real_part().into_inner(), 5.0);
assert_eq!(z.imag_part().into_inner(), 0.0);
}
#[test]
fn new_unchecked_imaginary_only() {
let z = unsafe { ComplexValidated::new_unchecked(Complex::new(0.0, -3.0)) };
assert_eq!(z.real_part().into_inner(), 0.0);
assert_eq!(z.imag_part().into_inner(), -3.0);
}
#[test]
fn new_unchecked_negative_components() {
let z = unsafe { ComplexValidated::new_unchecked(Complex::new(-1.5, -2.5)) };
assert_eq!(z.real_part().into_inner(), -1.5);
assert_eq!(z.imag_part().into_inner(), -2.5);
}
#[test]
fn new_unchecked_preserves_value_in_arithmetic() {
let a = unsafe { ComplexValidated::new_unchecked(Complex::new(1.0, 2.0)) };
let b = unsafe { ComplexValidated::new_unchecked(Complex::new(3.0, 4.0)) };
let sum = a + b;
assert_eq!(sum.real_part().into_inner(), 4.0);
assert_eq!(sum.imag_part().into_inner(), 6.0);
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "new_unchecked() validation failed in debug mode")]
fn new_unchecked_nan_real_part_panics_in_debug() {
let _ = unsafe { ComplexValidated::new_unchecked(Complex::new(f64::NAN, 1.0)) };
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "new_unchecked() validation failed in debug mode")]
fn new_unchecked_nan_imag_part_panics_in_debug() {
let _ = unsafe { ComplexValidated::new_unchecked(Complex::new(1.0, f64::NAN)) };
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "new_unchecked() validation failed in debug mode")]
fn new_unchecked_infinity_real_part_panics_in_debug() {
let _ =
unsafe { ComplexValidated::new_unchecked(Complex::new(f64::INFINITY, 1.0)) };
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "new_unchecked() validation failed in debug mode")]
fn new_unchecked_infinity_imag_part_panics_in_debug() {
let _ =
unsafe { ComplexValidated::new_unchecked(Complex::new(1.0, f64::INFINITY)) };
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "new_unchecked() validation failed in debug mode")]
fn new_unchecked_neg_infinity_panics_in_debug() {
let _ = unsafe {
ComplexValidated::new_unchecked(Complex::new(
f64::NEG_INFINITY,
f64::NEG_INFINITY,
))
};
}
}
}
mod abs {
use super::*;
mod real {
use super::*;
#[test]
fn abs_valid() {
let value = RealValidated::try_new(-4.).unwrap();
let expected_result = RealValidated::try_new(4.).unwrap();
assert_eq!(value.try_abs().unwrap(), expected_result);
assert_eq!(value.abs(), expected_result);
}
#[test]
fn abs_zero() {
let value = RealValidated::try_new(0.).unwrap();
let expected_result = RealValidated::try_new(0.).unwrap();
assert_eq!(value.try_abs().unwrap(), expected_result);
assert_eq!(value.abs(), expected_result);
}
}
mod complex {
use super::*;
#[test]
fn abs_valid() {
let value = ComplexValidated::try_new(Complex::new(3., 4.)).unwrap();
let expected_result = RealValidated::try_new(5.).unwrap();
assert_eq!(value.try_abs().unwrap(), expected_result);
assert_eq!(value.abs(), expected_result);
}
#[test]
fn abs_zero() {
let value = ComplexValidated::try_new(Complex::new(0., 0.)).unwrap();
let expected_result = RealValidated::try_new(0.).unwrap();
assert_eq!(value.try_abs().unwrap(), expected_result);
assert_eq!(value.abs(), expected_result);
}
}
}
mod builders {
use super::*;
mod real {
use super::*;
#[test]
fn into_inner() {
let value = RealValidated::try_new(1.23).unwrap();
assert_eq!(value.into_inner(), 1.23);
}
#[test]
fn new() {
let value = RealValidated::try_new(1.23).unwrap();
assert_eq!(value, 1.23);
}
#[test]
fn try_new_nan() {
let err = RealValidated::try_new(f64::NAN).unwrap_err();
assert!(matches!(err, ErrorsValidationRawReal::IsNaN { .. }));
}
#[test]
fn try_new_pos_infinity() {
let err = RealValidated::try_new(f64::INFINITY).unwrap_err();
assert!(matches!(err, ErrorsValidationRawReal::IsPosInfinity { .. }));
}
#[test]
fn try_new_neg_infinity() {
let err = RealValidated::try_new(f64::NEG_INFINITY).unwrap_err();
assert!(matches!(err, ErrorsValidationRawReal::IsNegInfinity { .. }));
}
}
mod complex {
use super::*;
#[test]
fn into_inner() {
let v = Complex::new(1., 2.);
let value = ComplexValidated::try_new(v).unwrap();
assert_eq!(value.into_inner(), v);
}
#[test]
fn new() {
let v = Complex::new(1., 2.);
let value = ComplexValidated::try_new(v).unwrap();
assert_eq!(value.into_inner(), v);
}
#[test]
fn real_part() {
let c1 = ComplexValidated::try_new_validated(Complex::new(1.23, 4.56)).unwrap();
assert_eq!(c1.real_part(), 1.23);
let c2 = ComplexValidated::try_new_validated(Complex::new(-7.89, 0.12)).unwrap();
assert_eq!(c2.real_part(), -7.89);
let c3 = ComplexValidated::try_new_validated(Complex::new(0., 10.)).unwrap();
assert_eq!(c3.real_part(), 0.);
let c_nan_re =
ComplexValidated::try_new_validated(Complex::new(f64::NAN, 5.)).unwrap_err();
assert!(matches!(
c_nan_re,
ErrorsValidationRawComplex::InvalidRealPart {
source: box ErrorsValidationRawReal::IsNaN { .. }
}
));
let c_inf_re = ComplexValidated::try_new_validated(Complex::new(f64::INFINITY, 5.))
.unwrap_err();
assert!(matches!(
c_inf_re,
ErrorsValidationRawComplex::InvalidRealPart {
source: box ErrorsValidationRawReal::IsPosInfinity { .. }
}
));
let c_neg_inf_re =
ComplexValidated::try_new_validated(Complex::new(f64::NEG_INFINITY, 5.))
.unwrap_err();
assert!(matches!(
c_neg_inf_re,
ErrorsValidationRawComplex::InvalidRealPart {
source: box ErrorsValidationRawReal::IsNegInfinity { .. }
}
));
}
#[test]
fn imag_part() {
let c1 = ComplexValidated::try_new_validated(Complex::new(1.23, 4.56)).unwrap();
assert_eq!(c1.imag_part(), 4.56);
let c2 = ComplexValidated::try_new_validated(Complex::new(-7.89, 0.12)).unwrap();
assert_eq!(c2.imag_part(), 0.12);
let c3 = ComplexValidated::try_new_validated(Complex::new(10., 0.)).unwrap();
assert_eq!(c3.imag_part(), 0.);
let c_nan_im =
ComplexValidated::try_new_validated(Complex::new(5., f64::NAN)).unwrap_err();
assert!(matches!(
c_nan_im,
ErrorsValidationRawComplex::InvalidImaginaryPart {
source: box ErrorsValidationRawReal::IsNaN { .. }
}
));
let c_inf_im = ComplexValidated::try_new_validated(Complex::new(5., f64::INFINITY))
.unwrap_err();
assert!(matches!(
c_inf_im,
ErrorsValidationRawComplex::InvalidImaginaryPart {
source: box ErrorsValidationRawReal::IsPosInfinity { .. }
}
));
let c_neg_inf_im =
ComplexValidated::try_new_validated(Complex::new(5., f64::NEG_INFINITY))
.unwrap_err();
assert!(matches!(
c_neg_inf_im,
ErrorsValidationRawComplex::InvalidImaginaryPart {
source: box ErrorsValidationRawReal::IsNegInfinity { .. }
}
));
}
#[test]
fn try_new_complex() {
let r1 = RealValidated::try_new(1.23).unwrap();
let i1 = RealValidated::try_new(4.56).unwrap();
let c1 = ComplexValidated::try_new_complex(*r1.as_ref(), *i1.as_ref()).unwrap();
assert_eq!(c1.real_part(), r1);
assert_eq!(c1.imag_part(), i1);
let r2 = RealValidated::try_new(-7.89).unwrap();
let i2 = RealValidated::try_new(-0.12).unwrap();
let c2 = ComplexValidated::try_new_complex(*r2.as_ref(), *i2.as_ref()).unwrap();
assert_eq!(c2.real_part(), r2);
assert_eq!(c2.imag_part(), i2);
let r3 = RealValidated::try_new(0.).unwrap();
let i3 = RealValidated::try_new(0.).unwrap();
let c3 = ComplexValidated::try_new_complex(*r3.as_ref(), *i3.as_ref()).unwrap();
assert_eq!(c3.real_part(), r3);
assert_eq!(c3.real_part(), i3);
assert!(c3.is_zero());
let c_nan_re = ComplexValidated::try_new_complex(f64::NAN, 5.).unwrap_err();
assert!(matches!(
c_nan_re,
ErrorsValidationRawComplex::InvalidRealPart { .. }
));
let c_inf_im = ComplexValidated::try_new_complex(10., f64::INFINITY).unwrap_err();
assert!(matches!(
c_inf_im,
ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
));
let c_nan_re_inf_im =
ComplexValidated::try_new_complex(f64::NAN, f64::INFINITY).unwrap_err();
assert!(matches!(
c_nan_re_inf_im,
ErrorsValidationRawComplex::InvalidBothParts { .. }
));
}
#[test]
fn try_new_pure_real() {
let r1 = RealValidated::try_new(1.23).unwrap();
let c1 = ComplexValidated::try_new_pure_real(*r1.as_ref()).unwrap();
assert_eq!(c1.real_part(), r1);
assert!(c1.imag_part().is_zero());
let c_nan = ComplexValidated::try_new_pure_real(f64::NAN).unwrap_err();
assert!(matches!(
c_nan,
ErrorsValidationRawComplex::InvalidRealPart {
source: box ErrorsValidationRawReal::IsNaN { .. }
}
));
}
#[test]
fn try_new_pure_imaginary() {
let i1 = RealValidated::try_new(1.23).unwrap();
let c1 = ComplexValidated::try_new_pure_imaginary(*i1.as_ref()).unwrap();
assert!(c1.real_part().is_zero());
assert_eq!(c1.imag_part(), i1);
let c_nan = ComplexValidated::try_new_pure_imaginary(f64::NAN).unwrap_err();
assert!(matches!(
c_nan,
ErrorsValidationRawComplex::InvalidImaginaryPart {
source: box ErrorsValidationRawReal::IsNaN { .. }
}
));
}
#[test]
fn add_to_real_part() {
let mut c = ComplexValidated::try_new_validated(Complex::new(1., 2.)).unwrap();
c.add_to_real_part(&RealValidated::try_new(3.).unwrap());
assert_eq!(c.real_part(), 4.);
assert_eq!(c.imag_part(), 2.);
c.add_to_real_part(&RealValidated::try_new(-5.).unwrap());
assert_eq!(c.real_part(), -1.);
assert_eq!(c.imag_part(), 2.);
}
#[test]
fn add_to_imaginary_part() {
let mut c = ComplexValidated::try_new_validated(Complex::new(1., 2.)).unwrap();
c.add_to_imaginary_part(&RealValidated::try_new(3.).unwrap());
assert_eq!(c.real_part(), 1.);
assert_eq!(c.imag_part(), 5.);
c.add_to_imaginary_part(&RealValidated::try_new(-4.).unwrap());
assert_eq!(c.real_part(), 1.);
assert_eq!(c.imag_part(), 1.);
}
#[test]
fn multiply_real_part() {
let mut c = ComplexValidated::try_new_validated(Complex::new(1., 2.)).unwrap();
c.multiply_real_part(&RealValidated::try_new(3.).unwrap());
assert_eq!(c.real_part(), 3.);
assert_eq!(c.imag_part(), 2.);
c.multiply_real_part(&RealValidated::try_new(-2.).unwrap());
assert_eq!(c.real_part(), -6.);
assert_eq!(c.imag_part(), 2.);
}
#[test]
fn multiply_imaginary_part() {
let mut c = ComplexValidated::try_new_validated(Complex::new(1., 2.)).unwrap();
c.multiply_imaginary_part(&RealValidated::try_new(3.).unwrap());
assert_eq!(c.real_part(), 1.);
assert_eq!(c.imag_part(), 6.);
c.multiply_imaginary_part(&RealValidated::try_new(-0.5).unwrap());
assert_eq!(c.real_part(), 1.);
assert_eq!(c.imag_part(), -3.);
}
#[test]
fn set_real_part() {
let mut c = ComplexValidated::try_new_validated(Complex::new(1., 2.)).unwrap();
c.set_real_part(RealValidated::try_new(3.).unwrap());
assert_eq!(c.real_part(), 3.);
assert_eq!(c.imag_part(), 2.);
c.set_real_part(RealValidated::try_new(-4.).unwrap());
assert_eq!(c.real_part(), -4.);
assert_eq!(c.imag_part(), 2.);
}
#[test]
fn set_imaginary_part() {
let mut c = ComplexValidated::try_new_validated(Complex::new(1., 2.)).unwrap();
c.set_imaginary_part(RealValidated::try_new(3.).unwrap());
assert_eq!(c.real_part(), 1.);
assert_eq!(c.imag_part(), 3.);
c.set_imaginary_part(RealValidated::try_new(-4.).unwrap());
assert_eq!(c.real_part(), 1.);
assert_eq!(c.imag_part(), -4.);
}
}
}
mod mul {
use super::*;
mod real {
use super::*;
#[test]
fn multiply_ref() {
let r1 = RealValidated::try_new_validated(3.).unwrap();
let r2 = RealValidated::try_new_validated(4.).unwrap();
let result = r1 * r2;
assert_eq!(result, RealValidated::try_new_validated(12.).unwrap());
}
}
mod complex {
use super::*;
#[test]
fn multiply_ref() {
let c1 = ComplexValidated::try_new_validated(Complex::new(1., 2.)).unwrap();
let c2 = ComplexValidated::try_new_validated(Complex::new(3., 4.)).unwrap();
let result = c1 * c2;
assert_eq!(
result,
ComplexValidated::try_new_validated(Complex::new(-5., 10.)).unwrap()
); }
#[test]
fn complex_times_real() {
let r = RealValidated::try_new_validated(2.).unwrap();
let c = ComplexValidated::try_new_validated(Complex::new(3., 4.)).unwrap();
let result_expected =
ComplexValidated::try_new_validated(Complex::new(6., 8.)).unwrap();
let result = c * r;
assert_eq!(&result, &result_expected);
let result = c * r;
assert_eq!(&result, &result_expected);
let mut result = c;
result *= &r;
assert_eq!(&result, &result_expected);
let mut result = c;
result *= r;
assert_eq!(&result, &result_expected);
}
#[test]
fn real_times_complex() {
let r = RealValidated::try_new_validated(2.).unwrap();
let c = ComplexValidated::try_new_validated(Complex::new(3., 4.)).unwrap();
let result_expected =
ComplexValidated::try_new_validated(Complex::new(6., 8.)).unwrap();
let result = r * c;
assert_eq!(&result, &result_expected);
}
}
}
mod arithmetic {
use super::*;
mod real {
use super::*;
#[test]
fn add() {
let r1 = RealValidated::try_new_validated(3.).unwrap();
let r2 = RealValidated::try_new_validated(4.).unwrap();
let expected_result = RealValidated::try_new_validated(7.).unwrap();
let result = r1.add(&r2);
assert_eq!(result, expected_result);
let result = r1.add(r2);
assert_eq!(result, expected_result);
let result = (&r1).add(r2);
assert_eq!(result, expected_result);
let result = (&r1).add(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.add_assign(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.add_assign(r2);
assert_eq!(result, expected_result);
}
#[test]
fn sub() {
let r1 = RealValidated::try_new_validated(3.).unwrap();
let r2 = RealValidated::try_new_validated(4.).unwrap();
let expected_result = RealValidated::try_new_validated(-1.).unwrap();
let result = r1.sub(&r2);
assert_eq!(result, expected_result);
let result = r1.sub(r2);
assert_eq!(result, expected_result);
let result = (&r1).sub(r2);
assert_eq!(result, expected_result);
let result = (&r1).sub(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.sub_assign(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.sub_assign(r2);
assert_eq!(result, expected_result);
}
#[test]
fn mul() {
let r1 = RealValidated::try_new_validated(3.).unwrap();
let r2 = RealValidated::try_new_validated(4.).unwrap();
let expected_result = RealValidated::try_new_validated(12.).unwrap();
let result = r1.mul(&r2);
assert_eq!(result, expected_result);
let result = r1.mul(r2);
assert_eq!(result, expected_result);
let result = (&r1).mul(r2);
assert_eq!(result, expected_result);
let result = (&r1).mul(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.mul_assign(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.mul_assign(r2);
assert_eq!(result, expected_result);
}
#[test]
fn div() {
let r1 = RealValidated::try_new_validated(3.).unwrap();
let r2 = RealValidated::try_new_validated(4.).unwrap();
let expected_result = RealValidated::try_new_validated(0.75).unwrap();
let result = r1.div(&r2);
assert_eq!(result, expected_result);
let result = r1.div(r2);
assert_eq!(result, expected_result);
let result = (&r1).div(r2);
assert_eq!(result, expected_result);
let result = (&r1).div(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.div_assign(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.div_assign(r2);
assert_eq!(result, expected_result);
}
#[test]
fn neg() {
let num = RealValidated::try_new_validated(1.).unwrap();
let expected = RealValidated::try_new_validated(-1.).unwrap();
assert_eq!(num.neg(), expected);
}
#[test]
fn neg_assign() {
let mut num = 1.;
num.neg_assign();
let expected = -1.;
assert_eq!(&num, &expected);
let mut num = RealValidated::one();
num.neg_assign();
let expected = RealValidated::try_new_validated(-1.).unwrap();
assert_eq!(&num, &expected);
}
#[test]
#[should_panic(expected = "Division failed validation")]
fn div_by_zero() {
let one = RealValidated::one();
let zero = RealValidated::zero();
let _ = one / zero;
}
#[test]
#[should_panic(expected = "Division failed validation")]
fn div_assign_by_zero() {
let mut num = RealValidated::one();
let zero_ref = &RealValidated::zero();
num /= zero_ref;
}
#[test]
fn mul_add() {
let a = RealValidated::try_new(2.0).unwrap();
let b = RealValidated::try_new(3.0).unwrap();
let c = RealValidated::try_new(4.0).unwrap();
assert_eq!(a.mul_add_ref(&b, &c), RealValidated::try_new(10.0).unwrap());
}
}
mod complex {
use super::*;
#[test]
fn add() {
let r1 = ComplexValidated::try_new_validated(Complex::new(2., 3.)).unwrap();
let r2 = ComplexValidated::try_new_validated(Complex::new(4., -4.)).unwrap();
let expected_result =
ComplexValidated::try_new_validated(Complex::new(6., -1.)).unwrap();
let result = r1.add(&r2);
assert_eq!(result, expected_result);
let result = r1.add(r2);
assert_eq!(result, expected_result);
let result = (&r1).add(r2);
assert_eq!(result, expected_result);
let result = (&r1).add(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.add_assign(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.add_assign(r2);
assert_eq!(result, expected_result);
}
#[test]
fn sub() {
let r1 = ComplexValidated::try_new_validated(Complex::new(2., 3.)).unwrap();
let r2 = ComplexValidated::try_new_validated(Complex::new(4., -4.)).unwrap();
let expected_result =
ComplexValidated::try_new_validated(Complex::new(-2., 7.)).unwrap();
let result = r1.sub(&r2);
assert_eq!(result, expected_result);
let result = r1.sub(r2);
assert_eq!(result, expected_result);
let result = (&r1).sub(r2);
assert_eq!(result, expected_result);
let result = (&r1).sub(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.sub_assign(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.sub_assign(r2);
assert_eq!(result, expected_result);
}
#[test]
fn mul() {
let r1 = ComplexValidated::try_new_validated(Complex::new(2., 3.)).unwrap();
let r2 = ComplexValidated::try_new_validated(Complex::new(4., -4.)).unwrap();
let expected_result =
ComplexValidated::try_new_validated(Complex::new(20., 4.)).unwrap();
let result = r1.mul(&r2);
assert_eq!(result, expected_result);
let result = r1.mul(r2);
assert_eq!(result, expected_result);
let result = (&r1).mul(r2);
assert_eq!(result, expected_result);
let result = (&r1).mul(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.mul_assign(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.mul_assign(r2);
assert_eq!(result, expected_result);
}
#[test]
fn div() {
let r1 = ComplexValidated::try_new_validated(Complex::new(2., 3.)).unwrap();
let r2 = ComplexValidated::try_new_validated(Complex::new(4., -4.)).unwrap();
let expected_result =
ComplexValidated::try_new_validated(Complex::new(-0.125, 0.625)).unwrap();
let result = r1.div(&r2);
assert_eq!(result, expected_result);
let result = r1.div(r2);
assert_eq!(result, expected_result);
let result = (&r1).div(r2);
assert_eq!(result, expected_result);
let result = (&r1).div(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.div_assign(&r2);
assert_eq!(result, expected_result);
let mut result = r1;
result.div_assign(r2);
assert_eq!(result, expected_result);
}
#[test]
fn neg() {
let v = Complex::new(1., 2.);
let num = ComplexValidated::try_new_validated(v).unwrap();
let expected = Complex::new(-1., -2.);
assert_eq!(num.neg().into_inner(), expected);
}
#[test]
fn neg_assign() {
let v = Complex::new(1., 2.);
let mut num = ComplexValidated::try_new_validated(v).unwrap();
let expected = Complex::new(-1., -2.);
num.neg_assign();
assert_eq!(num.as_ref(), &expected);
}
#[test]
#[should_panic(expected = "Division failed validation")]
fn div_by_zero() {
let one = ComplexValidated::one();
let zero = ComplexValidated::zero();
let _ = one / zero;
}
#[test]
#[should_panic(expected = "Division failed validation")]
fn div_assign_by_zero() {
let mut num = ComplexValidated::one();
let zero_ref = &ComplexValidated::zero();
num /= zero_ref;
}
#[test]
fn mul_add() {
let ca = ComplexValidated::try_new(Complex::new(1.0, 2.0)).unwrap();
let cb = ComplexValidated::try_new(Complex::new(3.0, 4.0)).unwrap();
let cc = ComplexValidated::try_new(Complex::new(5.0, 6.0)).unwrap();
let expected = ComplexValidated::try_new(Complex::new(0.0, 16.0)).unwrap();
assert_eq!(ca.mul_add_ref(&cb, &cc), expected);
}
}
}
mod real_scalar_methods {
use super::*;
#[test]
fn test_constants() {
assert_eq!(<RealValidated as Constants>::epsilon(), f64::EPSILON);
assert_eq!(<RealValidated as Constants>::negative_one(), -1.0);
assert_eq!(<RealValidated as Constants>::one_div_2(), 0.5);
assert_eq!(<RealValidated as Constants>::two(), 2.0);
assert_eq!(<RealValidated as Constants>::max_finite(), f64::MAX);
assert_eq!(<RealValidated as Constants>::min_finite(), f64::MIN);
assert_eq!(<RealValidated as Constants>::pi(), std::f64::consts::PI);
assert_eq!(
<RealValidated as Constants>::two_pi(),
std::f64::consts::PI * 2.0
);
assert_eq!(
<RealValidated as Constants>::pi_div_2(),
std::f64::consts::FRAC_PI_2
);
assert_eq!(<RealValidated as Constants>::ln_2(), std::f64::consts::LN_2);
assert_eq!(
<RealValidated as Constants>::ln_10(),
std::f64::consts::LN_10
);
assert_eq!(
<RealValidated as Constants>::log10_2(),
std::f64::consts::LOG10_2
);
assert_eq!(
<RealValidated as Constants>::log2_10(),
std::f64::consts::LOG2_10
);
assert_eq!(
<RealValidated as Constants>::log2_e(),
std::f64::consts::LOG2_E
);
assert_eq!(
<RealValidated as Constants>::log10_e(),
std::f64::consts::LOG10_E
);
assert_eq!(<RealValidated as Constants>::e(), std::f64::consts::E);
}
#[test]
fn round_ties_even() {
let f = RealValidated::try_new(3.3).unwrap();
let g = RealValidated::try_new(-3.3).unwrap();
let h = RealValidated::try_new(3.5).unwrap();
let i = RealValidated::try_new(4.5).unwrap();
let j = RealValidated::try_new(-3.5).unwrap();
let k = RealValidated::try_new(-4.5).unwrap();
assert_eq!(
f.kernel_round_ties_even(),
RealValidated::try_new(3.0).unwrap()
);
assert_eq!(
g.kernel_round_ties_even(),
RealValidated::try_new(-3.0).unwrap()
);
assert_eq!(
h.kernel_round_ties_even(),
RealValidated::try_new(4.0).unwrap()
);
assert_eq!(
i.kernel_round_ties_even(),
RealValidated::try_new(4.0).unwrap()
);
assert_eq!(
j.kernel_round_ties_even(),
RealValidated::try_new(-4.0).unwrap()
);
assert_eq!(
k.kernel_round_ties_even(),
RealValidated::try_new(-4.0).unwrap()
);
}
#[test]
fn classify() {
let normal = RealValidated::try_new(1.0).unwrap();
assert_eq!(normal.classify(), FpCategory::Normal);
let zero = RealValidated::zero();
assert_eq!(zero.classify(), FpCategory::Zero);
let subnormal_err = RealValidated::try_new(f64::MIN_POSITIVE / 2.).unwrap_err();
assert!(matches!(
subnormal_err,
ErrorsValidationRawReal::IsSubnormal { .. }
));
let pos_inf_err = RealValidated::try_new(f64::INFINITY).unwrap_err();
assert!(matches!(
pos_inf_err,
ErrorsValidationRawReal::IsPosInfinity { .. }
));
let neg_inf_err = RealValidated::try_new(f64::NEG_INFINITY).unwrap_err();
assert!(matches!(
neg_inf_err,
ErrorsValidationRawReal::IsNegInfinity { .. }
));
let nan_err = RealValidated::try_new(f64::NAN).unwrap_err();
assert!(matches!(nan_err, ErrorsValidationRawReal::IsNaN { .. }));
}
#[test]
fn try_from_f64_valid() {
let val = RealValidated::try_from_f64(123.45).unwrap();
assert_eq!(val.as_ref(), &123.45);
}
#[test]
fn try_from_f64_invalid() {
let err = RealValidated::try_from_f64(f64::NAN).unwrap_err();
assert!(matches!(
err,
ErrorsTryFromf64::Output {
source: ErrorsValidationRawReal::IsNaN { .. }
}
));
}
#[test]
fn rounding_and_trunc() {
let val1 = RealValidated::try_new(3.7).unwrap();
let val2 = RealValidated::try_new(-3.7).unwrap();
assert_eq!(val1.kernel_ceil(), RealValidated::try_new(4.0).unwrap());
assert_eq!(val2.kernel_ceil(), RealValidated::try_new(-3.0).unwrap());
assert_eq!(val1.kernel_floor(), RealValidated::try_new(3.0).unwrap());
assert_eq!(val2.kernel_floor(), RealValidated::try_new(-4.0).unwrap());
assert_eq!(val1.kernel_round(), RealValidated::try_new(4.0).unwrap());
assert_eq!(val2.kernel_round(), RealValidated::try_new(-4.0).unwrap());
assert_eq!(val1.kernel_trunc(), RealValidated::try_new(3.0).unwrap());
assert_eq!(val2.kernel_trunc(), RealValidated::try_new(-3.0).unwrap());
let frac1 = val1.kernel_fract();
assert!((frac1.as_ref() - 0.7).abs() < 1e-9);
let frac2 = val2.kernel_fract();
assert!((frac2.as_ref() - (-0.7)).abs() < 1e-9);
}
#[test]
fn sign_and_constants() {
let pos = RealValidated::try_new(5.0).unwrap();
let neg = RealValidated::try_new(-5.0).unwrap();
let zero = RealValidated::zero();
assert!(pos.kernel_is_sign_positive());
assert!(!pos.kernel_is_sign_negative());
assert!(!neg.kernel_is_sign_positive());
assert!(neg.kernel_is_sign_negative());
assert!(zero.kernel_is_sign_positive()); assert!(!zero.kernel_is_sign_negative());
let neg_zero = RealValidated::try_new(-0.0).unwrap();
assert!(!neg_zero.kernel_is_sign_positive());
assert!(neg_zero.kernel_is_sign_negative());
assert_eq!(pos.kernel_copysign(&neg), neg);
assert_eq!(neg.kernel_copysign(&pos), pos);
assert_eq!(
RealValidated::one_div_2(),
RealValidated::try_new(0.5).unwrap()
);
assert_eq!(RealValidated::two(), RealValidated::try_new(2.0).unwrap());
assert_eq!(
RealValidated::max_finite(),
RealValidated::try_new(f64::MAX).unwrap()
);
assert_eq!(
RealValidated::min_finite(),
RealValidated::try_new(f64::MIN).unwrap()
);
}
#[test]
fn epsilon() {
let eps = RealValidated::epsilon();
assert!(eps.is_finite() && eps > RealValidated::zero());
let expected_eps_val = 2.0f64.pow(-52);
let expected_eps = RealValidated::try_new(expected_eps_val).unwrap();
assert_eq!(eps, expected_eps, "Epsilon value mismatch");
}
#[test]
fn clamp_ref() {
let val = RealValidated::try_new(5.).unwrap();
let min_val = RealValidated::try_new(0.).unwrap();
let max_val = RealValidated::try_new(10.).unwrap();
assert_eq!(val.clamp_ref(&min_val, &max_val), val);
assert_eq!(
RealValidated::try_new(-5.)
.unwrap()
.clamp_ref(&min_val, &max_val),
min_val
);
assert_eq!(
RealValidated::try_new(15.)
.unwrap()
.clamp_ref(&min_val, &max_val),
max_val
);
}
#[test]
fn hypot() {
let a = RealValidated::try_new(3.).unwrap();
let b = RealValidated::try_new(4.).unwrap();
let expected = RealValidated::try_new(5.).unwrap();
assert_eq!(a.hypot(&b), expected);
}
#[test]
fn signum() {
assert_eq!(
RealValidated::try_new(5.).unwrap().kernel_signum(),
RealValidated::one()
);
assert_eq!(
RealValidated::try_new(-5.).unwrap().kernel_signum(),
RealValidated::negative_one()
);
assert_eq!(RealValidated::zero().kernel_signum(), RealValidated::one());
}
#[test]
fn total_cmp() {
let r1 = RealValidated::try_new(1.).unwrap();
let r2 = RealValidated::try_new(2.).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 = RealValidated::try_new(2.).unwrap();
let b = RealValidated::try_new(3.).unwrap(); let c = RealValidated::try_new(4.).unwrap(); let d = RealValidated::try_new(5.).unwrap(); a.kernel_mul_add_mul_mut(&b, &c, &d);
assert_eq!(a, RealValidated::try_new(26.).unwrap());
}
#[test]
fn mul_sub_mul_mut() {
let mut a = RealValidated::try_new(10.).unwrap();
let b = RealValidated::try_new(2.).unwrap(); let c = RealValidated::try_new(3.).unwrap(); let d = RealValidated::try_new(4.).unwrap(); a.kernel_mul_sub_mul_mut(&b, &c, &d);
assert_eq!(a, RealValidated::try_new(8.).unwrap());
}
}
mod complex_scalar_methods {
use super::*;
use crate::functions::{ArgErrors, ArgInputErrors};
#[test]
fn conjugate() {
let c = ComplexValidated::try_new(Complex::new(1., 2.)).unwrap();
let expected = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
assert_eq!(c.conjugate(), expected);
let c_real = ComplexValidated::try_new_pure_real(5.).unwrap();
assert_eq!(c_real.conjugate(), c_real);
let c_imag = ComplexValidated::try_new_pure_imaginary(3.).unwrap();
let expected_imag = ComplexValidated::try_new_pure_imaginary(-3.).unwrap();
assert_eq!(c_imag.conjugate(), expected_imag);
}
#[test]
fn arg_valid() {
let c1 = ComplexValidated::one();
assert_eq!(c1.arg(), RealValidated::zero());
let c2 = ComplexValidated::try_new_pure_imaginary(1.0).unwrap();
let pi_div_2 = RealValidated::try_new(FRAC_PI_2).unwrap();
assert_eq!(c2.arg(), pi_div_2);
let c3 = ComplexValidated::try_new_pure_real(-1.0).unwrap();
let pi = RealValidated::try_new(PI).unwrap();
assert_eq!(c3.arg(), pi);
let c4 = ComplexValidated::try_new(Complex::new(1.0, 1.0)).unwrap();
let pi_div_4 = RealValidated::try_new(FRAC_PI_4).unwrap();
assert_eq!(c4.arg(), pi_div_4);
}
#[test]
fn arg_zero() {
let zero = ComplexValidated::zero();
let res = zero.try_arg();
assert!(matches!(
res,
Err(ArgErrors::Input {
source: ArgInputErrors::Zero { .. }
})
));
}
}
mod function_traits {
use super::*;
use crate::functions::{
ATan2InputErrors, LogarithmRealErrors, LogarithmRealInputErrors,
PowComplexBaseRealExponentInputErrors, PowRealBaseRealExponentInputErrors,
ReciprocalInputErrors, SqrtRealInputErrors,
};
mod min_max {
use super::*;
#[test]
fn max_valid() {
let r1 = RealValidated::try_new(3.).unwrap();
let r2 = RealValidated::try_new(4.).unwrap();
assert_eq!(r1.max_by_ref(&r2), &r2);
assert_eq!(r2.max_by_ref(&r1), &r2);
}
#[test]
fn min_valid() {
let r1 = RealValidated::try_new(3.).unwrap();
let r2 = RealValidated::try_new(4.).unwrap();
assert_eq!(r1.min_by_ref(&r2), &r1);
assert_eq!(r2.min_by_ref(&r1), &r1);
}
}
mod exp {
use super::*;
mod real {
use super::*;
#[test]
fn exp_valid() {
let exponent = RealValidated::try_new(1.).unwrap();
let expected = std::f64::consts::E;
assert_eq!(exponent.try_exp().unwrap().as_ref(), &expected);
assert_eq!(exponent.exp().as_ref(), &expected);
}
#[test]
fn exp_m1_valid() {
let exponent = RealValidated::try_new(1.).unwrap();
let expected = 1.718281828459045;
assert_ulps_eq!(exponent.exp_m1().as_ref(), &expected);
}
#[test]
fn exp_overflow() {
let large_val = RealValidated::try_new(1.0e60).unwrap(); let res_large = large_val.try_exp();
assert!(matches!(
res_large,
Err(ExpErrors::Output {
source: ErrorsValidationRawReal::IsPosInfinity { .. }
})
),);
}
}
mod complex {
use super::*;
#[test]
fn exp_valid() {
let exponent = ComplexValidated::try_new(Complex::new(0., PI)).unwrap();
let expected = Complex::new(-1., 1.2246467991473532e-16);
assert_eq!(exponent.try_exp().unwrap().as_ref(), &expected);
assert_eq!(exponent.exp().as_ref(), &expected);
}
} }
mod logarithm {
use super::*;
mod real {
use super::*;
#[test]
fn ln_valid() {
let e = RealValidated::one().exp();
let expected = 1.0;
assert_eq!(e.try_ln().unwrap().as_ref(), &expected);
assert_eq!(e.ln().as_ref(), &expected);
}
#[test]
fn log10_valid() {
let v = RealValidated::try_new(100.).unwrap();
let expected = 2.0;
assert_eq!(v.try_log10().unwrap().as_ref(), &expected);
assert_eq!(v.log10().as_ref(), &expected);
}
#[test]
fn log2_valid() {
let v = RealValidated::try_new(4.).unwrap();
let expected = 2.0;
assert_eq!(v.try_log2().unwrap().as_ref(), &expected);
assert_eq!(v.log2().as_ref(), &expected);
}
#[test]
fn ln_1p_valid() {
let v = RealValidated::one().exp() - RealValidated::one();
assert_eq!(v.ln_1p().as_ref(), &1.);
}
#[test]
fn ln_domain_errors() {
let neg_val = RealValidated::try_new(-1.).unwrap();
assert!(matches!(
neg_val.try_ln(),
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::NegativeArgument { .. }
})
));
let zero_val = RealValidated::zero();
assert!(matches!(
zero_val.try_ln(),
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn log10_domain_errors() {
let neg_val = RealValidated::try_new(-1.).unwrap();
assert!(matches!(
neg_val.try_log10(),
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::NegativeArgument { .. }
})
));
let zero_val = RealValidated::zero();
assert!(matches!(
zero_val.try_log10(),
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn log2_domain_errors() {
let neg_val = RealValidated::try_new(-1.).unwrap();
assert!(matches!(
neg_val.try_log2(),
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::NegativeArgument { .. }
})
));
let zero_val = RealValidated::zero();
assert!(matches!(
zero_val.try_log2(),
Err(LogarithmRealErrors::Input {
source: LogarithmRealInputErrors::ZeroArgument { .. }
})
));
}
}
mod complex {
use super::*;
#[test]
fn ln_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = Complex::new(0.8047189562170503, -1.1071487177940904);
assert_eq!(v.try_ln().unwrap().as_ref(), &expected);
assert_eq!(v.ln().as_ref(), &expected);
}
#[test]
fn log10_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = Complex::new(0.3494850021680094, -0.480828578784234);
assert_eq!(v.try_log10().unwrap().as_ref(), &expected);
assert_eq!(v.log10().as_ref(), &expected);
}
#[test]
fn log2_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = Complex::new(1.1609640474436813, -1.5972779646881088);
assert_eq!(v.try_log2().unwrap().as_ref(), &expected);
assert_eq!(v.log2().as_ref(), &expected);
}
#[test]
fn ln_zero() {
let zero_val = ComplexValidated::zero();
assert!(matches!(
zero_val.try_ln(),
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn log10_zero() {
let zero_val = ComplexValidated::zero();
assert!(matches!(
zero_val.try_log10(),
Err(LogarithmComplexErrors::Input {
source: LogarithmComplexInputErrors::ZeroArgument { .. }
})
));
}
#[test]
fn log2_zero() {
let zero_val = ComplexValidated::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 = RealValidated::try_new(-2.).unwrap();
let exponent = RealValidated::try_new(0.5).unwrap();
let res = base.try_pow(&exponent);
assert!(matches!(
res,
Err(PowRealBaseRealExponentErrors::Input {
source: PowRealBaseRealExponentInputErrors::NegativeBase { .. }
})
));
}
#[test]
fn real_base_uint_exponent_valid() {
let base = RealValidated::try_new(2.).unwrap();
assert_eq!(
base.try_pow(3u8).unwrap(),
RealValidated::try_new(8.).unwrap()
);
assert_eq!(
base.try_pow(3u16).unwrap(),
RealValidated::try_new(8.).unwrap()
);
assert_eq!(
base.try_pow(3u32).unwrap(),
RealValidated::try_new(8.).unwrap()
);
assert_eq!(
base.try_pow(3u64).unwrap(),
RealValidated::try_new(8.).unwrap()
);
assert_eq!(
base.try_pow(3u128).unwrap(),
RealValidated::try_new(8.).unwrap()
);
assert_eq!(
base.try_pow(3usize).unwrap(),
RealValidated::try_new(8.).unwrap()
);
assert_eq!(base.pow(3u8), RealValidated::try_new(8.).unwrap());
assert_eq!(base.pow(3u16), RealValidated::try_new(8.).unwrap());
assert_eq!(base.pow(3u32), RealValidated::try_new(8.).unwrap());
assert_eq!(base.pow(3u64), RealValidated::try_new(8.).unwrap());
assert_eq!(base.pow(3u128), RealValidated::try_new(8.).unwrap());
assert_eq!(base.pow(3usize), RealValidated::try_new(8.).unwrap());
}
#[test]
fn real_base_int_exponent_valid() {
let base = RealValidated::try_new(2.).unwrap();
assert_eq!(
base.try_pow(3i8).unwrap(),
RealValidated::try_new(8.).unwrap()
);
assert_eq!(
base.try_pow(3i16).unwrap(),
RealValidated::try_new(8.).unwrap()
);
assert_eq!(
base.try_pow(3i32).unwrap(),
RealValidated::try_new(8.).unwrap()
);
assert_eq!(
base.try_pow(3i64).unwrap(),
RealValidated::try_new(8.).unwrap()
);
assert_eq!(
base.try_pow(3i128).unwrap(),
RealValidated::try_new(8.).unwrap()
);
assert_eq!(
base.try_pow(3isize).unwrap(),
RealValidated::try_new(8.).unwrap()
);
assert_eq!(base.pow(3i8), RealValidated::try_new(8.).unwrap());
assert_eq!(base.pow(3i16), RealValidated::try_new(8.).unwrap());
assert_eq!(base.pow(3i32), RealValidated::try_new(8.).unwrap());
assert_eq!(base.pow(3i64), RealValidated::try_new(8.).unwrap());
assert_eq!(base.pow(3i128), RealValidated::try_new(8.).unwrap());
assert_eq!(base.pow(3isize), RealValidated::try_new(8.).unwrap());
}
#[test]
fn real_base_int_exponent_zero_neg_exp_error() {
let base = RealValidated::zero();
let exponent: i32 = -2;
let res = base.try_pow(exponent);
assert!(matches!(
res,
Err(PowIntExponentErrors::Input {
source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
})
));
}
#[test]
fn real_base_real_exponent_valid() {
let base = RealValidated::try_new(2.).unwrap();
let exponent = RealValidated::try_new(3.).unwrap();
let expected = 8.;
assert_eq!(base.try_pow(&exponent).unwrap().as_ref(), &expected);
assert_eq!(base.pow(&exponent).as_ref(), &expected);
}
}
mod complex_base {
use super::*;
#[test]
fn complex_base_uint_exponent_valid() {
let base = ComplexValidated::try_new(Complex::new(2., 3.)).unwrap();
let expected_res = ComplexValidated::try_new(Complex::new(-46., 9.)).unwrap();
assert_eq!(&base.try_pow(3u8).unwrap(), &expected_res);
assert_eq!(&base.try_pow(3u16).unwrap(), &expected_res);
assert_eq!(&base.try_pow(3u32).unwrap(), &expected_res);
assert_eq!(&base.try_pow(3u64).unwrap(), &expected_res);
assert_eq!(&base.try_pow(3u128).unwrap(), &expected_res);
assert_eq!(&base.try_pow(3usize).unwrap(), &expected_res);
assert_eq!(&base.pow(3u8), &expected_res);
assert_eq!(&base.pow(3u16), &expected_res);
assert_eq!(&base.pow(3u32), &expected_res);
assert_eq!(&base.pow(3u64), &expected_res);
assert_eq!(&base.pow(3u128), &expected_res);
assert_eq!(&base.pow(3usize), &expected_res);
}
#[test]
fn complex_base_int_exponent_valid() {
let base = ComplexValidated::try_new(Complex::new(2., 3.)).unwrap();
let expected_res = ComplexValidated::try_new(Complex::new(-46., 9.)).unwrap();
assert_eq!(&base.try_pow(3i8).unwrap(), &expected_res);
assert_eq!(&base.try_pow(3i16).unwrap(), &expected_res);
assert_eq!(&base.try_pow(3i32).unwrap(), &expected_res);
assert_eq!(&base.try_pow(3i64).unwrap(), &expected_res);
assert_eq!(&base.try_pow(3i128).unwrap(), &expected_res);
assert_eq!(&base.try_pow(3isize).unwrap(), &expected_res);
assert_eq!(&base.pow(3i8), &expected_res);
assert_eq!(&base.pow(3i16), &expected_res);
assert_eq!(&base.pow(3i32), &expected_res);
assert_eq!(&base.pow(3i64), &expected_res);
assert_eq!(&base.pow(3i128), &expected_res);
assert_eq!(&base.pow(3isize), &expected_res);
}
#[test]
fn complex_zero_base_negative_real_exponent_error() {
let base = ComplexValidated::zero();
let exponent = RealValidated::try_new(-2.).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 = ComplexValidated::zero();
let exponent = RealValidated::zero();
let res = base.try_pow(&exponent).unwrap();
assert_eq!(res, ComplexValidated::one());
}
#[test]
fn complex_base_int_exponent_zero_neg_exp_error() {
let base = ComplexValidated::zero();
let exponent: i32 = -2;
let res = base.try_pow(exponent);
assert!(matches!(
res,
Err(PowIntExponentErrors::Input {
source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
})
));
}
#[test]
fn complex_base_real_exponent_valid() {
let base = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let exponent = RealValidated::try_new(3.).unwrap();
let expected = Complex::new(-11.000000000000004, 1.9999999999999973);
assert_eq!(base.try_pow(&exponent).unwrap().as_ref(), &expected);
assert_eq!(base.pow(&exponent).as_ref(), &expected);
}
#[test]
fn complex_zero_base_real_exponent_valid() {
let base = ComplexValidated::zero();
let exponent = RealValidated::try_new(3.).unwrap();
let expected = Complex::new(0., 0.);
assert_eq!(base.try_pow(&exponent).unwrap().as_ref(), &expected);
assert_eq!(base.pow(&exponent).as_ref(), &expected);
}
}
}
mod reciprocal {
use super::*;
mod real {
use super::*;
#[test]
fn reciprocal_valid() {
let v = RealValidated::try_new(2.).unwrap();
let res = v.try_reciprocal().unwrap();
assert_eq!(res.into_inner(), 0.5);
let res = v.reciprocal();
assert_eq!(res.into_inner(), 0.5);
}
#[test]
fn reciprocal_real_zero() {
let zero_val = RealValidated::zero();
let res = zero_val.try_reciprocal();
assert!(matches!(
res,
Err(ReciprocalErrors::Input {
source: ReciprocalInputErrors::DivisionByZero { .. }
})
));
}
}
mod complex {
use super::*;
#[test]
fn reciprocal_valid() {
let v = ComplexValidated::try_new(Complex::new(3., 4.)).unwrap();
let expected = Complex::new(0.12, -0.16);
let res = v.try_reciprocal().unwrap();
assert_eq!(res.as_ref(), &expected);
let res = v.reciprocal();
assert_eq!(res.as_ref(), &expected);
}
#[test]
fn reciprocal_complex_zero() {
let zero_val = ComplexValidated::zero();
let res = zero_val.try_reciprocal();
assert!(matches!(
res,
Err(ReciprocalErrors::Input {
source: ReciprocalInputErrors::DivisionByZero { .. }
})
));
}
}
}
mod sqrt {
use super::*;
mod real {
use super::*;
#[test]
fn sqrt_valid() {
let v = RealValidated::try_new(9.).unwrap();
assert_eq!(v.try_sqrt().unwrap().as_ref(), &3.);
assert_eq!(v.sqrt().as_ref(), &3.);
}
#[test]
fn sqrt_negative_input() {
let neg_val = RealValidated::try_new(-4.).unwrap();
let res = neg_val.try_sqrt();
assert!(matches!(
res,
Err(SqrtRealErrors::Input {
source: SqrtRealInputErrors::NegativeValue { .. }
})
));
}
}
mod complex {
use super::*;
#[test]
fn sqrt_valid() {
let expected = Complex::new(1., 2.);
let v = ComplexValidated::try_new(expected * expected).unwrap();
let expected = Complex::new(1.0000000000000002, 2.);
assert_eq!(v.try_sqrt().unwrap().as_ref(), &expected);
assert_eq!(v.sqrt().as_ref(), &expected);
}
}
}
mod trigonometric {
use super::*;
mod real {
use super::*;
#[test]
fn sin_real_valid() {
let v = RealValidated::pi_div_2();
let expected = 1.;
assert_eq!(v.try_sin().unwrap().as_ref(), &expected);
assert_eq!(v.sin().as_ref(), &expected);
}
#[test]
fn cos_real_valid() {
let v = RealValidated::pi();
let expected = -1.;
assert_eq!(v.try_cos().unwrap().as_ref(), &expected);
assert_eq!(v.cos().as_ref(), &expected);
}
#[test]
fn tan_real_valid() {
let v = RealValidated::one();
let expected = 1.5574077246549023;
assert_ulps_eq!(v.try_tan().unwrap().as_ref(), &expected);
assert_ulps_eq!(v.tan().as_ref(), &expected);
}
#[test]
fn asin_real_valid() {
let v = RealValidated::one();
let expected = std::f64::consts::FRAC_PI_2; assert_eq!(v.try_asin().unwrap().as_ref(), &expected);
assert_eq!(v.asin().as_ref(), &expected);
}
#[test]
fn acos_real_valid() {
let v = RealValidated::one();
let expected = 0.;
assert_eq!(v.try_acos().unwrap().as_ref(), &expected);
assert_eq!(v.acos().as_ref(), &expected);
}
#[test]
fn atan_real_valid() {
let v = RealValidated::one();
let expected = std::f64::consts::FRAC_PI_4; assert_eq!(v.try_atan().unwrap().as_ref(), &expected);
assert_eq!(v.atan().as_ref(), &expected);
}
#[test]
fn atan2_valid() {
let one = RealValidated::one();
let zero = RealValidated::zero();
let expected = std::f64::consts::FRAC_PI_2; assert_eq!(one.try_atan2(&zero).unwrap().as_ref(), &expected);
assert_eq!(one.atan2(&zero).as_ref(), &expected);
let expected = 0.;
assert_eq!(zero.try_atan2(&one).unwrap().as_ref(), &expected);
assert_eq!(zero.atan2(&one).as_ref(), &expected);
let expected = std::f64::consts::FRAC_PI_4; assert_eq!(one.try_atan2(&one).unwrap().as_ref(), &expected);
assert_eq!(one.atan2(&one).as_ref(), &expected);
}
#[test]
fn atan2_zero_over_zero() {
let zero_val = RealValidated::zero();
let res = zero_val.try_atan2(&RealValidated::zero());
assert!(matches!(
res,
Err(ATan2Errors::Input {
source: ATan2InputErrors::ZeroOverZero { .. }
})
));
}
#[test]
fn asin_real_out_of_domain() {
let val_gt_1 = RealValidated::try_new(1.5).unwrap();
assert!(matches!(
val_gt_1.try_asin(),
Err(ASinRealErrors::Input {
source: ASinRealInputErrors::OutOfDomain { .. }
})
));
let val_lt_neg1 = RealValidated::try_new(-1.5).unwrap();
assert!(matches!(
val_lt_neg1.try_asin(),
Err(ASinRealErrors::Input {
source: ASinRealInputErrors::OutOfDomain { .. }
})
));
}
#[test]
fn acos_real_out_of_domain() {
let val_gt_1 = RealValidated::try_new(1.5).unwrap();
assert!(matches!(
val_gt_1.try_acos(),
Err(ACosRealErrors::Input {
source: ACosRealInputErrors::OutOfDomain { .. }
})
));
let val_lt_neg1 = RealValidated::try_new(-1.5).unwrap();
assert!(matches!(
val_lt_neg1.try_acos(),
Err(ACosRealErrors::Input {
source: ACosRealInputErrors::OutOfDomain { .. }
})
));
}
}
mod complex {
use super::*;
#[test]
fn sin_complex_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = if cfg!(target_arch = "x86_64") {
Complex::new(3.165778513216168, -1.9596010414216063)
} else if cfg!(target_arch = "aarch64") {
Complex::new(3.165778513216168, -1.959601041421606)
} else {
todo!("Architecture not-tested");
};
assert_eq!(v.try_sin().unwrap().as_ref(), &expected);
assert_eq!(v.sin().as_ref(), &expected);
let zero = ComplexValidated::zero();
let expected = Complex::new(0., 0.);
assert_eq!(zero.try_sin().unwrap().as_ref(), &expected);
assert_eq!(zero.sin().as_ref(), &expected);
}
#[test]
fn cos_complex_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = if cfg!(target_arch = "x86_64") {
Complex::new(2.0327230070196656, 3.0518977991518)
} else if cfg!(target_arch = "aarch64") {
Complex::new(2.0327230070196656, 3.0518977991517997)
} else {
todo!("Architecture not-tested");
};
assert_eq!(v.try_cos().unwrap().as_ref(), &expected);
assert_eq!(v.cos().as_ref(), &expected);
let zero = ComplexValidated::zero();
let expected = Complex::new(1., 0.);
assert_eq!(zero.try_cos().unwrap().as_ref(), &expected);
assert_eq!(zero.cos().as_ref(), &expected);
}
#[test]
fn tan_complex_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = Complex::new(0.03381282607989669, -1.0147936161466335);
assert_eq!(v.try_tan().unwrap().as_ref(), &expected);
assert_eq!(v.tan().as_ref(), &expected);
let zero = ComplexValidated::zero();
let expected = Complex::new(0., 0.);
assert_eq!(zero.try_tan().unwrap().as_ref(), &expected);
assert_eq!(zero.tan().as_ref(), &expected);
}
#[test]
fn asin_complex_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = Complex::new(0.42707858639247614, -1.528570919480998);
assert_eq!(v.try_asin().unwrap().as_ref(), &expected);
assert_eq!(v.asin().as_ref(), &expected);
let zero = ComplexValidated::zero();
let expected = Complex::new(0., 0.);
assert_eq!(zero.try_asin().unwrap().as_ref(), &expected);
assert_eq!(zero.asin().as_ref(), &expected);
}
#[test]
fn acos_complex_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = Complex::new(1.14371774040242, 1.5285709194809995);
assert_eq!(v.try_acos().unwrap().as_ref(), &expected);
assert_eq!(v.acos().as_ref(), &expected);
let one = ComplexValidated::one();
let expected = Complex::new(0., 0.);
assert_eq!(one.try_acos().unwrap().as_ref(), &expected);
assert_eq!(one.acos().as_ref(), &expected);
}
#[test]
fn atan_complex_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = Complex::new(1.3389725222944935, -0.4023594781085251);
assert_eq!(v.try_atan().unwrap().as_ref(), &expected);
assert_eq!(v.atan().as_ref(), &expected);
let zero = ComplexValidated::zero();
let expected = Complex::new(0., 0.);
assert_eq!(zero.try_atan().unwrap().as_ref(), &expected);
assert_eq!(zero.atan().as_ref(), &expected);
}
#[test]
fn atan_complex_pole() {
let i_val = ComplexValidated::try_new_pure_imaginary(1.).unwrap();
assert!(matches!(
i_val.try_atan(),
Err(ATanComplexErrors::Input {
source: ATanComplexInputErrors::ArgumentIsPole { .. }
})
));
let neg_i_val = ComplexValidated::try_new_pure_imaginary(-1.).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_valid() {
let v = RealValidated::zero();
let expected = 0.;
assert_eq!(v.try_atanh().unwrap().as_ref(), &expected);
assert_eq!(v.atanh().as_ref(), &expected);
}
#[test]
fn atanh_real_out_of_domain() {
let val_ge_1 = RealValidated::one(); assert!(matches!(
val_ge_1.try_atanh(),
Err(ATanHErrors::Input {
source: ATanHInputErrors::OutOfDomain { .. }
})
));
let val_le_neg1 = RealValidated::negative_one(); assert!(matches!(
val_le_neg1.try_atanh(),
Err(ATanHErrors::Input {
source: ATanHInputErrors::OutOfDomain { .. }
})
));
}
#[test]
fn acosh_real_valid() {
let v = RealValidated::one();
let expected = 0.;
assert_eq!(v.try_acosh().unwrap().as_ref(), &expected);
assert_eq!(v.acosh().as_ref(), &expected);
}
#[test]
fn acosh_real_out_of_domain() {
let val_lt_1 = RealValidated::try_new(0.5).unwrap();
assert!(matches!(
val_lt_1.try_acosh(),
Err(ACosHErrors::Input {
source: ACosHInputErrors::OutOfDomain { .. }
})
));
}
#[test]
fn asinh_real_valid() {
let v = RealValidated::one();
let expected = 0.881373587019543;
assert_eq!(v.try_asinh().unwrap().as_ref(), &expected);
assert_eq!(v.asinh().as_ref(), &expected);
}
#[test]
fn sinh_real_valid() {
let v = RealValidated::try_new(0.881373587019543).unwrap();
let expected = 1.;
assert_eq!(v.try_sinh().unwrap().as_ref(), &expected);
assert_eq!(v.sinh().as_ref(), &expected);
}
#[test]
fn cosh_real_valid() {
let v = RealValidated::one();
let expected = 1.5430806348152437;
assert_eq!(v.try_cosh().unwrap().as_ref(), &expected);
assert_eq!(v.cosh().as_ref(), &expected);
}
#[test]
fn tanh_real_valid() {
let v = RealValidated::one();
let expected = 0.7615941559557649;
assert_eq!(v.try_tanh().unwrap().as_ref(), &expected);
assert_eq!(v.tanh().as_ref(), &expected);
}
}
mod complex {
use super::*;
#[test]
fn sinh_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = Complex::new(-0.4890562590412937, -1.4031192506220405);
assert_eq!(v.try_sinh().unwrap().as_ref(), &expected);
assert_eq!(v.sinh().as_ref(), &expected);
}
#[test]
fn cosh_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = Complex::new(-0.64214812471552, -1.0686074213827783);
assert_eq!(v.try_cosh().unwrap().as_ref(), &expected);
assert_eq!(v.cosh().as_ref(), &expected);
}
#[test]
fn tanh_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = if cfg!(target_arch = "x86_64") {
Complex::new(1.16673625724092, 0.24345820118572523)
} else if cfg!(target_arch = "aarch64") {
Complex::new(1.16673625724092, 0.24345820118572528)
} else {
todo!("Architecture not-tested");
};
assert_eq!(v.try_tanh().unwrap().as_ref(), &expected);
assert_eq!(v.tanh().as_ref(), &expected);
}
#[test]
fn asinh_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = Complex::new(1.4693517443681852, -1.0634400235777521);
Complex::new(1.4693517443681852, -1.0634400235777521);
assert_eq!(v.try_asinh().unwrap().as_ref(), &expected);
assert_eq!(v.asinh().as_ref(), &expected);
}
#[test]
fn acosh_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = Complex::new(1.528570919480998, -1.1437177404024206);
assert_eq!(v.try_acosh().unwrap().as_ref(), &expected);
assert_eq!(v.acosh().as_ref(), &expected);
}
#[test]
fn atanh_valid() {
let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
let expected = Complex::new(0.1732867951399864, -1.1780972450961724);
assert_eq!(v.try_atanh().unwrap().as_ref(), &expected);
assert_eq!(v.atanh().as_ref(), &expected);
}
#[test]
fn acosh_out_of_domain() {
let val_on_branch_cut = ComplexValidated::try_new_pure_real(0.5).unwrap();
assert!(matches!(
val_on_branch_cut.try_acosh(),
Err(ACosHErrors::Input {
source: ACosHInputErrors::OutOfDomain { .. }
})
));
let val_on_branch_cut_neg = ComplexValidated::try_new_pure_real(-5.).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 = ComplexValidated::try_new_pure_real(1.).unwrap();
assert!(matches!(
val_ge_1.try_atanh(),
Err(ATanHErrors::Input {
source: ATanHInputErrors::OutOfDomain { .. }
})
));
let val_le_neg1 = ComplexValidated::try_new_pure_real(-1.).unwrap();
assert!(matches!(
val_le_neg1.try_atanh(),
Err(ATanHErrors::Input {
source: ATanHInputErrors::OutOfDomain { .. }
})
));
}
}
} }
mod summation {
use super::*;
#[test]
fn sum_real() {
let values = vec![
RealValidated::try_new(1.0).unwrap(),
RealValidated::try_new(2.0).unwrap(),
RealValidated::try_new(3.0).unwrap(),
RealValidated::try_new(4.0).unwrap(),
RealValidated::try_new(5.0).unwrap(),
];
let sum: RealValidated = values.into_iter().sum();
assert_eq!(sum, RealValidated::try_new(15.0).unwrap());
}
#[test]
fn sum_real_compensated() {
let values = vec![
RealValidated::try_new(1.0e100).unwrap(),
RealValidated::try_new(1.0).unwrap(),
RealValidated::try_new(-1.0e100).unwrap(),
];
let sum: RealValidated = values.into_iter().sum();
assert_eq!(sum, RealValidated::try_new(1.0).unwrap());
}
#[test]
fn sum_complex() {
let values = vec![
ComplexValidated::try_new(Complex::new(1.0, 2.0)).unwrap(),
ComplexValidated::try_new(Complex::new(3.0, 4.0)).unwrap(),
ComplexValidated::try_new(Complex::new(5.0, 6.0)).unwrap(),
];
let sum: ComplexValidated = values.into_iter().sum();
assert_eq!(
sum,
ComplexValidated::try_new(Complex::new(9.0, 12.0)).unwrap()
);
}
#[test]
fn sum_complex_compensated() {
let values = vec![
ComplexValidated::try_new(Complex::new(1.0e100, -1.0e100)).unwrap(),
ComplexValidated::try_new(Complex::new(1.0, 2.0)).unwrap(),
ComplexValidated::try_new(Complex::new(-1.0e100, 1.0e100)).unwrap(),
];
let sum: ComplexValidated = values.into_iter().sum();
assert_eq!(
sum,
ComplexValidated::try_new(Complex::new(1.0, 2.0)).unwrap()
);
}
}
mod neumaier_sum {
use crate::algorithms::neumaier_sum::NeumaierSum;
use try_create::TryNewValidated;
use super::*;
mod real {
use super::*;
#[test]
fn new() {
let neumaier = NeumaierSum::new(RealValidated::try_new_validated(1.0).unwrap());
assert_eq!(neumaier.sum_before_compensation(), &1.0);
assert_eq!(neumaier.compensation(), &0.0);
}
#[test]
fn zero() {
let neumaier = NeumaierSum::<RealValidated>::zero();
assert_eq!(neumaier.sum_before_compensation(), &0.0);
assert_eq!(neumaier.compensation(), &0.0);
}
#[test]
fn add() {
let mut neumaier = NeumaierSum::zero();
neumaier.add(RealValidated::try_new_validated(1.0).unwrap());
neumaier.add(RealValidated::try_new_validated(1e-16).unwrap());
neumaier.add(RealValidated::try_new_validated(-1.0).unwrap());
assert_eq!(neumaier.sum_before_compensation(), &0.0);
assert_eq!(neumaier.compensation(), &1e-16);
}
#[test]
fn sum() {
let mut neumaier = NeumaierSum::zero();
neumaier.add(RealValidated::try_new_validated(1.0).unwrap());
neumaier.add(RealValidated::try_new_validated(1e-16).unwrap());
neumaier.add(RealValidated::try_new_validated(-1.0).unwrap());
assert_eq!(neumaier.sum_before_compensation(), &0.0);
assert_eq!(neumaier.compensation(), &1e-16);
assert_eq!(neumaier.sum().as_ref(), &1e-16);
println!("compensated sum = {}", neumaier.sum());
}
#[test]
fn reset() {
let mut neumaier = NeumaierSum::zero();
neumaier.add(RealValidated::try_new_validated(1.0).unwrap());
neumaier.add(RealValidated::try_new_validated(1e-16).unwrap());
assert_eq!(neumaier.sum_before_compensation(), &1.0);
assert_eq!(neumaier.compensation(), &1e-16);
neumaier.reset();
assert_eq!(neumaier.sum_before_compensation(), &0.0);
assert_eq!(neumaier.compensation(), &0.0);
}
#[test]
fn sum_big_values() {
let values = [1.0, 1e100, 1.0, -1e100]
.iter()
.map(|&v| RealValidated::try_new_validated(v).unwrap())
.collect::<Vec<_>>();
let sum = values.iter().cloned().sum::<RealValidated>();
assert_eq!(sum, 2.0);
let neumaier = NeumaierSum::new_sequential(values);
assert_eq!(neumaier.sum(), 2.0);
println!("compensated sum = {}", neumaier.sum());
}
#[test]
fn sum_small_values() {
let values = [1.0, 1e-100, -1.0]
.iter()
.map(|&v| RealValidated::try_new_validated(v).unwrap())
.collect::<Vec<_>>();
let sum = values.iter().cloned().sum::<RealValidated>();
assert_eq!(sum, 1e-100);
let neumaier = NeumaierSum::new_sequential(values);
assert_eq!(neumaier.sum(), 1e-100);
println!("compensated sum = {}", neumaier.sum());
}
}
mod complex {
use super::*;
#[test]
fn new() {
let neumaier = NeumaierSum::new(
ComplexValidated::try_new_validated(Complex::new(1.0, 2.0)).unwrap(),
);
assert_eq!(
neumaier.sum_before_compensation().as_ref(),
&Complex::new(1.0, 2.0)
);
assert_eq!(neumaier.compensation().as_ref(), &Complex::new(0.0, 0.0));
}
#[test]
fn zero() {
let neumaier = NeumaierSum::<ComplexValidated>::zero();
let zero = Complex::new(0.0, 0.0);
assert_eq!(neumaier.sum_before_compensation().as_ref(), &zero);
assert_eq!(neumaier.compensation().as_ref(), &zero);
}
#[test]
fn add() {
let zero = Complex::new(0.0, 0.0);
let v = Complex::new(1e-16, 2e-16);
let mut neumaier = NeumaierSum::zero();
neumaier.add(ComplexValidated::try_new_validated(Complex::new(1.0, 2.0)).unwrap());
neumaier.add(ComplexValidated::try_new_validated(v).unwrap());
neumaier
.add(ComplexValidated::try_new_validated(Complex::new(-1.0, -2.0)).unwrap());
assert_eq!(neumaier.sum_before_compensation().as_ref(), &zero);
assert_eq!(neumaier.compensation().as_ref(), &v);
}
#[test]
fn sum() {
let zero = Complex::new(0.0, 0.0);
let v = Complex::new(1e-16, 2e-16);
let mut neumaier = NeumaierSum::zero();
neumaier.add(ComplexValidated::try_new_validated(Complex::new(1.0, 2.0)).unwrap());
neumaier.add(ComplexValidated::try_new_validated(v).unwrap());
neumaier
.add(ComplexValidated::try_new_validated(Complex::new(-1.0, -2.0)).unwrap());
assert_eq!(neumaier.sum_before_compensation().as_ref(), &zero);
assert_eq!(neumaier.compensation().as_ref(), &v);
assert_eq!(neumaier.sum().as_ref(), &v);
println!("compensated sum = {}", neumaier.sum());
}
#[test]
fn reset() {
let zero = Complex::new(0.0, 0.0);
let a = Complex::new(1.0, 2.0);
let v = Complex::new(1e-16, 2e-16);
let mut neumaier = NeumaierSum::zero();
neumaier.add(ComplexValidated::try_new_validated(a).unwrap());
neumaier.add(ComplexValidated::try_new_validated(v).unwrap());
assert_eq!(neumaier.sum_before_compensation().as_ref(), &a);
assert_eq!(neumaier.compensation().as_ref(), &v);
neumaier.reset();
assert_eq!(neumaier.sum_before_compensation().as_ref(), &zero);
assert_eq!(neumaier.compensation().as_ref(), &zero);
}
#[test]
fn sum_big_values() {
let values = [
Complex::new(1.0, 2.0),
Complex::new(1e100, 2e100),
Complex::new(1.0, 2.0),
Complex::new(-1e100, -2e100),
]
.iter()
.map(|&v| ComplexValidated::try_new_validated(v).unwrap())
.collect::<Vec<_>>();
let sum = values.clone().into_iter().sum::<ComplexValidated>();
let expected_sum = Complex::new(2., 4.);
assert_eq!(sum.as_ref(), &expected_sum);
let neumaier = NeumaierSum::new_sequential(values);
assert_eq!(neumaier.sum().as_ref(), &expected_sum);
println!("compensated sum = {}", neumaier.sum());
}
#[test]
fn sum_small_values() {
let v = Complex::new(1e-100, 2e-100);
let values = [Complex::new(1.0, 2.0), v, Complex::new(-1.0, -2.0)]
.iter()
.map(|&v| ComplexValidated::try_new_validated(v).unwrap())
.collect::<Vec<_>>();
let sum = values.iter().cloned().sum::<ComplexValidated>();
let sum_expected = v;
assert_eq!(sum.as_ref(), &sum_expected);
let neumaier = NeumaierSum::new_sequential(values);
assert_eq!(neumaier.sum().as_ref(), &sum_expected);
println!("compensated sum = {}", neumaier.sum());
}
}
}
mod random {
use super::*;
use super::{ComplexNative64StrictFinite, RealNative64StrictFinite};
use crate::{RandomSampleFromF64, new_random_vec};
use rand::{SeedableRng, distr::Uniform, rngs::StdRng};
#[test]
fn test_random_real_validated() {
let seed = [42; 32];
let mut rng = StdRng::from_seed(seed);
let random_real: RealNative64StrictFinite = rng.random();
assert_eq!(random_real, 0.23713468825474326);
let mut rng2 = StdRng::from_seed(seed);
let random_real2: RealNative64StrictFinite = 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: ComplexNative64StrictFinite = 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: ComplexNative64StrictFinite = 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 = RealNative64StrictFinite::sample_from(&dist, &mut rng);
assert_eq!(val, -5.257306234905137);
let mut rng2 = StdRng::from_seed(SEED);
let val2 = RealNative64StrictFinite::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 = ComplexNative64StrictFinite::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 = ComplexNative64StrictFinite::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<RealNative64StrictFinite> = 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<RealNative64StrictFinite> = 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<ComplexNative64StrictFinite> = 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<ComplexNative64StrictFinite> = new_random_vec(3, &dist, &mut rng2);
assert_eq!(vec, vec2);
}
}
mod hash_map_key_usage {
use crate::{
backends::native64::validated::{
ComplexNative64StrictFinite, RealNative64StrictFinite,
RealNative64StrictFiniteInDebug,
},
functions::Sign,
};
use num::Complex;
use std::collections::HashMap;
use try_create::TryNew;
#[test]
fn test_native64_as_hashmap_key() {
let mut map = HashMap::new();
let key1 = RealNative64StrictFinite::try_new(1.0).unwrap();
let key2 = RealNative64StrictFinite::try_new(2.5).unwrap();
map.insert(key1, "one");
map.insert(key2, "two_point_five");
assert_eq!(
map.get(&RealNative64StrictFinite::try_new(1.0).unwrap()),
Some(&"one")
);
assert_eq!(map.len(), 2);
let old_value = map.insert(key1, "new_one");
assert_eq!(old_value, Some("one"));
assert_eq!(map.get(&key1), Some(&"new_one"));
}
#[test]
fn test_native64_debug_as_hashmap_key() {
let mut map = HashMap::new();
let key1 = RealNative64StrictFiniteInDebug::try_new(1.0).unwrap();
let key2 = RealNative64StrictFiniteInDebug::try_new(2.5).unwrap();
map.insert(key1, "one_debug");
map.insert(key2, "two_point_five_debug");
assert_eq!(
map.get(&RealNative64StrictFiniteInDebug::try_new(1.0).unwrap()),
Some(&"one_debug")
);
assert_eq!(map.len(), 2);
let old_value = map.insert(key1, "new_one_debug");
assert_eq!(old_value, Some("one_debug"));
assert_eq!(map.get(&key1), Some(&"new_one_debug"));
}
#[test]
fn test_hashmap_basic_operations() {
let mut map = HashMap::new();
let key1 = RealNative64StrictFinite::try_new(1.0).unwrap();
let key2 = RealNative64StrictFinite::try_new(2.5).unwrap();
let key3 = RealNative64StrictFinite::try_new(1.0).unwrap();
assert_eq!(map.insert(key1, "one"), None);
assert_eq!(map.insert(key2, "two_point_five"), None);
assert_eq!(map.len(), 2);
assert_eq!(map.get(&key3), Some(&"one"));
assert_eq!(map.insert(key3, "one_updated"), Some("one"));
assert_eq!(map.len(), 2); }
#[test]
fn test_hashset_operations() {
use std::collections::HashSet;
let mut set = HashSet::new();
let val1 = RealNative64StrictFinite::try_new(1.0).unwrap();
let val2 = RealNative64StrictFinite::try_new(2.0).unwrap();
let val1_duplicate = RealNative64StrictFinite::try_new(1.0).unwrap();
assert!(set.insert(val1));
assert!(set.insert(val2));
assert!(!set.insert(val1_duplicate));
assert_eq!(set.len(), 2);
assert!(set.contains(&RealNative64StrictFinite::try_new(1.0).unwrap()));
}
#[test]
fn test_hash_consistency() {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let val1 = RealNative64StrictFinite::try_new(1.234).unwrap();
let val2 = RealNative64StrictFinite::try_new(1.234).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_hash_signed_zero() {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let val1 = RealNative64StrictFinite::try_new(0.0).unwrap();
assert!(val1.kernel_is_sign_positive());
let val2 = RealNative64StrictFinite::try_new(-0.0).unwrap();
assert!(val2.kernel_is_sign_negative());
assert_ne!(
0.0f64.to_bits(),
(-0.0f64).to_bits(),
"Sanity check: +0.0 and -0.0 should have different bit patterns"
);
assert_eq!(val1, val2);
let mut hasher1 = DefaultHasher::new();
let mut hasher2 = DefaultHasher::new();
val1.hash(&mut hasher1);
val2.hash(&mut hasher2);
assert_eq!(hasher1.finish(), hasher2.finish());
}
#[test]
fn test_complex_as_hashmap_key() {
let mut map = HashMap::new();
let key1 = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
let key2 = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
map.insert(key1, "one_plus_two_i");
map.insert(key2, "three_plus_four_i");
assert_eq!(
map.get(&ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap()),
Some(&"one_plus_two_i")
);
assert_eq!(map.len(), 2);
let old_value = map.insert(key1, "updated_complex");
assert_eq!(old_value, Some("one_plus_two_i"));
assert_eq!(map.get(&key1), Some(&"updated_complex"));
}
#[test]
fn test_complex_hash_consistency() {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let val1 = ComplexNative64StrictFinite::try_new(Complex::new(1.234, 5.678)).unwrap();
let val2 = ComplexNative64StrictFinite::try_new(Complex::new(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 std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let val1 = ComplexNative64StrictFinite::try_new(Complex::new(0.0, 0.0)).unwrap();
let val2 = ComplexNative64StrictFinite::try_new(Complex::new(-0.0, 0.0)).unwrap();
let val3 = ComplexNative64StrictFinite::try_new(Complex::new(0.0, -0.0)).unwrap();
let val4 = ComplexNative64StrictFinite::try_new(Complex::new(-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_different_values_different_hashes() {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let val1 = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
let val2 = ComplexNative64StrictFinite::try_new(Complex::new(2.0, 1.0)).unwrap();
let val3 = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.001)).unwrap();
let mut hasher1 = DefaultHasher::new();
let mut hasher2 = DefaultHasher::new();
let mut hasher3 = DefaultHasher::new();
val1.hash(&mut hasher1);
val2.hash(&mut hasher2);
val3.hash(&mut hasher3);
let hash1 = hasher1.finish();
let hash2 = hasher2.finish();
let hash3 = hasher3.finish();
assert_ne!(val1, val2);
assert_ne!(val1, val3);
assert_ne!(hash1, hash2);
assert_ne!(hash1, hash3);
}
#[test]
fn test_complex_hashset_operations() {
use std::collections::HashSet;
let mut set = HashSet::new();
let val1 = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
let val2 = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
let val1_duplicate =
ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
assert!(set.insert(val1));
assert!(set.insert(val2));
assert!(!set.insert(val1_duplicate));
assert_eq!(set.len(), 2);
assert!(
set.contains(
&ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap()
)
);
}
}
mod test_truncate_to_usize {
use super::*;
use crate::core::errors::ErrorsRawRealToInteger;
#[test]
fn test_positive_integers() {
let value = RealNative64StrictFinite::try_new(42.0).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 42);
let value = RealNative64StrictFinite::try_new(1.0).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 1);
let value = RealNative64StrictFinite::try_new(100.0).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 100);
}
#[test]
fn test_positive_fractionals_truncate() {
let value = RealNative64StrictFinite::try_new(42.9).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 42);
let value = RealNative64StrictFinite::try_new(3.7).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 3);
let value = RealNative64StrictFinite::try_new(0.9).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 0);
let value = RealNative64StrictFinite::try_new(99.999).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 99);
}
#[test]
fn test_zero_cases() {
let value = RealNative64StrictFinite::try_new(0.0).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 0);
let value = RealNative64StrictFinite::try_new(0.1).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 0);
let value = RealNative64StrictFinite::try_new(0.5).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 0);
}
#[test]
fn test_large_valid_values() {
let value = RealNative64StrictFinite::try_new(1_000_000.7).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 1_000_000);
let value = RealNative64StrictFinite::try_new(1_000_000_000.0).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 1_000_000_000);
let max_safe = (usize::MAX as f64) - 2048.0; let value = RealNative64StrictFinite::try_new(max_safe).unwrap();
let result = value.truncate_to_usize().unwrap();
assert!(result < usize::MAX);
}
#[test]
fn test_negative_values_error() {
let value = RealNative64StrictFinite::try_new(-1.0).unwrap();
let result = value.truncate_to_usize();
assert!(matches!(
result,
Err(ErrorsRawRealToInteger::OutOfRange { .. })
));
let value = RealNative64StrictFinite::try_new(-10.5).unwrap();
let result = value.truncate_to_usize();
assert!(matches!(
result,
Err(ErrorsRawRealToInteger::OutOfRange { .. })
));
let value = RealNative64StrictFinite::try_new(-0.1).unwrap();
let result = value.truncate_to_usize();
assert!(matches!(result, Ok(0)));
let value = RealNative64StrictFinite::try_new(-1000.0).unwrap();
let result = value.truncate_to_usize();
assert!(matches!(
result,
Err(ErrorsRawRealToInteger::OutOfRange { .. })
));
}
#[test]
fn test_too_large_values_error() {
let too_large = (usize::MAX as f64) * 2.0;
let value = RealNative64StrictFinite::try_new(too_large).unwrap();
let result = value.truncate_to_usize();
assert!(matches!(
result,
Err(ErrorsRawRealToInteger::OutOfRange { .. })
));
let value = RealNative64StrictFinite::try_new(1e20).unwrap();
let result = value.truncate_to_usize();
assert!(matches!(
result,
Err(ErrorsRawRealToInteger::OutOfRange { .. })
));
}
#[test]
fn test_edge_cases() {
let value = RealNative64StrictFinite::try_new(f64::EPSILON).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 0);
let value = RealNative64StrictFinite::try_new(1.0 - f64::EPSILON).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 0);
let value = RealNative64StrictFinite::try_new(1.0 + f64::EPSILON).unwrap();
assert_eq!(value.truncate_to_usize().unwrap(), 1);
}
#[test]
fn test_truncation_behavior() {
let test_cases = [
(2.1, 2),
(2.5, 2), (2.9, 2),
(3.0, 3),
(3.1, 3),
(99.999, 99),
];
for (input, expected) in test_cases {
let value = RealNative64StrictFinite::try_new(input)
.unwrap()
.truncate_to_usize()
.unwrap();
assert_eq!(
value, expected,
"Failed for input {}: expected {}, got {:?}",
input, expected, value
);
}
}
#[test]
fn test_error_details() {
let value = RealNative64StrictFinite::try_new(-5.0).unwrap();
if let Err(ErrorsRawRealToInteger::OutOfRange {
value: err_val,
min,
max,
..
}) = value.truncate_to_usize()
{
assert_eq!(err_val, -5.0);
assert_eq!(min, usize::MIN);
assert_eq!(max, usize::MAX);
} else {
panic!("Expected OutOfRange error for negative value");
}
let large_value = 1e20;
let value = RealNative64StrictFinite::try_new(large_value).unwrap();
if let Err(ErrorsRawRealToInteger::OutOfRange {
value: err_val,
min,
max,
..
}) = value.truncate_to_usize()
{
assert_eq!(err_val, large_value);
assert_eq!(min, usize::MIN);
assert_eq!(max, usize::MAX);
} else {
panic!("Expected OutOfRange error for large value");
}
}
#[test]
fn test_practical_usage_scenario() {
fn create_vector_with_calculated_size<T: Default + Clone>(
size_float: RealNative64StrictFinite,
) -> Result<Vec<T>, Box<dyn std::error::Error>> {
let size = size_float.truncate_to_usize()?;
Ok(vec![T::default(); size])
}
let calculated_size = RealNative64StrictFinite::try_new(10.7).unwrap();
let vec: Vec<i32> = create_vector_with_calculated_size(calculated_size).unwrap();
assert_eq!(vec.len(), 10);
let negative_size = RealNative64StrictFinite::try_new(-5.0).unwrap();
let result: Result<Vec<i32>, _> = create_vector_with_calculated_size(negative_size);
assert!(result.is_err());
let huge_size = RealNative64StrictFinite::try_new(1e20).unwrap();
let result: Result<Vec<i32>, _> = create_vector_with_calculated_size(huge_size);
assert!(result.is_err());
}
#[test]
fn test_consistency_with_f64_behavior() {
let test_values = [0.0, 1.0, 2.5, 42.9, 100.0, 0.1, 0.9];
for &val in &test_values {
let validated = RealNative64StrictFinite::try_new(val).unwrap();
let result = validated.truncate_to_usize().unwrap();
let expected = val.trunc() as usize;
assert_eq!(result, expected, "Mismatch for value {}", val);
}
}
}
mod bytemuck_conversions {
use super::*;
use bytemuck::checked::{CheckedCastError, try_from_bytes};
mod real_strict_finite {
use super::*;
#[test]
fn valid_value_from_bytes() {
let value = 42.0_f64;
let bytes = value.to_ne_bytes();
let result: Result<&RealNative64StrictFinite, CheckedCastError> =
try_from_bytes(&bytes);
assert!(result.is_ok());
assert_eq!(*result.unwrap().as_ref(), 42.0);
}
#[test]
fn valid_value_try_cast() {
let value = 42.0_f64;
let bytes = value.to_ne_bytes();
let result: Result<&RealNative64StrictFinite, CheckedCastError> =
try_from_bytes(&bytes);
assert!(result.is_ok());
assert_eq!(*result.unwrap().as_ref(), 42.0);
}
#[test]
fn zero_from_bytes() {
let value = 0.0_f64;
let bytes = value.to_ne_bytes();
let result: Result<&RealNative64StrictFinite, CheckedCastError> =
try_from_bytes(&bytes);
assert!(result.is_ok());
assert_eq!(*result.unwrap().as_ref(), 0.0);
}
#[test]
fn negative_zero_from_bytes() {
let value = -0.0_f64;
let bytes = value.to_ne_bytes();
let result: Result<&RealNative64StrictFinite, CheckedCastError> =
try_from_bytes(&bytes);
assert!(result.is_ok());
assert_eq!(*result.unwrap().as_ref(), -0.0);
}
#[test]
fn max_value_from_bytes() {
let value = f64::MAX;
let bytes = value.to_ne_bytes();
let result: Result<&RealNative64StrictFinite, CheckedCastError> =
try_from_bytes(&bytes);
assert!(result.is_ok());
assert_eq!(*result.unwrap().as_ref(), f64::MAX);
}
#[test]
fn min_value_from_bytes() {
let value = f64::MIN;
let bytes = value.to_ne_bytes();
let result: Result<&RealNative64StrictFinite, CheckedCastError> =
try_from_bytes(&bytes);
assert!(result.is_ok());
assert_eq!(*result.unwrap().as_ref(), f64::MIN);
}
#[test]
fn nan_from_bytes_fails() {
let value = f64::NAN;
let bytes = value.to_ne_bytes();
let result: Result<&RealNative64StrictFinite, CheckedCastError> =
try_from_bytes(&bytes);
assert!(result.is_err());
assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
}
#[test]
fn nan_try_cast_fails() {
let value = f64::NAN;
let bytes = value.to_ne_bytes();
let result: Result<&RealNative64StrictFinite, CheckedCastError> =
try_from_bytes(&bytes);
assert!(result.is_err());
assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
}
#[test]
fn infinity_from_bytes_fails() {
let value = f64::INFINITY;
let bytes = value.to_ne_bytes();
let result: Result<&RealNative64StrictFinite, CheckedCastError> =
try_from_bytes(&bytes);
assert!(result.is_err());
assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
}
#[test]
fn neg_infinity_from_bytes_fails() {
let value = f64::NEG_INFINITY;
let bytes = value.to_ne_bytes();
let result: Result<&RealNative64StrictFinite, CheckedCastError> =
try_from_bytes(&bytes);
assert!(result.is_err());
assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
}
#[test]
fn subnormal_from_bytes_fails() {
let value = f64::MIN_POSITIVE / 2.0; let bytes = value.to_ne_bytes();
let result: Result<&RealNative64StrictFinite, CheckedCastError> =
try_from_bytes(&bytes);
assert!(result.is_err());
assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
}
#[test]
fn round_trip_conversion() {
let original = RealNative64StrictFinite::try_new(123.456).unwrap();
let as_f64 = *original.as_ref();
let bytes = as_f64.to_ne_bytes();
let from_bytes: &RealNative64StrictFinite = try_from_bytes(&bytes).unwrap();
assert_eq!(original, *from_bytes);
}
#[test]
fn vec_conversion() {
let values = vec![
RealNative64StrictFinite::try_new(1.0).unwrap(),
RealNative64StrictFinite::try_new(2.0).unwrap(),
RealNative64StrictFinite::try_new(3.0).unwrap(),
RealNative64StrictFinite::try_new(4.0).unwrap(),
];
let bytes = bytemuck::cast_slice::<RealNative64StrictFinite, u8>(&values);
let result: Result<&[RealNative64StrictFinite], CheckedCastError> =
bytemuck::checked::try_cast_slice(bytes);
assert!(result.is_ok());
let validated_slice = result.unwrap();
assert_eq!(validated_slice.len(), 4);
assert_eq!(*validated_slice[0].as_ref(), 1.0);
assert_eq!(*validated_slice[3].as_ref(), 4.0);
}
#[test]
fn direct_f64_slice_with_invalid_values() {
let mut bytes = Vec::new();
bytes.extend_from_slice(&1.0_f64.to_ne_bytes());
bytes.extend_from_slice(&f64::NAN.to_ne_bytes());
bytes.extend_from_slice(&3.0_f64.to_ne_bytes());
let result: Result<&[RealNative64StrictFinite], CheckedCastError> =
bytemuck::checked::try_cast_slice(&bytes);
assert!(result.is_err());
}
}
mod vec_conversions {
use super::*;
use try_create::TryNew;
#[test]
fn vec_f64_to_validated_all_valid() {
let f64_vec = [1.0, 2.5, -3.7, 0.0, 42.0];
let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
.iter()
.map(|&x| RealNative64StrictFinite::try_new(x))
.collect();
assert!(validated_vec.is_ok());
let validated_vec = validated_vec.unwrap();
assert_eq!(validated_vec.len(), 5);
assert_eq!(*validated_vec[0].as_ref(), 1.0);
assert_eq!(*validated_vec[1].as_ref(), 2.5);
assert_eq!(*validated_vec[2].as_ref(), -3.7);
assert_eq!(*validated_vec[3].as_ref(), 0.0);
assert_eq!(*validated_vec[4].as_ref(), 42.0);
}
#[test]
fn vec_f64_to_validated_with_nan() {
let f64_vec = [1.0, 2.5, f64::NAN, 0.0, 42.0];
let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
.iter()
.map(|&x| RealNative64StrictFinite::try_new(x))
.collect();
assert!(validated_vec.is_err());
}
#[test]
fn vec_f64_to_validated_with_infinity() {
let f64_vec = [1.0, f64::INFINITY, 3.0];
let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
.iter()
.map(|&x| RealNative64StrictFinite::try_new(x))
.collect();
assert!(validated_vec.is_err());
}
#[test]
fn vec_f64_to_validated_with_subnormal() {
let subnormal = f64::MIN_POSITIVE / 2.0;
let f64_vec = [1.0, subnormal, 3.0];
let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
.iter()
.map(|&x| RealNative64StrictFinite::try_new(x))
.collect();
assert!(validated_vec.is_err());
}
#[test]
fn vec_validated_to_f64() {
let validated_vec = [
RealNative64StrictFinite::try_new(1.0).unwrap(),
RealNative64StrictFinite::try_new(2.5).unwrap(),
RealNative64StrictFinite::try_new(-3.7).unwrap(),
RealNative64StrictFinite::try_new(0.0).unwrap(),
RealNative64StrictFinite::try_new(42.0).unwrap(),
];
let f64_vec: Vec<f64> = validated_vec.iter().map(|x| *x.as_ref()).collect();
assert_eq!(f64_vec.len(), 5);
assert_eq!(f64_vec[0], 1.0);
assert_eq!(f64_vec[1], 2.5);
assert_eq!(f64_vec[2], -3.7);
assert_eq!(f64_vec[3], 0.0);
assert_eq!(f64_vec[4], 42.0);
}
#[test]
fn vec_round_trip_conversion() {
let original_f64 = vec![1.0, 2.5, -3.7, 0.0, 42.0, -999.123];
let validated_vec: Vec<RealNative64StrictFinite> = original_f64
.iter()
.map(|&x| RealNative64StrictFinite::try_new(x).unwrap())
.collect();
let final_f64: Vec<f64> = validated_vec.iter().map(|x| *x.as_ref()).collect();
let slice_f64 =
bytemuck::cast_slice::<RealNative64StrictFinite, f64>(&validated_vec);
assert_eq!(slice_f64, &original_f64);
assert_eq!(original_f64, final_f64);
}
#[test]
fn vec_empty() {
let f64_vec: Vec<f64> = vec![];
let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
.iter()
.map(|&x| RealNative64StrictFinite::try_new(x))
.collect();
assert!(validated_vec.is_ok());
assert_eq!(validated_vec.unwrap().len(), 0);
}
#[test]
fn vec_large_values() {
let f64_vec = vec![f64::MAX, f64::MIN, f64::MIN_POSITIVE, -f64::MIN_POSITIVE];
let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
.iter()
.map(|&x| RealNative64StrictFinite::try_new(x))
.collect();
assert!(validated_vec.is_ok());
let validated_vec = validated_vec.unwrap();
let f64_back: Vec<f64> = validated_vec.iter().map(|x| *x.as_ref()).collect();
assert_eq!(f64_vec, f64_back);
}
#[test]
fn vec_with_zeros() {
let f64_vec = [0.0, -0.0, 1.0, -1.0];
let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
.iter()
.map(|&x| RealNative64StrictFinite::try_new(x))
.collect();
assert!(validated_vec.is_ok());
let validated_vec = validated_vec.unwrap();
assert_eq!(*validated_vec[0].as_ref(), 0.0);
assert_eq!(*validated_vec[1].as_ref(), -0.0);
}
#[test]
fn vec_using_from_iter() {
let f64_vec = [1.0, 2.0, 3.0, 4.0, 5.0];
let validated_vec: Vec<RealNative64StrictFinite> = f64_vec
.iter()
.filter_map(|&x| RealNative64StrictFinite::try_new(x).ok())
.collect();
assert_eq!(validated_vec.len(), 5);
}
#[test]
fn vec_conversion_preserves_order() {
let f64_vec: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
let validated_vec: Vec<RealNative64StrictFinite> = f64_vec
.iter()
.map(|&x| RealNative64StrictFinite::try_new(x).unwrap())
.collect();
for (i, val) in validated_vec.iter().enumerate() {
assert_eq!(*val.as_ref(), i as f64 * 0.1);
}
}
#[test]
fn vec_partial_conversion_with_find() {
let f64_vec = [1.0, 2.0, f64::NAN, 4.0, 5.0];
let (invalid_idx, _) = f64_vec
.iter()
.enumerate()
.find(|(_, x)| RealNative64StrictFinite::try_new(**x).is_err())
.expect("Should find invalid value");
assert_eq!(invalid_idx, 2);
}
#[test]
fn vec_consume_and_convert() {
let f64_vec = vec![1.0, 2.0, 3.0];
let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
.into_iter()
.map(RealNative64StrictFinite::try_new)
.collect();
assert!(validated_vec.is_ok());
assert_eq!(validated_vec.unwrap().len(), 3);
}
#[test]
fn vec_validated_to_f64_with_try_cast_vec() {
use bytemuck::allocation::try_cast_vec;
let validated_vec: Vec<RealNative64StrictFinite> = vec![
RealNative64StrictFinite::try_new(1.0).unwrap(),
RealNative64StrictFinite::try_new(2.5).unwrap(),
RealNative64StrictFinite::try_new(-3.7).unwrap(),
RealNative64StrictFinite::try_new(0.0).unwrap(),
RealNative64StrictFinite::try_new(42.0).unwrap(),
];
let f64_vec_result: Result<Vec<f64>, _> = try_cast_vec(validated_vec);
assert!(
f64_vec_result.is_ok(),
"try_cast_vec should work for Vec<RealNative64StrictFinite> -> Vec<f64>"
);
let f64_vec = f64_vec_result.unwrap();
assert_eq!(f64_vec.len(), 5);
assert_eq!(f64_vec[0], 1.0);
assert_eq!(f64_vec[1], 2.5);
assert_eq!(f64_vec[2], -3.7);
assert_eq!(f64_vec[3], 0.0);
assert_eq!(f64_vec[4], 42.0);
}
#[test]
fn vec_f64_to_validated_try_cast_vec_fails() {
let f64_vec = [1.0, 2.5, -3.7, 0.0, 42.0];
let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
.iter()
.map(|&x| RealNative64StrictFinite::try_new(x))
.collect();
assert!(validated_vec.is_ok());
assert_eq!(validated_vec.unwrap().len(), 5);
}
}
mod real_strict_finite_in_debug {
use super::*;
#[test]
fn valid_value_from_bytes() {
let value = 42.0_f64;
let bytes = value.to_ne_bytes();
let result: Result<&RealNative64StrictFiniteInDebug, CheckedCastError> =
try_from_bytes(&bytes);
assert!(result.is_ok());
assert_eq!(*result.unwrap().as_ref(), 42.0);
}
#[test]
fn nan_from_bytes() {
let value = f64::NAN;
let bytes = value.to_ne_bytes();
let result: Result<&RealNative64StrictFiniteInDebug, CheckedCastError> =
try_from_bytes(&bytes);
#[cfg(debug_assertions)]
{
assert!(result.is_err());
assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
}
#[cfg(not(debug_assertions))]
{
assert!(result.is_ok());
}
}
#[test]
fn infinity_from_bytes() {
let value = f64::INFINITY;
let bytes = value.to_ne_bytes();
let result: Result<&RealNative64StrictFiniteInDebug, CheckedCastError> =
try_from_bytes(&bytes);
#[cfg(debug_assertions)]
{
assert!(result.is_err());
}
#[cfg(not(debug_assertions))]
{
assert!(result.is_ok());
}
}
#[test]
fn round_trip_with_valid_value() {
let original = RealNative64StrictFiniteInDebug::try_new(123.456).unwrap();
let as_f64 = *original.as_ref();
let bytes = as_f64.to_ne_bytes();
let from_bytes: &RealNative64StrictFiniteInDebug = try_from_bytes(&bytes).unwrap();
assert_eq!(original, *from_bytes);
}
}
#[test]
fn alignment_check() {
use std::mem;
assert_eq!(
mem::align_of::<RealNative64StrictFinite>(),
mem::align_of::<f64>()
);
assert_eq!(
mem::size_of::<RealNative64StrictFinite>(),
mem::size_of::<f64>()
);
}
}
mod copy_trait_tests {
use super::*;
mod real_copy {
use super::*;
#[test]
fn real_is_copy() {
fn assert_copy<T: Copy>() {}
assert_copy::<RealNative64StrictFinite>();
assert_copy::<RealNative64StrictFiniteInDebug>();
}
#[test]
fn real_copy_semantics() {
let x = RealNative64StrictFinite::try_new(3.).unwrap();
let y = x; let z = x; assert_eq!(x, y);
assert_eq!(x, z);
}
#[test]
fn real_copy_in_function_call() {
fn takes_by_value(val: RealNative64StrictFinite) -> f64 {
*val.as_ref()
}
let x = RealNative64StrictFinite::try_new(42.0).unwrap();
let result1 = takes_by_value(x);
let result2 = takes_by_value(x); assert_eq!(result1, 42.0);
assert_eq!(result2, 42.0);
}
#[test]
fn real_copy_in_loop() {
let x = RealNative64StrictFinite::try_new(1.0).unwrap();
let mut sum = RealNative64StrictFinite::zero();
for _ in 0..5 {
sum += x; }
assert_eq!(*sum.as_ref(), 5.0);
assert_eq!(*x.as_ref(), 1.0); }
#[test]
fn real_copy_with_arithmetic() {
let a = RealNative64StrictFinite::try_new(2.0).unwrap();
let b = RealNative64StrictFinite::try_new(3.0).unwrap();
let sum = a + b;
let diff = a - b;
let prod = a * b;
let quot = a / b;
assert_eq!(*a.as_ref(), 2.0);
assert_eq!(*b.as_ref(), 3.0);
assert_eq!(*sum.as_ref(), 5.0);
assert_eq!(*diff.as_ref(), -1.0);
assert_eq!(*prod.as_ref(), 6.0);
assert!((quot.as_ref() - 2.0 / 3.0).abs() < 1e-10);
}
}
mod complex_copy {
use super::*;
#[test]
fn complex_is_copy() {
fn assert_copy<T: Copy>() {}
assert_copy::<ComplexNative64StrictFinite>();
assert_copy::<ComplexNative64StrictFiniteInDebug>();
}
#[test]
fn complex_copy_semantics() {
let z = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
let w = z; let v = z; assert_eq!(z, w);
assert_eq!(z, v);
}
#[test]
fn complex_copy_in_function_call() {
fn takes_by_value(val: ComplexNative64StrictFinite) -> Complex<f64> {
val.into_inner()
}
let z = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
let result1 = takes_by_value(z);
let result2 = takes_by_value(z); assert_eq!(result1, Complex::new(3.0, 4.0));
assert_eq!(result2, Complex::new(3.0, 4.0));
}
#[test]
fn complex_copy_with_arithmetic() {
let a = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
let b = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
let sum = a + b;
let diff = a - b;
let prod = a * b;
assert_eq!(a.into_inner(), Complex::new(1.0, 2.0));
assert_eq!(b.into_inner(), Complex::new(3.0, 4.0));
assert_eq!(sum.into_inner(), Complex::new(4.0, 6.0));
assert_eq!(diff.into_inner(), Complex::new(-2.0, -2.0));
assert_eq!(prod.into_inner(), Complex::new(-5.0, 10.0));
}
#[test]
fn complex_copy_in_loop() {
let z = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 1.0)).unwrap();
let mut sum = ComplexNative64StrictFinite::zero();
for _ in 0..3 {
sum += z; }
assert_eq!(sum.into_inner(), Complex::new(3.0, 3.0));
assert_eq!(z.into_inner(), Complex::new(1.0, 1.0)); }
}
mod mixed_copy {
use super::*;
#[test]
fn real_and_complex_copy_in_expression() {
let r = RealNative64StrictFinite::try_new(2.0).unwrap();
let z = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 1.0)).unwrap();
let result1 = z * r;
let result2 = z * r;
assert_eq!(*r.as_ref(), 2.0);
assert_eq!(z.into_inner(), Complex::new(1.0, 1.0));
assert_eq!(result1.into_inner(), Complex::new(2.0, 2.0));
assert_eq!(result2.into_inner(), Complex::new(2.0, 2.0));
}
}
}
}