#![deny(rustdoc::broken_intra_doc_links)]

//! # Validated Native 64-bit Kernel Types
//!
//! This module provides convenient, pre-configured type aliases for the native `f64`
//! kernel. These types wrap [`f64`] and [`num::Complex<f64>`] in the [`RealValidated`]
//! and [`ComplexValidated`] structs, bundling them with specific *validation policies*.
//!
//! These type aliases are the primary entry point for users who want to work with
//! validated numbers that provide compile-time guarantees about their properties (e.g., finiteness).
//!
//! ## Policies
//!
//! Two main policies are provided:
//!
//! - **[`Native64StrictFinite`]:** Enforces that all values are finite (not `NaN` or `Infinity`)
//!   in all build modes. Operations on types using this policy will panic on validation
//!   failure in debug builds and return a `Result` in release builds. This is the safest and
//!   most common choice.
//!
//! - **[`Native64StrictFiniteInDebug`]:** Also enforces finiteness, but validation checks that
//!   would panic are **only performed in debug builds**. In release builds, these checks are
//!   skipped for performance, and operations assume the inputs are valid. This is for
//!   performance-critical code where the developer can guarantee the validity of inputs.
//!
//! ## Example
//!
//! ```rust
//! use num_valid::kernels::native64_validated::RealNative64StrictFinite;
//! use num_valid::functions::Sqrt;
//! use try_create::TryNew;
//!
//! // Creation succeeds because 4.0 is a valid, finite number.
//! let x = RealNative64StrictFinite::try_new(4.0).unwrap();
//!
//! // Creation fails for non-finite numbers.
//! assert!(RealNative64StrictFinite::try_new(f64::NAN).is_err());
//!
//! // Mathematical operations are available through traits.
//! let sqrt_x = x.sqrt();
//! assert_eq!(*sqrt_x.as_ref(), 2.0);
//! ```
//!
//! ## Zero-Copy Conversions with Bytemuck
//!
//! The validated types in this module implement [`bytemuck::CheckedBitPattern`] and
//! [`bytemuck::NoUninit`], enabling safe, zero-copy conversions between `f64` byte
//! representations and validated types. This is particularly useful for:
//!
//! - Interoperability with binary data formats and serialization
//! - Performance-critical code working with byte arrays
//! - Loading validated numbers from external data sources
//!
//! The conversion automatically validates the bit pattern, rejecting invalid values
//! (NaN, Infinity, subnormal numbers) while maintaining zero-cost performance for
//! valid inputs:
//!
//! ```rust
//! use num_valid::RealNative64StrictFinite;
//! use bytemuck::checked::try_from_bytes;
//!
//! // Valid conversion
//! let value = 42.0_f64;
//! let bytes = value.to_ne_bytes();
//! let validated: &RealNative64StrictFinite = try_from_bytes(&bytes).unwrap();
//! assert_eq!(*validated.as_ref(), 42.0);
//!
//! // Invalid values are rejected
//! let nan_bytes = f64::NAN.to_ne_bytes();
//! assert!(try_from_bytes::<RealNative64StrictFinite>(&nan_bytes).is_err());
//! ```
//!
//! For comprehensive examples of valid conversions, error handling, and slice operations,
//! see the test module in the source code.

use crate::kernels::{
    ComplexValidated, NumKernelStrictFinite, NumKernelStrictFiniteInDebug, RealValidated,
};

//------------------------------------------------------------------------------------------------------------
/// A kernel policy that enforces strict finiteness for `f64` and `Complex<f64>` values.
///
/// This is a type alias for [`NumKernelStrictFinite<f64, 53>`].
///
/// It ensures that all validated values are finite (not `NaN` or `Infinity`).
/// In debug builds, operations that fail validation will panic. In release builds, they
/// will return an error. This policy is used by [`RealNative64StrictFinite`] and
/// [`ComplexNative64StrictFinite`].
pub type Native64StrictFinite = NumKernelStrictFinite<f64, 53>;
//------------------------------------------------------------------------------------------------------------

//------------------------------------------------------------------------------------------------------------
/// A kernel policy that enforces strict finiteness for `f64` values **only in debug builds**.
///
/// This is a type alias for [`NumKernelStrictFiniteInDebug<f64, 53>`].
///
/// This policy is designed for performance-critical applications. In debug builds, it
/// behaves identically to [`Native64StrictFinite`], panicking on validation failures.
/// In **release builds**, these validation checks are **disabled**, and operations proceed
/// assuming the inputs are valid. Use this policy with caution when you can guarantee
/// the integrity of your data in release environments.
pub type Native64StrictFiniteInDebug = NumKernelStrictFiniteInDebug<f64, 53>;
//------------------------------------------------------------------------------------------------------------

//------------------------------------------------------------------------------------------------------------
/// A validated real number that guarantees its inner `f64` value is finite.
///
/// This is a type alias for [`RealValidated<Native64StrictFinite>`].
///
/// It is the standard, safe-to-use validated real number type for the native `f64` kernel.
/// It prevents the representation of `NaN` and `Infinity`.
pub type RealNative64StrictFinite = RealValidated<Native64StrictFinite>;

/// A validated complex number that guarantees its inner `f64` parts are finite.
///
/// This is a type alias for [`ComplexValidated<Native64StrictFinite>`].
///
/// It is the standard, safe-to-use validated complex number type for the native `f64` kernel.
/// It ensures that both the real and imaginary components are finite values.
pub type ComplexNative64StrictFinite = ComplexValidated<Native64StrictFinite>;
//------------------------------------------------------------------------------------------------------------

//------------------------------------------------------------------------------------------------------------
/// A validated real number that checks for finiteness **only in debug builds**.
///
/// This is a type alias for [`RealValidated<Native64StrictFiniteInDebug>`].
///
/// Use this type in performance-sensitive contexts where the overhead of validation
/// in release builds is unacceptable and inputs are known to be valid.
pub type RealNative64StrictFiniteInDebug = RealValidated<Native64StrictFiniteInDebug>;

/// A validated complex number that checks for finiteness **only in debug builds**.
///
/// This is a type alias for [`ComplexValidated<Native64StrictFiniteInDebug>`].
///
/// Use this type in performance-sensitive contexts where the overhead of validation
/// in release builds is unacceptable and inputs are known to be valid.
pub type ComplexNative64StrictFiniteInDebug = ComplexValidated<Native64StrictFiniteInDebug>;
//------------------------------------------------------------------------------------------------------------

// --- Hashing Implementation ---------------------------------------------------------
// Note: The Hash trait is implemented generically in the validation module for all
// RealValidated<K> types where K::RealPolicy implements GuaranteesFiniteValues.
// This ensures that validated types with finite value guarantees can be used as
// keys in HashMap and other hash-based collections.
//
// The implementation hashes the raw IEEE 754 bit representation of the f64 value,
// with special handling for signed zeros to maintain the hash contract that
// a == b implies hash(a) == hash(b).
//-------------------------------------------------------------

//------------------------------------------------------------------------------------------------
#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        Clamp, ComplexScalarConstructors, ComplexScalarGetParts, ComplexScalarMutateParts,
        ComplexScalarSetParts, Constants, ExpM1, FpChecks, Hypot, Ln1p, MulAddRef, NegAssign,
        RealScalar, Rounding, Sign, TotalCmp,
        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, Pow,
            PowComplexBaseRealExponentErrors, PowIntExponentErrors, PowIntExponentInputErrors,
            PowRealBaseRealExponentErrors, Reciprocal, ReciprocalErrors, Sin, SinH, Sqrt,
            SqrtRealErrors, Tan, TanH,
        },
        validation::{ErrorsTryFromf64, ErrorsValidationRawComplex, ErrorsValidationRawReal},
    };
    use num::{Complex, One, Zero};
    use std::{
        cmp::Ordering,
        f64::consts::*,
        num::FpCategory,
        ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
    };
    use try_create::{IntoInner, New, 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: 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 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);
            }

            /*
            #[cfg(feature = "rug")]
            #[test]
            fn abs_nan() {
                let value =
                    RealValidated::try_new(rug::Float::with_val(53, rug::float::Special::Nan))
                        .unwrap();
                let result = value.try_abs();
                assert!(matches!(result, Err(AbsRealErrors::Input { .. })));
            }

            #[cfg(feature = "rug")]
            #[test]
            fn abs_infinite() {
                let value = RealValidated::try_new(rug::Float::with_val(
                    53,
                    rug::float::Special::Infinity,
                ))
                .unwrap();
                let result = value.try_abs();
                assert!(matches!(result, Err(AbsRealErrors::Input { .. })));
            }
            */
        }

        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);
            }
            /*
            #[test]
            fn abs_nan() {
                let value = Complex64Validated::try_new(Complex::new(
                    53,
                    (
                        rug::Float::with_val(53, rug::float::Special::Nan),
                        0.,
                    ),
                ))
                .unwrap();
                assert!(matches!(
                    value.try_abs(),
                    Err(AbsComplexErrors::Input { .. })
                ));
            }

            #[test]
            fn abs_infinite() {
                let value = Complex64Validated::try_new(Complex::new(
                    53,
                    (
                        rug::Float::with_val(53, rug::float::Special::Infinity),
                        0.,
                    ),
                ))
                .unwrap();
                assert!(matches!(
                    value.try_abs(),
                    Err(AbsComplexErrors::Input { .. })
                ));
            }
            */
        }
    }

    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::new(1.23);
                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::new(v);
                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: 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: 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: 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: 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: 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: 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: 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: 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()
                ); // (1*3 - 2*4) + (1*4 + 2*3)i
            }

            #[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(); // 2 * (3 + 4i) = 6 + 8i

                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(); // 2 * (3 + 4i) = 6 + 8i

                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();
                // 2*3 + 4 = 10
                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();
                // (1+2i)*(3+4i) + (5+6i) = (3+4i+6i-8) + (5+6i) = (-5+10i) + (5+6i) = 0+16i
                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);

            // Subnormals, Infinite and NaN are not constructible with StrictFinitePolicy

            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());

            // Using a tolerance for fract_ due to floating point representation
            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()); // +0.0 is 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() {
            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(&min_val, &max_val), val);
            assert_eq!(
                RealValidated::try_new(-5.)
                    .unwrap()
                    .clamp(&min_val, &max_val),
                min_val
            );
            assert_eq!(
                RealValidated::try_new(15.)
                    .unwrap()
                    .clamp(&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()
            );
            // rug::Float::signum of 0. is 1.
            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(); // mul
            let c = RealValidated::try_new(4.).unwrap(); // add_mul1
            let d = RealValidated::try_new(5.).unwrap(); // add_mul2
            // Expected: a = a*b + c*d = 2*3 + 4*5 = 6 + 20 = 26
            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(); // mul
            let c = RealValidated::try_new(3.).unwrap(); // sub_mul1
            let d = RealValidated::try_new(4.).unwrap(); // sub_mul2
            // Expected: a = a*b - c*d = 10*2 - 3*4 = 20 - 12 = 8
            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() {
            // arg(1 + 0i) = 0
            let c1 = ComplexValidated::one();
            assert_eq!(c1.arg(), RealValidated::zero());

            // arg(0 + i) = PI/2
            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);

            // arg(-1 + 0i) = PI
            let c3 = ComplexValidated::try_new_pure_real(-1.0).unwrap();
            let pi = RealValidated::try_new(PI).unwrap();
            assert_eq!(c3.arg(), pi);

            // arg(1 + i) = PI/4
            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(&r2), &r2);
                assert_eq!(r2.max(&r1), &r2);
            }

            #[test]
            fn min_valid() {
                let r1 = RealValidated::try_new(3.).unwrap();
                let r2 = RealValidated::try_new(4.).unwrap();
                assert_eq!(r1.min(&r2), &r1);
                assert_eq!(r2.min(&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 = if cfg!(target_arch = "x86_64") {
                        1.718281828459045
                    } else if cfg!(target_arch = "aarch64") {
                        1.7182818284590453
                    } else {
                        todo!("Not implemented for this architecture");
                    };
                    assert_eq!(exponent.exp_m1().as_ref(), &expected);
                }

                #[test]
                fn exp_overflow() {
                    let large_val = RealValidated::try_new(1.0e60).unwrap(); // exp(1.0e60) is very large
                    let res_large = large_val.try_exp();
                    assert!(matches!(
                        res_large,
                        Err(ExpErrors::Output {
                            source: ErrorsValidationRawReal::IsPosInfinity { .. }
                        })
                    ),);
                }
            } // end mod 

            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);
                }
            } // end mod complex
        } // end mod exp

        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() {
                    // v = e - 1;
                    let v = RealValidated::one().exp() - RealValidated::one();

                    // ln(1 + v) = ln(1 + e - 1) = ln(e) = 1
                    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 { .. }
                        })
                    ));
                }
            } // end mod real

            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 { .. }
                        })
                    ));
                }
            } // end mod complex
        } // end mod logarithm

        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 { .. }
                        })
                    ));
                }
            }
        } // end mod reciprocal

        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 { .. }
                        })
                    ));
                }
            } // end mod real

            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);
                }
            }
        } // end mod sqrt

        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 = if cfg!(target_arch = "x86_64") {
                        1.5574077246549023
                    } else if cfg!(target_arch = "aarch64") {
                        1.557407724654902
                    } else {
                        todo!("Implement for other architectures");
                    };
                    assert_eq!(v.try_tan().unwrap().as_ref(), &expected);
                    assert_eq!(v.tan().as_ref(), &expected);
                }

                #[test]
                fn asin_real_valid() {
                    let v = RealValidated::one();

                    let expected = std::f64::consts::FRAC_PI_2; // π/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; // π/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; // π/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; // π/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]
                #[ignore = "at the moment we cannot create a pole for the Tan function"]
                fn tan_real_pole() {
                    // tan(PI/2) is a pole
                    let pi_half = RealValidated::pi_div_2();
                    let res = pi_half.try_tan();
                    println!("Result: {:?}", res);
                    assert!(matches!(
                        res,
                        Err(TanRealErrors::Input {
                            source: TanRealInputErrors::ArgumentIsPole { .. }
                        })
                    ));
                }
                */

                #[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 { .. }
                        })
                    ));
                }
            } // end mod real

            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!("Implement for other architectures");
                    };
                    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!("Implement for other architectures");
                    };
                    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() {
                    // atan(i) and atan(-i) are poles
                    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 { .. }
                        })
                    ));
                }
            } // end mod complex
        } // end mod trigonometric

        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(); // atanh(1) is Inf
                    assert!(matches!(
                        val_ge_1.try_atanh(),
                        Err(ATanHErrors::Input {
                            source: ATanHInputErrors::OutOfDomain { .. }
                        })
                    ));

                    let val_le_neg1 = RealValidated::negative_one(); // atanh(-1) is -Inf
                    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!("Missing target architecture!");
                    };
                    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]
                #[ignore = "at the moment we cannot create a pole for the ATanH function"]
                fn tanh_complex_pole() {
                    // tanh(z) has poles where cosh(z) = 0. e.g. z = i * (PI/2 + k*PI)
                    let pi_half = RealValidated::pi_div_2().into_inner();
                    let pole_val =
                        Complex64Validated::try_new_pure_imaginary(pi_half).unwrap();
                    println!("Atanh(Pole value): {:?}", pole_val.clone().try_tanh());
                    assert!(matches!(
                        pole_val.try_tanh(),
                        Err(TanHComplexErrors::Input {
                            source: TanHComplexInputErrors::OutOfDomain { .. }
                        })
                    ));
                }
                */

                #[test]
                fn acosh_out_of_domain() {
                    // acosh(z) domain is C \ (-inf, 1) on real axis
                    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 { .. }
                        })
                    ));
                }
            }

            /*
            #[test]
            #[ignore = "at the moment we cannot create a pole for the TanH function"]
            fn tanh_out_of_domain() {
                // tanh(z) has poles where cosh(z) = 0. e.g. z = i * (PI/2 + k*PI)
                let pi_half = RealValidated::pi_div_2().into_inner();
                let pole_val = Complex64Validated::try_new_pure_imaginary(pi_half).unwrap();
                println!("TanH(Pole value): {:?}", pole_val.clone().try_tanh());
                assert!(matches!(
                    pole_val.try_tanh(),
                    Err(TanHComplexErrors::Input {
                        source: TanHComplexInputErrors::OutOfDomain { .. }
                    })
                ));
            }
            */
        } // end mod hyperbolic
    }

    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() {
            // Test case where simple summation might lose precision
            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();
            // The Neumaier sum should correctly result in 1.0
            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()
            );
        }
    } // end mod summation

    mod neumaier_sum {
        use crate::neumaier_compensated_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 crate::{
            RandomSampleFromF64,
            kernels::native64_validated::{ComplexNative64StrictFinite, RealNative64StrictFinite},
            new_random_vec,
        };
        use rand::{Rng, SeedableRng, distr::Uniform, rngs::StdRng};

        /// Tests the random generation of a `RealValidated` value.
        /// It uses a seeded RNG to ensure deterministic results and checks
        /// if the generated value falls within the expected [0, 1) range.
        #[test]
        fn test_random_real_validated() {
            let seed = [42; 32];
            let mut rng = StdRng::from_seed(seed);

            let random_real: RealNative64StrictFinite = rng.random();

            // rng.random::<f64>() produces a value in [0, 1), so the converted value should be in the same range.
            assert_eq!(random_real, 0.23713468825474326);

            // Check for determinism
            let mut rng2 = StdRng::from_seed(seed);
            let random_real2: RealNative64StrictFinite = rng2.random();
            assert_eq!(random_real, random_real2);
        }

        /// Tests the random generation of a `ComplexValidated` value.
        /// It uses a seeded RNG for determinism and verifies that both the real
        /// and imaginary parts of the generated complex number are within the
        /// expected [0, 1) range.
        #[test]
        fn test_random_complex_validated() {
            let seed = [99; 32];
            let mut rng = StdRng::from_seed(seed);

            let random_complex: ComplexNative64StrictFinite = rng.random();

            // The real and imaginary parts are generated independently,
            // so both should be in the [0, 1) range.
            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);

            // Check for determinism
            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);

            // Check determinism
            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);

            // Check determinism
            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);

            // Check determinism
            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);

            // Check determinism
            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::{
            functions::Sign,
            kernels::native64_validated::{
                ComplexNative64StrictFinite, RealNative64StrictFinite,
                RealNative64StrictFiniteInDebug,
            },
        };
        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);

            // Overwrite an existing key
            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);

            // Overwrite an existing key
            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(); // Same as key1

            // Insert and verify
            assert_eq!(map.insert(key1, "one"), None);
            assert_eq!(map.insert(key2, "two_point_five"), None);
            assert_eq!(map.len(), 2);

            // Test key equality (key3 should be equal to key1)
            assert_eq!(map.get(&key3), Some(&"one"));

            // Overwrite existing key
            assert_eq!(map.insert(key3, "one_updated"), Some("one"));
            assert_eq!(map.len(), 2); // Size shouldn't change
        }

        #[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)); // Should return false (already exists)

            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();

            // Equal values should have equal hashes
            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); // Verify they're actually equal
        }

        #[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());

            // Verify the underlying f64 values have different bit patterns
            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); // Verify they're actually equal

            // Equal values should have equal hashes
            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);

            // Overwrite an existing key
            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();

            // Equal values should have equal hashes
            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); // Verify they're actually equal
        }

        #[test]
        fn test_complex_hash_signed_zero() {
            use std::collections::hash_map::DefaultHasher;
            use std::hash::{Hash, Hasher};

            // Test all combinations of signed zeros
            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();

            // All should be equal
            assert_eq!(val1, val2);
            assert_eq!(val1, val3);
            assert_eq!(val1, val4);

            // All should have the same hash
            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();

            // Different values should (very likely) have different hashes
            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();

            // These are not guaranteed but extremely likely
            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)); // Should return false (already exists)

            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::validation::ErrorsRawRealToInteger;

        #[test]
        fn test_positive_integers() {
            // Whole numbers should convert exactly
            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() {
            // Positive fractional parts should be discarded (truncated toward zero)
            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() {
            // Zero should convert to 0
            let value = RealNative64StrictFinite::try_new(0.0).unwrap();
            assert_eq!(value.truncate_to_usize().unwrap(), 0);

            // Positive fractional values less than 1 should truncate to 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() {
            // Large but representable values within usize range
            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);

            // Test with a value close to but less than usize::MAX (on 64-bit systems)
            let max_safe = (usize::MAX as f64) - 2048.0; // Subtract to avoid precision issues
            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() {
            // Negative values should return OutOfRange 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() {
            // Values larger than usize::MAX should return OutOfRange 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() {
            // Test values very close to boundaries

            // Just above zero
            let value = RealNative64StrictFinite::try_new(f64::EPSILON).unwrap();
            assert_eq!(value.truncate_to_usize().unwrap(), 0);

            // Just below 1
            let value = RealNative64StrictFinite::try_new(1.0 - f64::EPSILON).unwrap();
            assert_eq!(value.truncate_to_usize().unwrap(), 0);

            // Just above 1
            let value = RealNative64StrictFinite::try_new(1.0 + f64::EPSILON).unwrap();
            assert_eq!(value.truncate_to_usize().unwrap(), 1);
        }

        #[test]
        fn test_truncation_behavior() {
            // Verify truncation (toward zero) behavior vs other rounding modes
            let test_cases = [
                (2.1, 2),
                (2.5, 2), // truncate, not round
                (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() {
            // Test that error variants contain expected information

            // OutOfRange error for negative value
            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");
            }

            // OutOfRange error for too large 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() {
            // Test a realistic usage scenario: creating a vector with calculated size
            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])
            }

            // Valid case
            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); // Truncated from 10.7

            // Error case - negative size
            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());

            // Error case - too large size
            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() {
            // Verify that our implementation behaves consistently with direct f64 operations
            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();

                // Compare with direct f64 truncation
                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; // subnormal
                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(),
                ];

                // Cast to bytes
                let bytes = bytemuck::cast_slice::<RealNative64StrictFinite, u8>(&values);

                // Try to cast back - should succeed
                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() {
                // Create bytes representing f64 values, some invalid
                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());

                // Should fail because of NaN
                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() {
                // Create a Vec<f64> with all valid values
                let f64_vec = [1.0, 2.5, -3.7, 0.0, 42.0];

                // Convert to Vec<RealNative64StrictFinite>
                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();

                // Verify length
                assert_eq!(validated_vec.len(), 5);

                // Verify values
                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() {
                // Create a Vec<f64> with a NaN value
                let f64_vec = [1.0, 2.5, f64::NAN, 0.0, 42.0];

                // Conversion should fail on the NaN
                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() {
                // Create a Vec<f64> with an infinity value
                let f64_vec = [1.0, f64::INFINITY, 3.0];

                // Conversion should fail on the infinity
                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() {
                // Create a Vec<f64> with a subnormal value
                let subnormal = f64::MIN_POSITIVE / 2.0;
                let f64_vec = [1.0, subnormal, 3.0];

                // Conversion should fail on the subnormal
                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() {
                // Create a Vec<RealNative64StrictFinite>
                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(),
                ];

                // Convert to Vec<f64>
                let f64_vec: Vec<f64> = validated_vec.iter().map(|x| *x.as_ref()).collect();

                // Verify length
                assert_eq!(f64_vec.len(), 5);

                // Verify values
                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() {
                // Start with Vec<f64>
                let original_f64 = vec![1.0, 2.5, -3.7, 0.0, 42.0, -999.123];

                // Convert to Vec<RealNative64StrictFinite>
                let validated_vec: Vec<RealNative64StrictFinite> = original_f64
                    .iter()
                    .map(|&x| RealNative64StrictFinite::try_new(x).unwrap())
                    .collect();

                // Convert back to Vec<f64>
                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);

                // Should be identical
                assert_eq!(original_f64, final_f64);
            }

            #[test]
            fn vec_empty() {
                // Empty Vec<f64>
                let f64_vec: Vec<f64> = vec![];

                // Convert to Vec<RealNative64StrictFinite>
                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() {
                // Test with extreme but valid values
                let f64_vec = vec![f64::MAX, f64::MIN, f64::MIN_POSITIVE, -f64::MIN_POSITIVE];

                // All should be valid
                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();

                // Verify round-trip
                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() {
                // Test with positive and negative 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() {
                // Test using from_iter for a more idiomatic approach
                let f64_vec = [1.0, 2.0, 3.0, 4.0, 5.0];

                // Using from_iter with filter_map to handle errors
                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() {
                // Test that order is preserved through conversion
                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();

                // Convert back and verify order
                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() {
                // Test finding the first invalid value
                let f64_vec = [1.0, 2.0, f64::NAN, 4.0, 5.0];

                // Find which index has the invalid value
                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() {
                // Test consuming the original vector
                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);

                // f64_vec is moved and cannot be used here
            }

            #[test]
            fn vec_validated_to_f64_with_try_cast_vec() {
                use bytemuck::allocation::try_cast_vec;

                // Create a Vec<RealNative64StrictFinite>
                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(),
                ];

                // Try to cast Vec<RealNative64StrictFinite> -> Vec<f64> using bytemuck
                let f64_vec_result: Result<Vec<f64>, _> = try_cast_vec(validated_vec);

                // This should work because:
                // - RealNative64StrictFinite implements NoUninit ✓
                // - f64 implements AnyBitPattern ✓
                // - Both have same size and alignment (repr(transparent)) ✓
                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() {
                // Create a Vec<f64>
                let f64_vec = [1.0, 2.5, -3.7, 0.0, 42.0];

                // Try to cast Vec<f64> -> Vec<RealNative64StrictFinite> using bytemuck
                // This SHOULD NOT compile because RealNative64StrictFinite does not implement AnyBitPattern
                // (it only implements CheckedBitPattern, which requires validation)

                // Uncomment the following line to verify it doesn't compile:
                // let validated_result: Result<Vec<RealNative64StrictFinite>, _> = try_cast_vec(f64_vec);

                // Instead, we must use the iterator approach with validation:
                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)]
                {
                    // In debug mode, should fail
                    assert!(result.is_err());
                    assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
                }

                #[cfg(not(debug_assertions))]
                {
                    // In release mode, validation is skipped
                    // This test documents the behavior but is NOT safe
                    // Don't use this in production without guarantees!
                    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;

            // Verify that RealNative64StrictFinite has the same alignment as f64
            assert_eq!(
                mem::align_of::<RealNative64StrictFinite>(),
                mem::align_of::<f64>()
            );

            // Verify size
            assert_eq!(
                mem::size_of::<RealNative64StrictFinite>(),
                mem::size_of::<f64>()
            );
        }
    }

    /// Tests for the conditional `Copy` implementation.
    ///
    /// These tests verify that `RealValidated` and `ComplexValidated` implement `Copy`
    /// when their underlying raw types implement `Copy` (e.g., `f64`, `Complex<f64>`).
    mod copy_trait_tests {
        use super::*;

        mod real_copy {
            use super::*;

            #[test]
            fn real_is_copy() {
                // Verify RealNative64StrictFinite 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; // Copy, not move
                let z = x; // x is still valid because it was copied
                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); // x is still valid after first call
                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; // x is copied each iteration
                }

                assert_eq!(*sum.as_ref(), 5.0);
                assert_eq!(*x.as_ref(), 1.0); // x unchanged
            }

            #[test]
            fn real_copy_with_arithmetic() {
                let a = RealNative64StrictFinite::try_new(2.0).unwrap();
                let b = RealNative64StrictFinite::try_new(3.0).unwrap();

                // All of these use copies of a and b
                let sum = a + b;
                let diff = a - b;
                let prod = a * b;
                let quot = a / b;

                // a and b still valid
                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() {
                // Verify ComplexNative64StrictFinite 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; // Copy, not move
                let v = z; // z is still valid because it was copied
                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); // z is still valid after first call
                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();

                // All of these use copies of a and b
                let sum = a + b;
                let diff = a - b;
                let prod = a * b;

                // a and b still valid
                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));
                // (1+2i)(3+4i) = 3 + 4i + 6i + 8i² = 3 + 10i - 8 = -5 + 10i
                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; // z is copied each iteration
                }

                assert_eq!(sum.into_inner(), Complex::new(3.0, 3.0));
                assert_eq!(z.into_inner(), Complex::new(1.0, 1.0)); // z unchanged
            }
        }

        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();

                // Complex * Real uses copies
                let result1 = z * r;
                let result2 = z * r;

                // Both still valid
                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));
            }
        }
    }
}
