use num::One;
use num_valid::functions::{Abs, ComplexScalarConstructors, Conjugate, Exp, Ln, Reciprocal, Sqrt};
use num_valid::{
RealScalar,
backends::native64::validated::{ComplexNative64StrictFinite, RealNative64StrictFinite},
};
use try_create::TryNew;
#[test]
fn test_quick_example() -> Result<(), Box<dyn std::error::Error>> {
let x = RealNative64StrictFinite::try_new(4.0)?;
let sqrt_x = x.sqrt(); assert_eq!(*sqrt_x.as_ref(), 2.0);
let bad = RealNative64StrictFinite::try_new(f64::NAN); assert!(bad.is_err());
Ok(())
}
#[test]
fn test_basic_usage() -> Result<(), Box<dyn std::error::Error>> {
let x = RealNative64StrictFinite::try_new(4.0)?;
let sqrt_x = x.sqrt();
assert_eq!(*sqrt_x.as_ref(), 2.0);
let neg = RealNative64StrictFinite::try_new(-4.0)?;
match neg.try_sqrt() {
Ok(_result) => panic!("Should have failed"),
Err(_e) => {} }
Ok(())
}
#[test]
fn test_generic_functions() -> Result<(), Box<dyn std::error::Error>> {
fn pythagorean_identity<T: RealScalar>(angle: T) -> T {
let sin_x = angle.clone().sin();
let cos_x = angle.cos();
(sin_x.clone() * sin_x) + (cos_x.clone() * cos_x)
}
let angle = RealNative64StrictFinite::try_from_f64(0.5)?;
let result = pythagorean_identity(angle);
let one = RealNative64StrictFinite::one();
let diff = (result - one).abs();
assert!(*diff.as_ref() < 1e-15);
Ok(())
}
#[cfg(feature = "rug")]
#[test]
fn test_arbitrary_precision() -> Result<(), Box<dyn std::error::Error>> {
use num_valid::RealRugStrictFinite;
fn pythagorean_identity<T: RealScalar>(angle: T) -> T {
let sin_x = angle.clone().sin();
let cos_x = angle.cos();
(sin_x.clone() * sin_x) + (cos_x.clone() * cos_x)
}
type HighPrecision = RealRugStrictFinite<200>;
let angle = HighPrecision::try_from_f64(0.5)?;
let result = pythagorean_identity(angle);
let one = HighPrecision::one();
let diff = (result - one).abs();
let threshold = HighPrecision::try_from_f64(1e-50)?;
assert!(*diff.as_ref() < *threshold.as_ref());
Ok(())
}
#[test]
fn test_complex_numbers() {
let re = RealNative64StrictFinite::from_f64(3.0);
let im = RealNative64StrictFinite::from_f64(4.0);
let z = ComplexNative64StrictFinite::new_complex(re, im);
let magnitude = z.abs(); assert_eq!(*magnitude.as_ref(), 5.0);
let _conjugate = z.conjugate(); let _reciprocal = z.reciprocal();
let _exp_z = z.exp();
let _log_z = z.ln();
let _sqrt_z = z.sqrt();
}
#[test]
fn test_zero_copy_conversions() {
use bytemuck::checked::try_from_bytes;
let bytes = 42.0_f64.to_ne_bytes();
let validated: &RealNative64StrictFinite = try_from_bytes(&bytes).unwrap();
assert_eq!(*validated.as_ref(), 42.0);
let nan_bytes = f64::NAN.to_ne_bytes();
assert!(try_from_bytes::<RealNative64StrictFinite>(&nan_bytes).is_err());
}
#[test]
fn test_error_handling_propagation() -> Result<(), Box<dyn std::error::Error>> {
use num_valid::functions::Sqrt;
fn compute_radius(area: f64) -> Result<RealNative64StrictFinite, Box<dyn std::error::Error>> {
let validated_area = RealNative64StrictFinite::try_from_f64(area)?;
let pi = RealNative64StrictFinite::try_from_f64(std::f64::consts::PI)?;
let radius_squared = validated_area / pi;
Ok(radius_squared.try_sqrt()?)
}
let radius = compute_radius(std::f64::consts::PI * 4.0)?; let expected = RealNative64StrictFinite::try_from_f64(2.0)?;
let diff = (radius - expected).abs();
assert!(*diff.as_ref() < 1e-10);
let result = compute_radius(-1.0);
assert!(result.is_err());
Ok(())
}
#[test]
fn test_error_handling_match_variants() {
use num_valid::functions::{Sqrt, SqrtRealErrors, SqrtRealInputErrors};
fn sqrt_with_fallback(x: RealNative64StrictFinite) -> RealNative64StrictFinite {
match x.try_sqrt() {
Ok(result) => result,
Err(SqrtRealErrors::Input {
source: SqrtRealInputErrors::NegativeValue { .. },
}) => {
(-x).sqrt()
}
Err(e) => panic!("Unexpected error: {e}"),
}
}
let x = RealNative64StrictFinite::from_f64(4.0);
let result = sqrt_with_fallback(x);
assert_eq!(*result.as_ref(), 2.0);
let neg_x = RealNative64StrictFinite::from_f64(-9.0);
let result = sqrt_with_fallback(neg_x);
assert_eq!(*result.as_ref(), 3.0);
}