Skip to main content

num_valid/backends/native64/
validated.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! # Validated Native 64-bit Kernel Types
4//!
5//! This module provides convenient, pre-configured type aliases for the native `f64`
6//! kernel. These types wrap [`f64`] and [`num::Complex<f64>`] in the [`RealValidated`](crate::core::types::RealValidated)
7//! and [`ComplexValidated`](crate::core::types::ComplexValidated) structs, bundling them with specific *validation policies*.
8//!
9//! These type aliases are the primary entry point for users who want to work with
10//! validated numbers that provide compile-time guarantees about their properties (e.g., finiteness).
11//!
12//! ## Policies
13//!
14//! Two main policies are provided:
15//!
16//! - **`Native64StrictFinite`:** Enforces that all values are finite (not `NaN` or `Infinity`)
17//!   in all build modes. Operations on types using this policy will panic on validation
18//!   failure in debug builds and return a `Result` in release builds. This is the safest and
19//!   most common choice.
20//!
21//! - **`Native64StrictFiniteInDebug`:** Also enforces finiteness, but validation checks that
22//!   would panic are **only performed in debug builds**. In release builds, these checks are
23//!   skipped for performance, and operations assume the inputs are valid. This is for
24//!   performance-critical code where the developer can guarantee the validity of inputs.
25//!
26//! ## Example
27//!
28//! ```rust
29//! use num_valid::{RealNative64StrictFinite, functions::Sqrt};
30//! use try_create::TryNew;
31//!
32//! // Creation succeeds because 4.0 is a valid, finite number.
33//! let x = RealNative64StrictFinite::try_new(4.0).unwrap();
34//!
35//! // Creation fails for non-finite numbers.
36//! assert!(RealNative64StrictFinite::try_new(f64::NAN).is_err());
37//!
38//! // Mathematical operations are available through traits.
39//! let sqrt_x = x.sqrt();
40//! assert_eq!(*sqrt_x.as_ref(), 2.0);
41//! ```
42//!
43//! ## Zero-Copy Conversions with Bytemuck
44//!
45//! The validated types in this module implement [`bytemuck::CheckedBitPattern`] and
46//! [`bytemuck::NoUninit`], enabling safe, zero-copy conversions between `f64` byte
47//! representations and validated types. This is particularly useful for:
48//!
49//! - Interoperability with binary data formats and serialization
50//! - Performance-critical code working with byte arrays
51//! - Loading validated numbers from external data sources
52//!
53//! The conversion automatically validates the bit pattern, rejecting invalid values
54//! (NaN, Infinity, subnormal numbers) while maintaining zero-cost performance for
55//! valid inputs:
56//!
57//! ```rust
58//! use num_valid::RealNative64StrictFinite;
59//! use bytemuck::checked::try_from_bytes;
60//!
61//! // Valid conversion
62//! let value = 42.0_f64;
63//! let bytes = value.to_ne_bytes();
64//! let validated: &RealNative64StrictFinite = try_from_bytes(&bytes).unwrap();
65//! assert_eq!(*validated.as_ref(), 42.0);
66//!
67//! // Invalid values are rejected
68//! let nan_bytes = f64::NAN.to_ne_bytes();
69//! assert!(try_from_bytes::<RealNative64StrictFinite>(&nan_bytes).is_err());
70//! ```
71//!
72//! For comprehensive examples of valid conversions, error handling, and slice operations,
73//! see the test module in the source code.
74
75use crate::kernels::{
76    ComplexValidated, NumKernelStrictFinite, NumKernelStrictFiniteInDebug, RealValidated,
77};
78
79//------------------------------------------------------------------------------------------------------------
80/// A kernel policy that enforces strict finiteness for `f64` and `Complex<f64>` values.
81///
82/// This is a type alias for [`NumKernelStrictFinite<f64, 53>`].
83///
84/// It ensures that all validated values are finite (not `NaN` or `Infinity`).
85/// In debug builds, operations that fail validation will panic. In release builds, they
86/// will return an error. This policy is used by [`RealNative64StrictFinite`] and
87/// [`ComplexNative64StrictFinite`].
88pub type Native64StrictFinite = NumKernelStrictFinite<f64, 53>;
89//------------------------------------------------------------------------------------------------------------
90
91//------------------------------------------------------------------------------------------------------------
92/// A kernel policy that enforces strict finiteness for `f64` values **only in debug builds**.
93///
94/// This is a type alias for [`NumKernelStrictFiniteInDebug<f64, 53>`].
95///
96/// This policy is designed for performance-critical applications. In debug builds, it
97/// behaves identically to [`Native64StrictFinite`], panicking on validation failures.
98/// In **release builds**, these validation checks are **disabled**, and operations proceed
99/// assuming the inputs are valid. Use this policy with caution when you can guarantee
100/// the integrity of your data in release environments.
101pub type Native64StrictFiniteInDebug = NumKernelStrictFiniteInDebug<f64, 53>;
102//------------------------------------------------------------------------------------------------------------
103
104//------------------------------------------------------------------------------------------------------------
105/// A validated real number that guarantees its inner `f64` value is finite.
106///
107/// This is a type alias for [`RealValidated<Native64StrictFinite>`].
108///
109/// It is the standard, safe-to-use validated real number type for the native `f64` kernel.
110/// It prevents the representation of `NaN` and `Infinity`.
111pub type RealNative64StrictFinite = RealValidated<Native64StrictFinite>;
112
113/// A validated complex number that guarantees its inner `f64` parts are finite.
114///
115/// This is a type alias for [`ComplexValidated<Native64StrictFinite>`].
116///
117/// It is the standard, safe-to-use validated complex number type for the native `f64` kernel.
118/// It ensures that both the real and imaginary components are finite values.
119pub type ComplexNative64StrictFinite = ComplexValidated<Native64StrictFinite>;
120//------------------------------------------------------------------------------------------------------------
121
122//------------------------------------------------------------------------------------------------------------
123/// A validated real number that checks for finiteness **only in debug builds**.
124///
125/// This is a type alias for [`RealValidated<Native64StrictFiniteInDebug>`].
126///
127/// Use this type in performance-sensitive contexts where the overhead of validation
128/// in release builds is unacceptable and inputs are known to be valid.
129pub type RealNative64StrictFiniteInDebug = RealValidated<Native64StrictFiniteInDebug>;
130
131/// A validated complex number that checks for finiteness **only in debug builds**.
132///
133/// This is a type alias for [`ComplexValidated<Native64StrictFiniteInDebug>`].
134///
135/// Use this type in performance-sensitive contexts where the overhead of validation
136/// in release builds is unacceptable and inputs are known to be valid.
137pub type ComplexNative64StrictFiniteInDebug = ComplexValidated<Native64StrictFiniteInDebug>;
138//------------------------------------------------------------------------------------------------------------
139
140// --- Hashing Implementation ---------------------------------------------------------
141// Note: The Hash trait is implemented generically in the validation module for all
142// RealValidated<K> types where K::RealPolicy implements GuaranteesFiniteRealValues.
143// This ensures that validated types with finite value guarantees can be used as
144// keys in HashMap and other hash-based collections.
145//
146// The implementation hashes the raw IEEE 754 bit representation of the f64 value,
147// with special handling for signed zeros to maintain the hash contract that
148// a == b implies hash(a) == hash(b).
149//-------------------------------------------------------------
150
151//------------------------------------------------------------------------------------------------
152#[cfg(test)]
153mod tests {
154    use super::*;
155    use crate::{
156        Clamp, ComplexScalarConstructors, ComplexScalarGetParts, ComplexScalarMutateParts,
157        ComplexScalarSetParts, Constants, ExpM1, FpChecks, Hypot, Ln1p, MulAddRef, RealScalar,
158        Rounding, Sign, TotalCmp,
159        core::errors::{ErrorsTryFromf64, ErrorsValidationRawComplex, ErrorsValidationRawReal},
160        functions::{
161            ACos, ACosH, ACosHErrors, ACosHInputErrors, ACosRealErrors, ACosRealInputErrors, ASin,
162            ASinH, ASinRealErrors, ASinRealInputErrors, ATan, ATan2, ATan2Errors,
163            ATanComplexErrors, ATanComplexInputErrors, ATanH, ATanHErrors, ATanHInputErrors, Abs,
164            Arg, Classify, Conjugate, Cos, CosH, Exp, ExpErrors, Ln, Log2, Log10,
165            LogarithmComplexErrors, LogarithmComplexInputErrors, Max, Min, NegAssign, Pow,
166            PowComplexBaseRealExponentErrors, PowIntExponentErrors, PowIntExponentInputErrors,
167            PowRealBaseRealExponentErrors, Reciprocal, ReciprocalErrors, Sin, SinH, Sqrt,
168            SqrtRealErrors, Tan, TanH,
169        },
170    };
171    use approx::assert_ulps_eq;
172    use num::{Complex, One, Zero};
173    use rand::RngExt;
174    use std::{
175        cmp::Ordering,
176        f64::consts::*,
177        num::FpCategory,
178        ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
179    };
180    use try_create::{IntoInner, TryNew, TryNewValidated};
181
182    type RealValidated = RealNative64StrictFinite;
183    type ComplexValidated = ComplexNative64StrictFinite;
184
185    mod fp_checks {
186        use super::*;
187
188        #[test]
189        fn is_finite() {
190            let real = RealValidated::try_new(1.).unwrap();
191            assert!(real.is_finite());
192
193            let real = RealValidated::try_new(f64::INFINITY);
194            assert!(real.is_err());
195
196            let complex = ComplexValidated::try_new(Complex::new(1., 1.)).unwrap();
197            assert!(complex.is_finite());
198
199            let complex = ComplexValidated::try_new(Complex::new(f64::INFINITY, 1.));
200            assert!(complex.is_err());
201        }
202
203        #[test]
204        fn is_infinite() {
205            let real = RealValidated::try_new(1.).unwrap();
206            assert!(!real.is_infinite());
207
208            let real = RealValidated::try_new(f64::INFINITY);
209            assert!(real.is_err());
210
211            let complex = ComplexValidated::try_new(Complex::new(1., 1.)).unwrap();
212            assert!(!complex.is_infinite());
213
214            let complex = ComplexValidated::try_new(Complex::new(f64::INFINITY, 1.));
215            assert!(complex.is_err());
216        }
217
218        #[test]
219        fn is_nan() {
220            let real = RealValidated::try_new(1.).unwrap();
221            assert!(!real.is_nan());
222
223            let real = RealValidated::try_new(f64::NAN);
224            assert!(matches!(real, Err(ErrorsValidationRawReal::IsNaN { .. })));
225
226            let complex = ComplexValidated::try_new(Complex::new(1., 1.)).unwrap();
227            assert!(!complex.is_nan());
228
229            let complex = ComplexValidated::try_new(Complex::new(f64::NAN, 1.));
230            assert!(matches!(
231                complex,
232                Err(ErrorsValidationRawComplex::InvalidRealPart {
233                    source: box ErrorsValidationRawReal::IsNaN { .. },
234                })
235            ));
236        }
237
238        #[test]
239        fn is_normal() {
240            let real = RealValidated::try_new(1.).unwrap();
241            assert!(real.is_normal());
242
243            let real = RealValidated::try_new(0.).unwrap();
244            assert!(!real.is_normal());
245
246            let complex = ComplexValidated::try_new(Complex::new(1., 1.)).unwrap();
247            assert!(complex.is_normal());
248
249            let complex = ComplexValidated::try_new(Complex::new(0., 0.)).unwrap();
250            assert!(!complex.is_normal());
251        }
252    }
253
254    mod new_unchecked {
255        use super::*;
256
257        mod real {
258            use super::*;
259
260            #[test]
261            fn new_unchecked_valid_value() {
262                // SAFETY: 3.0 is a valid finite f64
263                let x = unsafe { RealValidated::new_unchecked(3.) };
264                assert_eq!(*x.as_ref(), 3.);
265            }
266
267            #[test]
268            fn new_unchecked_zero() {
269                // SAFETY: 0.0 is valid
270                let x = unsafe { RealValidated::new_unchecked(0.0) };
271                assert!(x.is_zero());
272            }
273
274            #[test]
275            fn new_unchecked_negative() {
276                // SAFETY: -42.5 is a valid finite f64
277                let x = unsafe { RealValidated::new_unchecked(-42.5) };
278                assert_eq!(*x.as_ref(), -42.5);
279            }
280
281            #[test]
282            fn new_unchecked_large_value() {
283                // SAFETY: f64::MAX is finite
284                let x = unsafe { RealValidated::new_unchecked(f64::MAX) };
285                assert_eq!(*x.as_ref(), f64::MAX);
286            }
287
288            #[test]
289            fn new_unchecked_small_value() {
290                // SAFETY: f64::MIN is finite
291                let x = unsafe { RealValidated::new_unchecked(f64::MIN) };
292                assert_eq!(*x.as_ref(), f64::MIN);
293            }
294
295            #[test]
296            fn new_unchecked_epsilon() {
297                // SAFETY: f64::EPSILON is a valid finite f64
298                let x = unsafe { RealValidated::new_unchecked(f64::EPSILON) };
299                assert_eq!(*x.as_ref(), f64::EPSILON);
300            }
301
302            #[test]
303            #[cfg(debug_assertions)]
304            #[should_panic(expected = "new_unchecked() validation failed in debug mode")]
305            fn new_unchecked_nan_panics_in_debug() {
306                // In debug mode, new_unchecked validates and panics on NaN
307                let _ = unsafe { RealValidated::new_unchecked(f64::NAN) };
308            }
309
310            #[test]
311            #[cfg(debug_assertions)]
312            #[should_panic(expected = "new_unchecked() validation failed in debug mode")]
313            fn new_unchecked_infinity_panics_in_debug() {
314                // In debug mode, new_unchecked validates and panics on infinity
315                let _ = unsafe { RealValidated::new_unchecked(f64::INFINITY) };
316            }
317
318            #[test]
319            #[cfg(debug_assertions)]
320            #[should_panic(expected = "new_unchecked() validation failed in debug mode")]
321            fn new_unchecked_neg_infinity_panics_in_debug() {
322                // In debug mode, new_unchecked validates and panics on negative infinity
323                let _ = unsafe { RealValidated::new_unchecked(f64::NEG_INFINITY) };
324            }
325        }
326
327        mod complex {
328            use super::*;
329
330            #[test]
331            fn new_unchecked_valid_value() {
332                // SAFETY: Both components are valid finite f64 values
333                let z = unsafe { ComplexValidated::new_unchecked(Complex::new(1.0, 2.0)) };
334                assert_eq!(z.real_part().into_inner(), 1.0);
335                assert_eq!(z.imag_part().into_inner(), 2.0);
336            }
337
338            #[test]
339            fn new_unchecked_zero() {
340                // SAFETY: Zero is valid
341                let z = unsafe { ComplexValidated::new_unchecked(Complex::new(0.0, 0.0)) };
342                assert!(z.is_zero());
343            }
344
345            #[test]
346            fn new_unchecked_real_only() {
347                // SAFETY: Valid real part, zero imaginary
348                let z = unsafe { ComplexValidated::new_unchecked(Complex::new(5.0, 0.0)) };
349                assert_eq!(z.real_part().into_inner(), 5.0);
350                assert_eq!(z.imag_part().into_inner(), 0.0);
351            }
352
353            #[test]
354            fn new_unchecked_imaginary_only() {
355                // SAFETY: Zero real part, valid imaginary
356                let z = unsafe { ComplexValidated::new_unchecked(Complex::new(0.0, -3.0)) };
357                assert_eq!(z.real_part().into_inner(), 0.0);
358                assert_eq!(z.imag_part().into_inner(), -3.0);
359            }
360
361            #[test]
362            fn new_unchecked_negative_components() {
363                // SAFETY: Both negative finite values are valid
364                let z = unsafe { ComplexValidated::new_unchecked(Complex::new(-1.5, -2.5)) };
365                assert_eq!(z.real_part().into_inner(), -1.5);
366                assert_eq!(z.imag_part().into_inner(), -2.5);
367            }
368
369            #[test]
370            fn new_unchecked_preserves_value_in_arithmetic() {
371                // SAFETY: All values are valid finite f64
372                let a = unsafe { ComplexValidated::new_unchecked(Complex::new(1.0, 2.0)) };
373                let b = unsafe { ComplexValidated::new_unchecked(Complex::new(3.0, 4.0)) };
374                let sum = a + b;
375                assert_eq!(sum.real_part().into_inner(), 4.0);
376                assert_eq!(sum.imag_part().into_inner(), 6.0);
377            }
378
379            #[test]
380            #[cfg(debug_assertions)]
381            #[should_panic(expected = "new_unchecked() validation failed in debug mode")]
382            fn new_unchecked_nan_real_part_panics_in_debug() {
383                // In debug mode, new_unchecked validates and panics on NaN in real part
384                let _ = unsafe { ComplexValidated::new_unchecked(Complex::new(f64::NAN, 1.0)) };
385            }
386
387            #[test]
388            #[cfg(debug_assertions)]
389            #[should_panic(expected = "new_unchecked() validation failed in debug mode")]
390            fn new_unchecked_nan_imag_part_panics_in_debug() {
391                // In debug mode, new_unchecked validates and panics on NaN in imaginary part
392                let _ = unsafe { ComplexValidated::new_unchecked(Complex::new(1.0, f64::NAN)) };
393            }
394
395            #[test]
396            #[cfg(debug_assertions)]
397            #[should_panic(expected = "new_unchecked() validation failed in debug mode")]
398            fn new_unchecked_infinity_real_part_panics_in_debug() {
399                // In debug mode, new_unchecked validates and panics on infinity in real part
400                let _ =
401                    unsafe { ComplexValidated::new_unchecked(Complex::new(f64::INFINITY, 1.0)) };
402            }
403
404            #[test]
405            #[cfg(debug_assertions)]
406            #[should_panic(expected = "new_unchecked() validation failed in debug mode")]
407            fn new_unchecked_infinity_imag_part_panics_in_debug() {
408                // In debug mode, new_unchecked validates and panics on infinity in imaginary part
409                let _ =
410                    unsafe { ComplexValidated::new_unchecked(Complex::new(1.0, f64::INFINITY)) };
411            }
412
413            #[test]
414            #[cfg(debug_assertions)]
415            #[should_panic(expected = "new_unchecked() validation failed in debug mode")]
416            fn new_unchecked_neg_infinity_panics_in_debug() {
417                // In debug mode, new_unchecked validates and panics on negative infinity
418                let _ = unsafe {
419                    ComplexValidated::new_unchecked(Complex::new(
420                        f64::NEG_INFINITY,
421                        f64::NEG_INFINITY,
422                    ))
423                };
424            }
425        }
426    }
427
428    mod abs {
429        use super::*;
430
431        mod real {
432            use super::*;
433
434            #[test]
435            fn abs_valid() {
436                let value = RealValidated::try_new(-4.).unwrap();
437
438                let expected_result = RealValidated::try_new(4.).unwrap();
439                assert_eq!(value.try_abs().unwrap(), expected_result);
440                assert_eq!(value.abs(), expected_result);
441            }
442
443            #[test]
444            fn abs_zero() {
445                let value = RealValidated::try_new(0.).unwrap();
446
447                let expected_result = RealValidated::try_new(0.).unwrap();
448                assert_eq!(value.try_abs().unwrap(), expected_result);
449                assert_eq!(value.abs(), expected_result);
450            }
451
452            /*
453            #[cfg(feature = "rug")]
454            #[test]
455            fn abs_nan() {
456                let value =
457                    RealValidated::try_new(rug::Float::with_val(53, rug::float::Special::Nan))
458                        .unwrap();
459                let result = value.try_abs();
460                assert!(matches!(result, Err(AbsRealErrors::Input { .. })));
461            }
462
463            #[cfg(feature = "rug")]
464            #[test]
465            fn abs_infinite() {
466                let value = RealValidated::try_new(rug::Float::with_val(
467                    53,
468                    rug::float::Special::Infinity,
469                ))
470                .unwrap();
471                let result = value.try_abs();
472                assert!(matches!(result, Err(AbsRealErrors::Input { .. })));
473            }
474            */
475        }
476
477        mod complex {
478            use super::*;
479
480            #[test]
481            fn abs_valid() {
482                let value = ComplexValidated::try_new(Complex::new(3., 4.)).unwrap();
483
484                let expected_result = RealValidated::try_new(5.).unwrap();
485                assert_eq!(value.try_abs().unwrap(), expected_result);
486                assert_eq!(value.abs(), expected_result);
487            }
488
489            #[test]
490            fn abs_zero() {
491                let value = ComplexValidated::try_new(Complex::new(0., 0.)).unwrap();
492
493                let expected_result = RealValidated::try_new(0.).unwrap();
494                assert_eq!(value.try_abs().unwrap(), expected_result);
495                assert_eq!(value.abs(), expected_result);
496            }
497            /*
498            #[test]
499            fn abs_nan() {
500                let value = Complex64Validated::try_new(Complex::new(
501                    53,
502                    (
503                        rug::Float::with_val(53, rug::float::Special::Nan),
504                        0.,
505                    ),
506                ))
507                .unwrap();
508                assert!(matches!(
509                    value.try_abs(),
510                    Err(AbsComplexErrors::Input { .. })
511                ));
512            }
513
514            #[test]
515            fn abs_infinite() {
516                let value = Complex64Validated::try_new(Complex::new(
517                    53,
518                    (
519                        rug::Float::with_val(53, rug::float::Special::Infinity),
520                        0.,
521                    ),
522                ))
523                .unwrap();
524                assert!(matches!(
525                    value.try_abs(),
526                    Err(AbsComplexErrors::Input { .. })
527                ));
528            }
529            */
530        }
531    }
532
533    mod builders {
534        use super::*;
535
536        mod real {
537            use super::*;
538
539            #[test]
540            fn into_inner() {
541                let value = RealValidated::try_new(1.23).unwrap();
542                assert_eq!(value.into_inner(), 1.23);
543            }
544
545            #[test]
546            fn new() {
547                let value = RealValidated::try_new(1.23).unwrap();
548                assert_eq!(value, 1.23);
549            }
550
551            #[test]
552            fn try_new_nan() {
553                let err = RealValidated::try_new(f64::NAN).unwrap_err();
554                assert!(matches!(err, ErrorsValidationRawReal::IsNaN { .. }));
555            }
556
557            #[test]
558            fn try_new_pos_infinity() {
559                let err = RealValidated::try_new(f64::INFINITY).unwrap_err();
560                assert!(matches!(err, ErrorsValidationRawReal::IsPosInfinity { .. }));
561            }
562
563            #[test]
564            fn try_new_neg_infinity() {
565                let err = RealValidated::try_new(f64::NEG_INFINITY).unwrap_err();
566                assert!(matches!(err, ErrorsValidationRawReal::IsNegInfinity { .. }));
567            }
568        }
569
570        mod complex {
571            use super::*;
572
573            #[test]
574            fn into_inner() {
575                let v = Complex::new(1., 2.);
576                let value = ComplexValidated::try_new(v).unwrap();
577                assert_eq!(value.into_inner(), v);
578            }
579
580            #[test]
581            fn new() {
582                let v = Complex::new(1., 2.);
583                let value = ComplexValidated::try_new(v).unwrap();
584                assert_eq!(value.into_inner(), v);
585            }
586
587            #[test]
588            fn real_part() {
589                let c1 = ComplexValidated::try_new_validated(Complex::new(1.23, 4.56)).unwrap();
590                assert_eq!(c1.real_part(), 1.23);
591
592                let c2 = ComplexValidated::try_new_validated(Complex::new(-7.89, 0.12)).unwrap();
593                assert_eq!(c2.real_part(), -7.89);
594
595                let c3 = ComplexValidated::try_new_validated(Complex::new(0., 10.)).unwrap();
596                assert_eq!(c3.real_part(), 0.);
597
598                let c_nan_re =
599                    ComplexValidated::try_new_validated(Complex::new(f64::NAN, 5.)).unwrap_err();
600                assert!(matches!(
601                    c_nan_re,
602                    ErrorsValidationRawComplex::InvalidRealPart {
603                        source: box ErrorsValidationRawReal::IsNaN { .. }
604                    }
605                ));
606
607                let c_inf_re = ComplexValidated::try_new_validated(Complex::new(f64::INFINITY, 5.))
608                    .unwrap_err();
609                assert!(matches!(
610                    c_inf_re,
611                    ErrorsValidationRawComplex::InvalidRealPart {
612                        source: box ErrorsValidationRawReal::IsPosInfinity { .. }
613                    }
614                ));
615
616                let c_neg_inf_re =
617                    ComplexValidated::try_new_validated(Complex::new(f64::NEG_INFINITY, 5.))
618                        .unwrap_err();
619                assert!(matches!(
620                    c_neg_inf_re,
621                    ErrorsValidationRawComplex::InvalidRealPart {
622                        source: box ErrorsValidationRawReal::IsNegInfinity { .. }
623                    }
624                ));
625            }
626
627            #[test]
628            fn imag_part() {
629                let c1 = ComplexValidated::try_new_validated(Complex::new(1.23, 4.56)).unwrap();
630                assert_eq!(c1.imag_part(), 4.56);
631
632                let c2 = ComplexValidated::try_new_validated(Complex::new(-7.89, 0.12)).unwrap();
633                assert_eq!(c2.imag_part(), 0.12);
634
635                let c3 = ComplexValidated::try_new_validated(Complex::new(10., 0.)).unwrap();
636                assert_eq!(c3.imag_part(), 0.);
637
638                let c_nan_im =
639                    ComplexValidated::try_new_validated(Complex::new(5., f64::NAN)).unwrap_err();
640                assert!(matches!(
641                    c_nan_im,
642                    ErrorsValidationRawComplex::InvalidImaginaryPart {
643                        source: box ErrorsValidationRawReal::IsNaN { .. }
644                    }
645                ));
646
647                let c_inf_im = ComplexValidated::try_new_validated(Complex::new(5., f64::INFINITY))
648                    .unwrap_err();
649                assert!(matches!(
650                    c_inf_im,
651                    ErrorsValidationRawComplex::InvalidImaginaryPart {
652                        source: box ErrorsValidationRawReal::IsPosInfinity { .. }
653                    }
654                ));
655
656                let c_neg_inf_im =
657                    ComplexValidated::try_new_validated(Complex::new(5., f64::NEG_INFINITY))
658                        .unwrap_err();
659                assert!(matches!(
660                    c_neg_inf_im,
661                    ErrorsValidationRawComplex::InvalidImaginaryPart {
662                        source: box ErrorsValidationRawReal::IsNegInfinity { .. }
663                    }
664                ));
665            }
666
667            #[test]
668            fn try_new_complex() {
669                let r1 = RealValidated::try_new(1.23).unwrap();
670                let i1 = RealValidated::try_new(4.56).unwrap();
671                let c1 = ComplexValidated::try_new_complex(*r1.as_ref(), *i1.as_ref()).unwrap();
672                assert_eq!(c1.real_part(), r1);
673                assert_eq!(c1.imag_part(), i1);
674
675                let r2 = RealValidated::try_new(-7.89).unwrap();
676                let i2 = RealValidated::try_new(-0.12).unwrap();
677                let c2 = ComplexValidated::try_new_complex(*r2.as_ref(), *i2.as_ref()).unwrap();
678                assert_eq!(c2.real_part(), r2);
679                assert_eq!(c2.imag_part(), i2);
680
681                let r3 = RealValidated::try_new(0.).unwrap();
682                let i3 = RealValidated::try_new(0.).unwrap();
683                let c3 = ComplexValidated::try_new_complex(*r3.as_ref(), *i3.as_ref()).unwrap();
684                assert_eq!(c3.real_part(), r3);
685                assert_eq!(c3.real_part(), i3);
686                assert!(c3.is_zero());
687
688                let c_nan_re = ComplexValidated::try_new_complex(f64::NAN, 5.).unwrap_err();
689                assert!(matches!(
690                    c_nan_re,
691                    ErrorsValidationRawComplex::InvalidRealPart { .. }
692                ));
693
694                let c_inf_im = ComplexValidated::try_new_complex(10., f64::INFINITY).unwrap_err();
695                assert!(matches!(
696                    c_inf_im,
697                    ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
698                ));
699
700                let c_nan_re_inf_im =
701                    ComplexValidated::try_new_complex(f64::NAN, f64::INFINITY).unwrap_err();
702                assert!(matches!(
703                    c_nan_re_inf_im,
704                    ErrorsValidationRawComplex::InvalidBothParts { .. }
705                ));
706            }
707
708            #[test]
709            fn try_new_pure_real() {
710                let r1 = RealValidated::try_new(1.23).unwrap();
711                let c1 = ComplexValidated::try_new_pure_real(*r1.as_ref()).unwrap();
712                assert_eq!(c1.real_part(), r1);
713                assert!(c1.imag_part().is_zero());
714
715                let c_nan = ComplexValidated::try_new_pure_real(f64::NAN).unwrap_err();
716                assert!(matches!(
717                    c_nan,
718                    ErrorsValidationRawComplex::InvalidRealPart {
719                        source: box ErrorsValidationRawReal::IsNaN { .. }
720                    }
721                ));
722            }
723
724            #[test]
725            fn try_new_pure_imaginary() {
726                let i1 = RealValidated::try_new(1.23).unwrap();
727                let c1 = ComplexValidated::try_new_pure_imaginary(*i1.as_ref()).unwrap();
728                assert!(c1.real_part().is_zero());
729                assert_eq!(c1.imag_part(), i1);
730
731                let c_nan = ComplexValidated::try_new_pure_imaginary(f64::NAN).unwrap_err();
732                assert!(matches!(
733                    c_nan,
734                    ErrorsValidationRawComplex::InvalidImaginaryPart {
735                        source: box ErrorsValidationRawReal::IsNaN { .. }
736                    }
737                ));
738            }
739
740            #[test]
741            fn add_to_real_part() {
742                let mut c = ComplexValidated::try_new_validated(Complex::new(1., 2.)).unwrap();
743                c.add_to_real_part(&RealValidated::try_new(3.).unwrap());
744                assert_eq!(c.real_part(), 4.);
745                assert_eq!(c.imag_part(), 2.);
746
747                c.add_to_real_part(&RealValidated::try_new(-5.).unwrap());
748                assert_eq!(c.real_part(), -1.);
749                assert_eq!(c.imag_part(), 2.);
750            }
751
752            #[test]
753            fn add_to_imaginary_part() {
754                let mut c = ComplexValidated::try_new_validated(Complex::new(1., 2.)).unwrap();
755                c.add_to_imaginary_part(&RealValidated::try_new(3.).unwrap());
756                assert_eq!(c.real_part(), 1.);
757                assert_eq!(c.imag_part(), 5.);
758
759                c.add_to_imaginary_part(&RealValidated::try_new(-4.).unwrap());
760                assert_eq!(c.real_part(), 1.);
761                assert_eq!(c.imag_part(), 1.);
762            }
763
764            #[test]
765            fn multiply_real_part() {
766                let mut c = ComplexValidated::try_new_validated(Complex::new(1., 2.)).unwrap();
767                c.multiply_real_part(&RealValidated::try_new(3.).unwrap());
768                assert_eq!(c.real_part(), 3.);
769                assert_eq!(c.imag_part(), 2.);
770
771                c.multiply_real_part(&RealValidated::try_new(-2.).unwrap());
772                assert_eq!(c.real_part(), -6.);
773                assert_eq!(c.imag_part(), 2.);
774            }
775
776            #[test]
777            fn multiply_imaginary_part() {
778                let mut c = ComplexValidated::try_new_validated(Complex::new(1., 2.)).unwrap();
779                c.multiply_imaginary_part(&RealValidated::try_new(3.).unwrap());
780                assert_eq!(c.real_part(), 1.);
781                assert_eq!(c.imag_part(), 6.);
782
783                c.multiply_imaginary_part(&RealValidated::try_new(-0.5).unwrap());
784                assert_eq!(c.real_part(), 1.);
785                assert_eq!(c.imag_part(), -3.);
786            }
787
788            #[test]
789            fn set_real_part() {
790                let mut c = ComplexValidated::try_new_validated(Complex::new(1., 2.)).unwrap();
791                c.set_real_part(RealValidated::try_new(3.).unwrap());
792                assert_eq!(c.real_part(), 3.);
793                assert_eq!(c.imag_part(), 2.);
794
795                c.set_real_part(RealValidated::try_new(-4.).unwrap());
796                assert_eq!(c.real_part(), -4.);
797                assert_eq!(c.imag_part(), 2.);
798            }
799
800            #[test]
801            fn set_imaginary_part() {
802                let mut c = ComplexValidated::try_new_validated(Complex::new(1., 2.)).unwrap();
803                c.set_imaginary_part(RealValidated::try_new(3.).unwrap());
804                assert_eq!(c.real_part(), 1.);
805                assert_eq!(c.imag_part(), 3.);
806
807                c.set_imaginary_part(RealValidated::try_new(-4.).unwrap());
808                assert_eq!(c.real_part(), 1.);
809                assert_eq!(c.imag_part(), -4.);
810            }
811        }
812    }
813
814    mod mul {
815        use super::*;
816
817        mod real {
818            use super::*;
819
820            #[test]
821            fn multiply_ref() {
822                let r1 = RealValidated::try_new_validated(3.).unwrap();
823                let r2 = RealValidated::try_new_validated(4.).unwrap();
824                let result = r1 * r2;
825                assert_eq!(result, RealValidated::try_new_validated(12.).unwrap());
826            }
827        }
828
829        mod complex {
830            use super::*;
831
832            #[test]
833            fn multiply_ref() {
834                let c1 = ComplexValidated::try_new_validated(Complex::new(1., 2.)).unwrap();
835                let c2 = ComplexValidated::try_new_validated(Complex::new(3., 4.)).unwrap();
836                let result = c1 * c2;
837                assert_eq!(
838                    result,
839                    ComplexValidated::try_new_validated(Complex::new(-5., 10.)).unwrap()
840                ); // (1*3 - 2*4) + (1*4 + 2*3)i
841            }
842
843            #[test]
844            fn complex_times_real() {
845                let r = RealValidated::try_new_validated(2.).unwrap();
846                let c = ComplexValidated::try_new_validated(Complex::new(3., 4.)).unwrap();
847
848                let result_expected =
849                    ComplexValidated::try_new_validated(Complex::new(6., 8.)).unwrap(); // 2 * (3 + 4i) = 6 + 8i
850
851                let result = c * r;
852                assert_eq!(&result, &result_expected);
853
854                let result = c * r;
855                assert_eq!(&result, &result_expected);
856
857                let mut result = c;
858                result *= &r;
859                assert_eq!(&result, &result_expected);
860
861                let mut result = c;
862                result *= r;
863                assert_eq!(&result, &result_expected);
864            }
865
866            #[test]
867            fn real_times_complex() {
868                let r = RealValidated::try_new_validated(2.).unwrap();
869                let c = ComplexValidated::try_new_validated(Complex::new(3., 4.)).unwrap();
870
871                let result_expected =
872                    ComplexValidated::try_new_validated(Complex::new(6., 8.)).unwrap(); // 2 * (3 + 4i) = 6 + 8i
873
874                let result = r * c;
875                assert_eq!(&result, &result_expected);
876            }
877        }
878    }
879
880    mod arithmetic {
881        use super::*;
882
883        mod real {
884            use super::*;
885
886            #[test]
887            fn add() {
888                let r1 = RealValidated::try_new_validated(3.).unwrap();
889                let r2 = RealValidated::try_new_validated(4.).unwrap();
890
891                let expected_result = RealValidated::try_new_validated(7.).unwrap();
892
893                let result = r1.add(&r2);
894                assert_eq!(result, expected_result);
895
896                let result = r1.add(r2);
897                assert_eq!(result, expected_result);
898
899                let result = (&r1).add(r2);
900                assert_eq!(result, expected_result);
901
902                let result = (&r1).add(&r2);
903                assert_eq!(result, expected_result);
904
905                let mut result = r1;
906                result.add_assign(&r2);
907                assert_eq!(result, expected_result);
908
909                let mut result = r1;
910                result.add_assign(r2);
911                assert_eq!(result, expected_result);
912            }
913
914            #[test]
915            fn sub() {
916                let r1 = RealValidated::try_new_validated(3.).unwrap();
917                let r2 = RealValidated::try_new_validated(4.).unwrap();
918
919                let expected_result = RealValidated::try_new_validated(-1.).unwrap();
920
921                let result = r1.sub(&r2);
922                assert_eq!(result, expected_result);
923
924                let result = r1.sub(r2);
925                assert_eq!(result, expected_result);
926
927                let result = (&r1).sub(r2);
928                assert_eq!(result, expected_result);
929
930                let result = (&r1).sub(&r2);
931                assert_eq!(result, expected_result);
932
933                let mut result = r1;
934                result.sub_assign(&r2);
935                assert_eq!(result, expected_result);
936
937                let mut result = r1;
938                result.sub_assign(r2);
939                assert_eq!(result, expected_result);
940            }
941
942            #[test]
943            fn mul() {
944                let r1 = RealValidated::try_new_validated(3.).unwrap();
945                let r2 = RealValidated::try_new_validated(4.).unwrap();
946
947                let expected_result = RealValidated::try_new_validated(12.).unwrap();
948
949                let result = r1.mul(&r2);
950                assert_eq!(result, expected_result);
951
952                let result = r1.mul(r2);
953                assert_eq!(result, expected_result);
954
955                let result = (&r1).mul(r2);
956                assert_eq!(result, expected_result);
957
958                let result = (&r1).mul(&r2);
959                assert_eq!(result, expected_result);
960
961                let mut result = r1;
962                result.mul_assign(&r2);
963                assert_eq!(result, expected_result);
964
965                let mut result = r1;
966                result.mul_assign(r2);
967                assert_eq!(result, expected_result);
968            }
969
970            #[test]
971            fn div() {
972                let r1 = RealValidated::try_new_validated(3.).unwrap();
973                let r2 = RealValidated::try_new_validated(4.).unwrap();
974
975                let expected_result = RealValidated::try_new_validated(0.75).unwrap();
976
977                let result = r1.div(&r2);
978                assert_eq!(result, expected_result);
979
980                let result = r1.div(r2);
981                assert_eq!(result, expected_result);
982
983                let result = (&r1).div(r2);
984                assert_eq!(result, expected_result);
985
986                let result = (&r1).div(&r2);
987                assert_eq!(result, expected_result);
988
989                let mut result = r1;
990                result.div_assign(&r2);
991                assert_eq!(result, expected_result);
992
993                let mut result = r1;
994                result.div_assign(r2);
995                assert_eq!(result, expected_result);
996            }
997
998            #[test]
999            fn neg() {
1000                let num = RealValidated::try_new_validated(1.).unwrap();
1001                let expected = RealValidated::try_new_validated(-1.).unwrap();
1002                assert_eq!(num.neg(), expected);
1003            }
1004
1005            #[test]
1006            fn neg_assign() {
1007                let mut num = 1.;
1008                num.neg_assign();
1009                let expected = -1.;
1010                assert_eq!(&num, &expected);
1011
1012                let mut num = RealValidated::one();
1013                num.neg_assign();
1014                let expected = RealValidated::try_new_validated(-1.).unwrap();
1015                assert_eq!(&num, &expected);
1016            }
1017
1018            #[test]
1019            #[should_panic(expected = "Division failed validation")]
1020            fn div_by_zero() {
1021                let one = RealValidated::one();
1022                let zero = RealValidated::zero();
1023                let _ = one / zero;
1024            }
1025
1026            #[test]
1027            #[should_panic(expected = "Division failed validation")]
1028            fn div_assign_by_zero() {
1029                let mut num = RealValidated::one();
1030                let zero_ref = &RealValidated::zero();
1031                num /= zero_ref;
1032            }
1033
1034            #[test]
1035            fn mul_add() {
1036                let a = RealValidated::try_new(2.0).unwrap();
1037                let b = RealValidated::try_new(3.0).unwrap();
1038                let c = RealValidated::try_new(4.0).unwrap();
1039                // 2*3 + 4 = 10
1040                assert_eq!(a.mul_add_ref(&b, &c), RealValidated::try_new(10.0).unwrap());
1041            }
1042        }
1043
1044        mod complex {
1045            use super::*;
1046
1047            #[test]
1048            fn add() {
1049                let r1 = ComplexValidated::try_new_validated(Complex::new(2., 3.)).unwrap();
1050                let r2 = ComplexValidated::try_new_validated(Complex::new(4., -4.)).unwrap();
1051
1052                let expected_result =
1053                    ComplexValidated::try_new_validated(Complex::new(6., -1.)).unwrap();
1054
1055                let result = r1.add(&r2);
1056                assert_eq!(result, expected_result);
1057
1058                let result = r1.add(r2);
1059                assert_eq!(result, expected_result);
1060
1061                let result = (&r1).add(r2);
1062                assert_eq!(result, expected_result);
1063
1064                let result = (&r1).add(&r2);
1065                assert_eq!(result, expected_result);
1066
1067                let mut result = r1;
1068                result.add_assign(&r2);
1069                assert_eq!(result, expected_result);
1070
1071                let mut result = r1;
1072                result.add_assign(r2);
1073                assert_eq!(result, expected_result);
1074            }
1075
1076            #[test]
1077            fn sub() {
1078                let r1 = ComplexValidated::try_new_validated(Complex::new(2., 3.)).unwrap();
1079                let r2 = ComplexValidated::try_new_validated(Complex::new(4., -4.)).unwrap();
1080
1081                let expected_result =
1082                    ComplexValidated::try_new_validated(Complex::new(-2., 7.)).unwrap();
1083
1084                let result = r1.sub(&r2);
1085                assert_eq!(result, expected_result);
1086
1087                let result = r1.sub(r2);
1088                assert_eq!(result, expected_result);
1089
1090                let result = (&r1).sub(r2);
1091                assert_eq!(result, expected_result);
1092
1093                let result = (&r1).sub(&r2);
1094                assert_eq!(result, expected_result);
1095
1096                let mut result = r1;
1097                result.sub_assign(&r2);
1098                assert_eq!(result, expected_result);
1099
1100                let mut result = r1;
1101                result.sub_assign(r2);
1102                assert_eq!(result, expected_result);
1103            }
1104
1105            #[test]
1106            fn mul() {
1107                let r1 = ComplexValidated::try_new_validated(Complex::new(2., 3.)).unwrap();
1108                let r2 = ComplexValidated::try_new_validated(Complex::new(4., -4.)).unwrap();
1109
1110                let expected_result =
1111                    ComplexValidated::try_new_validated(Complex::new(20., 4.)).unwrap();
1112
1113                let result = r1.mul(&r2);
1114                assert_eq!(result, expected_result);
1115
1116                let result = r1.mul(r2);
1117                assert_eq!(result, expected_result);
1118
1119                let result = (&r1).mul(r2);
1120                assert_eq!(result, expected_result);
1121
1122                let result = (&r1).mul(&r2);
1123                assert_eq!(result, expected_result);
1124
1125                let mut result = r1;
1126                result.mul_assign(&r2);
1127                assert_eq!(result, expected_result);
1128
1129                let mut result = r1;
1130                result.mul_assign(r2);
1131                assert_eq!(result, expected_result);
1132            }
1133
1134            #[test]
1135            fn div() {
1136                let r1 = ComplexValidated::try_new_validated(Complex::new(2., 3.)).unwrap();
1137                let r2 = ComplexValidated::try_new_validated(Complex::new(4., -4.)).unwrap();
1138
1139                let expected_result =
1140                    ComplexValidated::try_new_validated(Complex::new(-0.125, 0.625)).unwrap();
1141
1142                let result = r1.div(&r2);
1143                assert_eq!(result, expected_result);
1144
1145                let result = r1.div(r2);
1146                assert_eq!(result, expected_result);
1147
1148                let result = (&r1).div(r2);
1149                assert_eq!(result, expected_result);
1150
1151                let result = (&r1).div(&r2);
1152                assert_eq!(result, expected_result);
1153
1154                let mut result = r1;
1155                result.div_assign(&r2);
1156                assert_eq!(result, expected_result);
1157
1158                let mut result = r1;
1159                result.div_assign(r2);
1160                assert_eq!(result, expected_result);
1161            }
1162
1163            #[test]
1164            fn neg() {
1165                let v = Complex::new(1., 2.);
1166
1167                let num = ComplexValidated::try_new_validated(v).unwrap();
1168                let expected = Complex::new(-1., -2.);
1169                assert_eq!(num.neg().into_inner(), expected);
1170            }
1171
1172            #[test]
1173            fn neg_assign() {
1174                let v = Complex::new(1., 2.);
1175
1176                let mut num = ComplexValidated::try_new_validated(v).unwrap();
1177                let expected = Complex::new(-1., -2.);
1178                num.neg_assign();
1179                assert_eq!(num.as_ref(), &expected);
1180            }
1181
1182            #[test]
1183            #[should_panic(expected = "Division failed validation")]
1184            fn div_by_zero() {
1185                let one = ComplexValidated::one();
1186                let zero = ComplexValidated::zero();
1187                let _ = one / zero;
1188            }
1189
1190            #[test]
1191            #[should_panic(expected = "Division failed validation")]
1192            fn div_assign_by_zero() {
1193                let mut num = ComplexValidated::one();
1194                let zero_ref = &ComplexValidated::zero();
1195                num /= zero_ref;
1196            }
1197
1198            #[test]
1199            fn mul_add() {
1200                let ca = ComplexValidated::try_new(Complex::new(1.0, 2.0)).unwrap();
1201                let cb = ComplexValidated::try_new(Complex::new(3.0, 4.0)).unwrap();
1202                let cc = ComplexValidated::try_new(Complex::new(5.0, 6.0)).unwrap();
1203                // (1+2i)*(3+4i) + (5+6i) = (3+4i+6i-8) + (5+6i) = (-5+10i) + (5+6i) = 0+16i
1204                let expected = ComplexValidated::try_new(Complex::new(0.0, 16.0)).unwrap();
1205                assert_eq!(ca.mul_add_ref(&cb, &cc), expected);
1206            }
1207        }
1208    }
1209
1210    mod real_scalar_methods {
1211        use super::*;
1212
1213        #[test]
1214        fn test_constants() {
1215            assert_eq!(<RealValidated as Constants>::epsilon(), f64::EPSILON);
1216            assert_eq!(<RealValidated as Constants>::negative_one(), -1.0);
1217            assert_eq!(<RealValidated as Constants>::one_div_2(), 0.5);
1218            assert_eq!(<RealValidated as Constants>::two(), 2.0);
1219            assert_eq!(<RealValidated as Constants>::max_finite(), f64::MAX);
1220            assert_eq!(<RealValidated as Constants>::min_finite(), f64::MIN);
1221            assert_eq!(<RealValidated as Constants>::pi(), std::f64::consts::PI);
1222            assert_eq!(
1223                <RealValidated as Constants>::two_pi(),
1224                std::f64::consts::PI * 2.0
1225            );
1226            assert_eq!(
1227                <RealValidated as Constants>::pi_div_2(),
1228                std::f64::consts::FRAC_PI_2
1229            );
1230            assert_eq!(<RealValidated as Constants>::ln_2(), std::f64::consts::LN_2);
1231            assert_eq!(
1232                <RealValidated as Constants>::ln_10(),
1233                std::f64::consts::LN_10
1234            );
1235            assert_eq!(
1236                <RealValidated as Constants>::log10_2(),
1237                std::f64::consts::LOG10_2
1238            );
1239            assert_eq!(
1240                <RealValidated as Constants>::log2_10(),
1241                std::f64::consts::LOG2_10
1242            );
1243            assert_eq!(
1244                <RealValidated as Constants>::log2_e(),
1245                std::f64::consts::LOG2_E
1246            );
1247            assert_eq!(
1248                <RealValidated as Constants>::log10_e(),
1249                std::f64::consts::LOG10_E
1250            );
1251            assert_eq!(<RealValidated as Constants>::e(), std::f64::consts::E);
1252        }
1253
1254        #[test]
1255        fn round_ties_even() {
1256            let f = RealValidated::try_new(3.3).unwrap();
1257            let g = RealValidated::try_new(-3.3).unwrap();
1258            let h = RealValidated::try_new(3.5).unwrap();
1259            let i = RealValidated::try_new(4.5).unwrap();
1260            let j = RealValidated::try_new(-3.5).unwrap();
1261            let k = RealValidated::try_new(-4.5).unwrap();
1262
1263            assert_eq!(
1264                f.kernel_round_ties_even(),
1265                RealValidated::try_new(3.0).unwrap()
1266            );
1267            assert_eq!(
1268                g.kernel_round_ties_even(),
1269                RealValidated::try_new(-3.0).unwrap()
1270            );
1271            assert_eq!(
1272                h.kernel_round_ties_even(),
1273                RealValidated::try_new(4.0).unwrap()
1274            );
1275            assert_eq!(
1276                i.kernel_round_ties_even(),
1277                RealValidated::try_new(4.0).unwrap()
1278            );
1279            assert_eq!(
1280                j.kernel_round_ties_even(),
1281                RealValidated::try_new(-4.0).unwrap()
1282            );
1283            assert_eq!(
1284                k.kernel_round_ties_even(),
1285                RealValidated::try_new(-4.0).unwrap()
1286            );
1287        }
1288
1289        #[test]
1290        fn classify() {
1291            let normal = RealValidated::try_new(1.0).unwrap();
1292            assert_eq!(normal.classify(), FpCategory::Normal);
1293
1294            let zero = RealValidated::zero();
1295            assert_eq!(zero.classify(), FpCategory::Zero);
1296
1297            // Subnormals, Infinite and NaN are not constructible with StrictFinitePolicy
1298
1299            let subnormal_err = RealValidated::try_new(f64::MIN_POSITIVE / 2.).unwrap_err();
1300            assert!(matches!(
1301                subnormal_err,
1302                ErrorsValidationRawReal::IsSubnormal { .. }
1303            ));
1304
1305            let pos_inf_err = RealValidated::try_new(f64::INFINITY).unwrap_err();
1306            assert!(matches!(
1307                pos_inf_err,
1308                ErrorsValidationRawReal::IsPosInfinity { .. }
1309            ));
1310
1311            let neg_inf_err = RealValidated::try_new(f64::NEG_INFINITY).unwrap_err();
1312            assert!(matches!(
1313                neg_inf_err,
1314                ErrorsValidationRawReal::IsNegInfinity { .. }
1315            ));
1316
1317            let nan_err = RealValidated::try_new(f64::NAN).unwrap_err();
1318            assert!(matches!(nan_err, ErrorsValidationRawReal::IsNaN { .. }));
1319        }
1320
1321        #[test]
1322        fn try_from_f64_valid() {
1323            let val = RealValidated::try_from_f64(123.45).unwrap();
1324            assert_eq!(val.as_ref(), &123.45);
1325        }
1326
1327        #[test]
1328        fn try_from_f64_invalid() {
1329            let err = RealValidated::try_from_f64(f64::NAN).unwrap_err();
1330            assert!(matches!(
1331                err,
1332                ErrorsTryFromf64::Output {
1333                    source: ErrorsValidationRawReal::IsNaN { .. }
1334                }
1335            ));
1336        }
1337
1338        #[test]
1339        fn rounding_and_trunc() {
1340            let val1 = RealValidated::try_new(3.7).unwrap();
1341            let val2 = RealValidated::try_new(-3.7).unwrap();
1342
1343            assert_eq!(val1.kernel_ceil(), RealValidated::try_new(4.0).unwrap());
1344            assert_eq!(val2.kernel_ceil(), RealValidated::try_new(-3.0).unwrap());
1345
1346            assert_eq!(val1.kernel_floor(), RealValidated::try_new(3.0).unwrap());
1347            assert_eq!(val2.kernel_floor(), RealValidated::try_new(-4.0).unwrap());
1348
1349            assert_eq!(val1.kernel_round(), RealValidated::try_new(4.0).unwrap());
1350            assert_eq!(val2.kernel_round(), RealValidated::try_new(-4.0).unwrap());
1351
1352            assert_eq!(val1.kernel_trunc(), RealValidated::try_new(3.0).unwrap());
1353            assert_eq!(val2.kernel_trunc(), RealValidated::try_new(-3.0).unwrap());
1354
1355            // Using a tolerance for fract_ due to floating point representation
1356            let frac1 = val1.kernel_fract();
1357            assert!((frac1.as_ref() - 0.7).abs() < 1e-9);
1358
1359            let frac2 = val2.kernel_fract();
1360            assert!((frac2.as_ref() - (-0.7)).abs() < 1e-9);
1361        }
1362
1363        #[test]
1364        fn sign_and_constants() {
1365            let pos = RealValidated::try_new(5.0).unwrap();
1366            let neg = RealValidated::try_new(-5.0).unwrap();
1367            let zero = RealValidated::zero();
1368
1369            assert!(pos.kernel_is_sign_positive());
1370            assert!(!pos.kernel_is_sign_negative());
1371
1372            assert!(!neg.kernel_is_sign_positive());
1373            assert!(neg.kernel_is_sign_negative());
1374
1375            assert!(zero.kernel_is_sign_positive()); // +0.0 is positive
1376            assert!(!zero.kernel_is_sign_negative());
1377
1378            let neg_zero = RealValidated::try_new(-0.0).unwrap();
1379            assert!(!neg_zero.kernel_is_sign_positive());
1380            assert!(neg_zero.kernel_is_sign_negative());
1381
1382            assert_eq!(pos.kernel_copysign(&neg), neg);
1383            assert_eq!(neg.kernel_copysign(&pos), pos);
1384
1385            assert_eq!(
1386                RealValidated::one_div_2(),
1387                RealValidated::try_new(0.5).unwrap()
1388            );
1389            assert_eq!(RealValidated::two(), RealValidated::try_new(2.0).unwrap());
1390            assert_eq!(
1391                RealValidated::max_finite(),
1392                RealValidated::try_new(f64::MAX).unwrap()
1393            );
1394            assert_eq!(
1395                RealValidated::min_finite(),
1396                RealValidated::try_new(f64::MIN).unwrap()
1397            );
1398        }
1399
1400        #[test]
1401        fn epsilon() {
1402            let eps = RealValidated::epsilon();
1403            assert!(eps.is_finite() && eps > RealValidated::zero());
1404            let expected_eps_val = 2.0f64.pow(-52);
1405            let expected_eps = RealValidated::try_new(expected_eps_val).unwrap();
1406            assert_eq!(eps, expected_eps, "Epsilon value mismatch");
1407        }
1408
1409        #[test]
1410        fn clamp_ref() {
1411            let val = RealValidated::try_new(5.).unwrap();
1412            let min_val = RealValidated::try_new(0.).unwrap();
1413            let max_val = RealValidated::try_new(10.).unwrap();
1414
1415            assert_eq!(val.clamp_ref(&min_val, &max_val), val);
1416            assert_eq!(
1417                RealValidated::try_new(-5.)
1418                    .unwrap()
1419                    .clamp_ref(&min_val, &max_val),
1420                min_val
1421            );
1422            assert_eq!(
1423                RealValidated::try_new(15.)
1424                    .unwrap()
1425                    .clamp_ref(&min_val, &max_val),
1426                max_val
1427            );
1428        }
1429
1430        #[test]
1431        fn hypot() {
1432            let a = RealValidated::try_new(3.).unwrap();
1433            let b = RealValidated::try_new(4.).unwrap();
1434            let expected = RealValidated::try_new(5.).unwrap();
1435            assert_eq!(a.hypot(&b), expected);
1436        }
1437
1438        #[test]
1439        fn signum() {
1440            assert_eq!(
1441                RealValidated::try_new(5.).unwrap().kernel_signum(),
1442                RealValidated::one()
1443            );
1444            assert_eq!(
1445                RealValidated::try_new(-5.).unwrap().kernel_signum(),
1446                RealValidated::negative_one()
1447            );
1448            // rug::Float::signum of 0. is 1.
1449            assert_eq!(RealValidated::zero().kernel_signum(), RealValidated::one());
1450        }
1451
1452        #[test]
1453        fn total_cmp() {
1454            let r1 = RealValidated::try_new(1.).unwrap();
1455            let r2 = RealValidated::try_new(2.).unwrap();
1456            assert_eq!(r1.total_cmp(&r1), Ordering::Equal);
1457            assert_eq!(r1.total_cmp(&r2), Ordering::Less);
1458            assert_eq!(r2.total_cmp(&r1), Ordering::Greater);
1459        }
1460
1461        #[test]
1462        fn mul_add_mul_mut() {
1463            let mut a = RealValidated::try_new(2.).unwrap();
1464            let b = RealValidated::try_new(3.).unwrap(); // mul
1465            let c = RealValidated::try_new(4.).unwrap(); // add_mul1
1466            let d = RealValidated::try_new(5.).unwrap(); // add_mul2
1467            // Expected: a = a*b + c*d = 2*3 + 4*5 = 6 + 20 = 26
1468            a.kernel_mul_add_mul_mut(&b, &c, &d);
1469            assert_eq!(a, RealValidated::try_new(26.).unwrap());
1470        }
1471
1472        #[test]
1473        fn mul_sub_mul_mut() {
1474            let mut a = RealValidated::try_new(10.).unwrap();
1475            let b = RealValidated::try_new(2.).unwrap(); // mul
1476            let c = RealValidated::try_new(3.).unwrap(); // sub_mul1
1477            let d = RealValidated::try_new(4.).unwrap(); // sub_mul2
1478            // Expected: a = a*b - c*d = 10*2 - 3*4 = 20 - 12 = 8
1479            a.kernel_mul_sub_mul_mut(&b, &c, &d);
1480            assert_eq!(a, RealValidated::try_new(8.).unwrap());
1481        }
1482    }
1483
1484    mod complex_scalar_methods {
1485        use super::*;
1486        use crate::functions::{ArgErrors, ArgInputErrors};
1487
1488        #[test]
1489        fn conjugate() {
1490            let c = ComplexValidated::try_new(Complex::new(1., 2.)).unwrap();
1491            let expected = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
1492            assert_eq!(c.conjugate(), expected);
1493
1494            let c_real = ComplexValidated::try_new_pure_real(5.).unwrap();
1495            assert_eq!(c_real.conjugate(), c_real);
1496
1497            let c_imag = ComplexValidated::try_new_pure_imaginary(3.).unwrap();
1498            let expected_imag = ComplexValidated::try_new_pure_imaginary(-3.).unwrap();
1499            assert_eq!(c_imag.conjugate(), expected_imag);
1500        }
1501
1502        #[test]
1503        fn arg_valid() {
1504            // arg(1 + 0i) = 0
1505            let c1 = ComplexValidated::one();
1506            assert_eq!(c1.arg(), RealValidated::zero());
1507
1508            // arg(0 + i) = PI/2
1509            let c2 = ComplexValidated::try_new_pure_imaginary(1.0).unwrap();
1510            let pi_div_2 = RealValidated::try_new(FRAC_PI_2).unwrap();
1511            assert_eq!(c2.arg(), pi_div_2);
1512
1513            // arg(-1 + 0i) = PI
1514            let c3 = ComplexValidated::try_new_pure_real(-1.0).unwrap();
1515            let pi = RealValidated::try_new(PI).unwrap();
1516            assert_eq!(c3.arg(), pi);
1517
1518            // arg(1 + i) = PI/4
1519            let c4 = ComplexValidated::try_new(Complex::new(1.0, 1.0)).unwrap();
1520            let pi_div_4 = RealValidated::try_new(FRAC_PI_4).unwrap();
1521            assert_eq!(c4.arg(), pi_div_4);
1522        }
1523
1524        #[test]
1525        fn arg_zero() {
1526            let zero = ComplexValidated::zero();
1527            let res = zero.try_arg();
1528            assert!(matches!(
1529                res,
1530                Err(ArgErrors::Input {
1531                    source: ArgInputErrors::Zero { .. }
1532                })
1533            ));
1534        }
1535    }
1536
1537    mod function_traits {
1538        use super::*;
1539        use crate::functions::{
1540            ATan2InputErrors, LogarithmRealErrors, LogarithmRealInputErrors,
1541            PowComplexBaseRealExponentInputErrors, PowRealBaseRealExponentInputErrors,
1542            ReciprocalInputErrors, SqrtRealInputErrors,
1543        };
1544
1545        mod min_max {
1546            use super::*;
1547
1548            #[test]
1549            fn max_valid() {
1550                let r1 = RealValidated::try_new(3.).unwrap();
1551                let r2 = RealValidated::try_new(4.).unwrap();
1552                assert_eq!(r1.max_by_ref(&r2), &r2);
1553                assert_eq!(r2.max_by_ref(&r1), &r2);
1554            }
1555
1556            #[test]
1557            fn min_valid() {
1558                let r1 = RealValidated::try_new(3.).unwrap();
1559                let r2 = RealValidated::try_new(4.).unwrap();
1560                assert_eq!(r1.min_by_ref(&r2), &r1);
1561                assert_eq!(r2.min_by_ref(&r1), &r1);
1562            }
1563        }
1564
1565        mod exp {
1566            use super::*;
1567
1568            mod real {
1569                use super::*;
1570
1571                #[test]
1572                fn exp_valid() {
1573                    let exponent = RealValidated::try_new(1.).unwrap();
1574                    let expected = std::f64::consts::E;
1575                    assert_eq!(exponent.try_exp().unwrap().as_ref(), &expected);
1576                    assert_eq!(exponent.exp().as_ref(), &expected);
1577                }
1578
1579                #[test]
1580                fn exp_m1_valid() {
1581                    let exponent = RealValidated::try_new(1.).unwrap();
1582                    let expected = 1.718281828459045;
1583                    assert_ulps_eq!(exponent.exp_m1().as_ref(), &expected);
1584                }
1585
1586                #[test]
1587                fn exp_overflow() {
1588                    let large_val = RealValidated::try_new(1.0e60).unwrap(); // exp(1.0e60) is very large
1589                    let res_large = large_val.try_exp();
1590                    assert!(matches!(
1591                        res_large,
1592                        Err(ExpErrors::Output {
1593                            source: ErrorsValidationRawReal::IsPosInfinity { .. }
1594                        })
1595                    ),);
1596                }
1597            } // end mod 
1598
1599            mod complex {
1600                use super::*;
1601
1602                #[test]
1603                fn exp_valid() {
1604                    let exponent = ComplexValidated::try_new(Complex::new(0., PI)).unwrap();
1605                    let expected = Complex::new(-1., 1.2246467991473532e-16);
1606                    assert_eq!(exponent.try_exp().unwrap().as_ref(), &expected);
1607                    assert_eq!(exponent.exp().as_ref(), &expected);
1608                }
1609            } // end mod complex
1610        } // end mod exp
1611
1612        mod logarithm {
1613            use super::*;
1614
1615            mod real {
1616                use super::*;
1617
1618                #[test]
1619                fn ln_valid() {
1620                    let e = RealValidated::one().exp();
1621                    let expected = 1.0;
1622                    assert_eq!(e.try_ln().unwrap().as_ref(), &expected);
1623                    assert_eq!(e.ln().as_ref(), &expected);
1624                }
1625
1626                #[test]
1627                fn log10_valid() {
1628                    let v = RealValidated::try_new(100.).unwrap();
1629                    let expected = 2.0;
1630                    assert_eq!(v.try_log10().unwrap().as_ref(), &expected);
1631                    assert_eq!(v.log10().as_ref(), &expected);
1632                }
1633
1634                #[test]
1635                fn log2_valid() {
1636                    let v = RealValidated::try_new(4.).unwrap();
1637                    let expected = 2.0;
1638                    assert_eq!(v.try_log2().unwrap().as_ref(), &expected);
1639                    assert_eq!(v.log2().as_ref(), &expected);
1640                }
1641
1642                #[test]
1643                fn ln_1p_valid() {
1644                    // v = e - 1;
1645                    let v = RealValidated::one().exp() - RealValidated::one();
1646
1647                    // ln(1 + v) = ln(1 + e - 1) = ln(e) = 1
1648                    assert_eq!(v.ln_1p().as_ref(), &1.);
1649                }
1650
1651                #[test]
1652                fn ln_domain_errors() {
1653                    let neg_val = RealValidated::try_new(-1.).unwrap();
1654                    assert!(matches!(
1655                        neg_val.try_ln(),
1656                        Err(LogarithmRealErrors::Input {
1657                            source: LogarithmRealInputErrors::NegativeArgument { .. }
1658                        })
1659                    ));
1660
1661                    let zero_val = RealValidated::zero();
1662                    assert!(matches!(
1663                        zero_val.try_ln(),
1664                        Err(LogarithmRealErrors::Input {
1665                            source: LogarithmRealInputErrors::ZeroArgument { .. }
1666                        })
1667                    ));
1668                }
1669
1670                #[test]
1671                fn log10_domain_errors() {
1672                    let neg_val = RealValidated::try_new(-1.).unwrap();
1673                    assert!(matches!(
1674                        neg_val.try_log10(),
1675                        Err(LogarithmRealErrors::Input {
1676                            source: LogarithmRealInputErrors::NegativeArgument { .. }
1677                        })
1678                    ));
1679
1680                    let zero_val = RealValidated::zero();
1681                    assert!(matches!(
1682                        zero_val.try_log10(),
1683                        Err(LogarithmRealErrors::Input {
1684                            source: LogarithmRealInputErrors::ZeroArgument { .. }
1685                        })
1686                    ));
1687                }
1688
1689                #[test]
1690                fn log2_domain_errors() {
1691                    let neg_val = RealValidated::try_new(-1.).unwrap();
1692                    assert!(matches!(
1693                        neg_val.try_log2(),
1694                        Err(LogarithmRealErrors::Input {
1695                            source: LogarithmRealInputErrors::NegativeArgument { .. }
1696                        })
1697                    ));
1698
1699                    let zero_val = RealValidated::zero();
1700                    assert!(matches!(
1701                        zero_val.try_log2(),
1702                        Err(LogarithmRealErrors::Input {
1703                            source: LogarithmRealInputErrors::ZeroArgument { .. }
1704                        })
1705                    ));
1706                }
1707            } // end mod real
1708
1709            mod complex {
1710                use super::*;
1711
1712                #[test]
1713                fn ln_valid() {
1714                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
1715                    let expected = Complex::new(0.8047189562170503, -1.1071487177940904);
1716                    assert_eq!(v.try_ln().unwrap().as_ref(), &expected);
1717                    assert_eq!(v.ln().as_ref(), &expected);
1718                }
1719
1720                #[test]
1721                fn log10_valid() {
1722                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
1723                    let expected = Complex::new(0.3494850021680094, -0.480828578784234);
1724                    assert_eq!(v.try_log10().unwrap().as_ref(), &expected);
1725                    assert_eq!(v.log10().as_ref(), &expected);
1726                }
1727
1728                #[test]
1729                fn log2_valid() {
1730                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
1731                    let expected = Complex::new(1.1609640474436813, -1.5972779646881088);
1732                    assert_eq!(v.try_log2().unwrap().as_ref(), &expected);
1733                    assert_eq!(v.log2().as_ref(), &expected);
1734                }
1735
1736                #[test]
1737                fn ln_zero() {
1738                    let zero_val = ComplexValidated::zero();
1739                    assert!(matches!(
1740                        zero_val.try_ln(),
1741                        Err(LogarithmComplexErrors::Input {
1742                            source: LogarithmComplexInputErrors::ZeroArgument { .. }
1743                        })
1744                    ));
1745                }
1746
1747                #[test]
1748                fn log10_zero() {
1749                    let zero_val = ComplexValidated::zero();
1750                    assert!(matches!(
1751                        zero_val.try_log10(),
1752                        Err(LogarithmComplexErrors::Input {
1753                            source: LogarithmComplexInputErrors::ZeroArgument { .. }
1754                        })
1755                    ));
1756                }
1757
1758                #[test]
1759                fn log2_zero() {
1760                    let zero_val = ComplexValidated::zero();
1761                    assert!(matches!(
1762                        zero_val.try_log2(),
1763                        Err(LogarithmComplexErrors::Input {
1764                            source: LogarithmComplexInputErrors::ZeroArgument { .. }
1765                        })
1766                    ));
1767                }
1768            } // end mod complex
1769        } // end mod logarithm
1770
1771        mod pow {
1772            use super::*;
1773
1774            mod real_base {
1775                use super::*;
1776
1777                #[test]
1778                fn negative_base_real_exponent_error() {
1779                    let base = RealValidated::try_new(-2.).unwrap();
1780                    let exponent = RealValidated::try_new(0.5).unwrap();
1781                    let res = base.try_pow(&exponent);
1782                    assert!(matches!(
1783                        res,
1784                        Err(PowRealBaseRealExponentErrors::Input {
1785                            source: PowRealBaseRealExponentInputErrors::NegativeBase { .. }
1786                        })
1787                    ));
1788                }
1789
1790                #[test]
1791                fn real_base_uint_exponent_valid() {
1792                    let base = RealValidated::try_new(2.).unwrap();
1793                    assert_eq!(
1794                        base.try_pow(3u8).unwrap(),
1795                        RealValidated::try_new(8.).unwrap()
1796                    );
1797                    assert_eq!(
1798                        base.try_pow(3u16).unwrap(),
1799                        RealValidated::try_new(8.).unwrap()
1800                    );
1801                    assert_eq!(
1802                        base.try_pow(3u32).unwrap(),
1803                        RealValidated::try_new(8.).unwrap()
1804                    );
1805                    assert_eq!(
1806                        base.try_pow(3u64).unwrap(),
1807                        RealValidated::try_new(8.).unwrap()
1808                    );
1809                    assert_eq!(
1810                        base.try_pow(3u128).unwrap(),
1811                        RealValidated::try_new(8.).unwrap()
1812                    );
1813                    assert_eq!(
1814                        base.try_pow(3usize).unwrap(),
1815                        RealValidated::try_new(8.).unwrap()
1816                    );
1817
1818                    assert_eq!(base.pow(3u8), RealValidated::try_new(8.).unwrap());
1819                    assert_eq!(base.pow(3u16), RealValidated::try_new(8.).unwrap());
1820                    assert_eq!(base.pow(3u32), RealValidated::try_new(8.).unwrap());
1821                    assert_eq!(base.pow(3u64), RealValidated::try_new(8.).unwrap());
1822                    assert_eq!(base.pow(3u128), RealValidated::try_new(8.).unwrap());
1823                    assert_eq!(base.pow(3usize), RealValidated::try_new(8.).unwrap());
1824                }
1825
1826                #[test]
1827                fn real_base_int_exponent_valid() {
1828                    let base = RealValidated::try_new(2.).unwrap();
1829                    assert_eq!(
1830                        base.try_pow(3i8).unwrap(),
1831                        RealValidated::try_new(8.).unwrap()
1832                    );
1833                    assert_eq!(
1834                        base.try_pow(3i16).unwrap(),
1835                        RealValidated::try_new(8.).unwrap()
1836                    );
1837                    assert_eq!(
1838                        base.try_pow(3i32).unwrap(),
1839                        RealValidated::try_new(8.).unwrap()
1840                    );
1841                    assert_eq!(
1842                        base.try_pow(3i64).unwrap(),
1843                        RealValidated::try_new(8.).unwrap()
1844                    );
1845                    assert_eq!(
1846                        base.try_pow(3i128).unwrap(),
1847                        RealValidated::try_new(8.).unwrap()
1848                    );
1849                    assert_eq!(
1850                        base.try_pow(3isize).unwrap(),
1851                        RealValidated::try_new(8.).unwrap()
1852                    );
1853
1854                    assert_eq!(base.pow(3i8), RealValidated::try_new(8.).unwrap());
1855                    assert_eq!(base.pow(3i16), RealValidated::try_new(8.).unwrap());
1856                    assert_eq!(base.pow(3i32), RealValidated::try_new(8.).unwrap());
1857                    assert_eq!(base.pow(3i64), RealValidated::try_new(8.).unwrap());
1858                    assert_eq!(base.pow(3i128), RealValidated::try_new(8.).unwrap());
1859                    assert_eq!(base.pow(3isize), RealValidated::try_new(8.).unwrap());
1860                }
1861
1862                #[test]
1863                fn real_base_int_exponent_zero_neg_exp_error() {
1864                    let base = RealValidated::zero();
1865                    let exponent: i32 = -2;
1866                    let res = base.try_pow(exponent);
1867                    assert!(matches!(
1868                        res,
1869                        Err(PowIntExponentErrors::Input {
1870                            source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
1871                        })
1872                    ));
1873                }
1874
1875                #[test]
1876                fn real_base_real_exponent_valid() {
1877                    let base = RealValidated::try_new(2.).unwrap();
1878                    let exponent = RealValidated::try_new(3.).unwrap();
1879                    let expected = 8.;
1880                    assert_eq!(base.try_pow(&exponent).unwrap().as_ref(), &expected);
1881                    assert_eq!(base.pow(&exponent).as_ref(), &expected);
1882                }
1883            }
1884
1885            mod complex_base {
1886                use super::*;
1887
1888                #[test]
1889                fn complex_base_uint_exponent_valid() {
1890                    let base = ComplexValidated::try_new(Complex::new(2., 3.)).unwrap();
1891                    let expected_res = ComplexValidated::try_new(Complex::new(-46., 9.)).unwrap();
1892
1893                    assert_eq!(&base.try_pow(3u8).unwrap(), &expected_res);
1894                    assert_eq!(&base.try_pow(3u16).unwrap(), &expected_res);
1895                    assert_eq!(&base.try_pow(3u32).unwrap(), &expected_res);
1896                    assert_eq!(&base.try_pow(3u64).unwrap(), &expected_res);
1897                    assert_eq!(&base.try_pow(3u128).unwrap(), &expected_res);
1898                    assert_eq!(&base.try_pow(3usize).unwrap(), &expected_res);
1899
1900                    assert_eq!(&base.pow(3u8), &expected_res);
1901                    assert_eq!(&base.pow(3u16), &expected_res);
1902                    assert_eq!(&base.pow(3u32), &expected_res);
1903                    assert_eq!(&base.pow(3u64), &expected_res);
1904                    assert_eq!(&base.pow(3u128), &expected_res);
1905                    assert_eq!(&base.pow(3usize), &expected_res);
1906                }
1907
1908                #[test]
1909                fn complex_base_int_exponent_valid() {
1910                    let base = ComplexValidated::try_new(Complex::new(2., 3.)).unwrap();
1911                    let expected_res = ComplexValidated::try_new(Complex::new(-46., 9.)).unwrap();
1912
1913                    assert_eq!(&base.try_pow(3i8).unwrap(), &expected_res);
1914                    assert_eq!(&base.try_pow(3i16).unwrap(), &expected_res);
1915                    assert_eq!(&base.try_pow(3i32).unwrap(), &expected_res);
1916                    assert_eq!(&base.try_pow(3i64).unwrap(), &expected_res);
1917                    assert_eq!(&base.try_pow(3i128).unwrap(), &expected_res);
1918                    assert_eq!(&base.try_pow(3isize).unwrap(), &expected_res);
1919
1920                    assert_eq!(&base.pow(3i8), &expected_res);
1921                    assert_eq!(&base.pow(3i16), &expected_res);
1922                    assert_eq!(&base.pow(3i32), &expected_res);
1923                    assert_eq!(&base.pow(3i64), &expected_res);
1924                    assert_eq!(&base.pow(3i128), &expected_res);
1925                    assert_eq!(&base.pow(3isize), &expected_res);
1926                }
1927
1928                #[test]
1929                fn complex_zero_base_negative_real_exponent_error() {
1930                    let base = ComplexValidated::zero();
1931                    let exponent = RealValidated::try_new(-2.).unwrap();
1932                    let res = base.try_pow(&exponent);
1933                    assert!(matches!(
1934                        res,
1935                        Err(PowComplexBaseRealExponentErrors::Input {
1936                            source:
1937                                PowComplexBaseRealExponentInputErrors::ZeroBaseNegativeExponent { .. }
1938                        })
1939                    ));
1940                }
1941
1942                #[test]
1943                fn complex_zero_base_zero_real_exponent() {
1944                    let base = ComplexValidated::zero();
1945                    let exponent = RealValidated::zero();
1946                    let res = base.try_pow(&exponent).unwrap();
1947                    assert_eq!(res, ComplexValidated::one());
1948                }
1949
1950                #[test]
1951                fn complex_base_int_exponent_zero_neg_exp_error() {
1952                    let base = ComplexValidated::zero();
1953                    let exponent: i32 = -2;
1954                    let res = base.try_pow(exponent);
1955                    assert!(matches!(
1956                        res,
1957                        Err(PowIntExponentErrors::Input {
1958                            source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
1959                        })
1960                    ));
1961                }
1962
1963                #[test]
1964                fn complex_base_real_exponent_valid() {
1965                    let base = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
1966                    let exponent = RealValidated::try_new(3.).unwrap();
1967                    let expected = Complex::new(-11.000000000000004, 1.9999999999999973);
1968                    assert_eq!(base.try_pow(&exponent).unwrap().as_ref(), &expected);
1969                    assert_eq!(base.pow(&exponent).as_ref(), &expected);
1970                }
1971
1972                #[test]
1973                fn complex_zero_base_real_exponent_valid() {
1974                    let base = ComplexValidated::zero();
1975                    let exponent = RealValidated::try_new(3.).unwrap();
1976                    let expected = Complex::new(0., 0.);
1977                    assert_eq!(base.try_pow(&exponent).unwrap().as_ref(), &expected);
1978                    assert_eq!(base.pow(&exponent).as_ref(), &expected);
1979                }
1980            }
1981        }
1982
1983        mod reciprocal {
1984            use super::*;
1985
1986            mod real {
1987                use super::*;
1988
1989                #[test]
1990                fn reciprocal_valid() {
1991                    let v = RealValidated::try_new(2.).unwrap();
1992
1993                    let res = v.try_reciprocal().unwrap();
1994                    assert_eq!(res.into_inner(), 0.5);
1995
1996                    let res = v.reciprocal();
1997                    assert_eq!(res.into_inner(), 0.5);
1998                }
1999
2000                #[test]
2001                fn reciprocal_real_zero() {
2002                    let zero_val = RealValidated::zero();
2003                    let res = zero_val.try_reciprocal();
2004                    assert!(matches!(
2005                        res,
2006                        Err(ReciprocalErrors::Input {
2007                            source: ReciprocalInputErrors::DivisionByZero { .. }
2008                        })
2009                    ));
2010                }
2011            }
2012
2013            mod complex {
2014                use super::*;
2015
2016                #[test]
2017                fn reciprocal_valid() {
2018                    let v = ComplexValidated::try_new(Complex::new(3., 4.)).unwrap();
2019
2020                    let expected = Complex::new(0.12, -0.16);
2021
2022                    let res = v.try_reciprocal().unwrap();
2023                    assert_eq!(res.as_ref(), &expected);
2024
2025                    let res = v.reciprocal();
2026                    assert_eq!(res.as_ref(), &expected);
2027                }
2028
2029                #[test]
2030                fn reciprocal_complex_zero() {
2031                    let zero_val = ComplexValidated::zero();
2032                    let res = zero_val.try_reciprocal();
2033                    assert!(matches!(
2034                        res,
2035                        Err(ReciprocalErrors::Input {
2036                            source: ReciprocalInputErrors::DivisionByZero { .. }
2037                        })
2038                    ));
2039                }
2040            }
2041        } // end mod reciprocal
2042
2043        mod sqrt {
2044            use super::*;
2045
2046            mod real {
2047                use super::*;
2048
2049                #[test]
2050                fn sqrt_valid() {
2051                    let v = RealValidated::try_new(9.).unwrap();
2052                    assert_eq!(v.try_sqrt().unwrap().as_ref(), &3.);
2053                    assert_eq!(v.sqrt().as_ref(), &3.);
2054                }
2055
2056                #[test]
2057                fn sqrt_negative_input() {
2058                    let neg_val = RealValidated::try_new(-4.).unwrap();
2059                    let res = neg_val.try_sqrt();
2060                    assert!(matches!(
2061                        res,
2062                        Err(SqrtRealErrors::Input {
2063                            source: SqrtRealInputErrors::NegativeValue { .. }
2064                        })
2065                    ));
2066                }
2067            } // end mod real
2068
2069            mod complex {
2070                use super::*;
2071
2072                #[test]
2073                fn sqrt_valid() {
2074                    let expected = Complex::new(1., 2.);
2075                    let v = ComplexValidated::try_new(expected * expected).unwrap();
2076
2077                    let expected = Complex::new(1.0000000000000002, 2.);
2078                    assert_eq!(v.try_sqrt().unwrap().as_ref(), &expected);
2079                    assert_eq!(v.sqrt().as_ref(), &expected);
2080                }
2081            }
2082        } // end mod sqrt
2083
2084        mod trigonometric {
2085            use super::*;
2086
2087            mod real {
2088                use super::*;
2089
2090                #[test]
2091                fn sin_real_valid() {
2092                    let v = RealValidated::pi_div_2();
2093
2094                    let expected = 1.;
2095                    assert_eq!(v.try_sin().unwrap().as_ref(), &expected);
2096                    assert_eq!(v.sin().as_ref(), &expected);
2097                }
2098
2099                #[test]
2100                fn cos_real_valid() {
2101                    let v = RealValidated::pi();
2102
2103                    let expected = -1.;
2104                    assert_eq!(v.try_cos().unwrap().as_ref(), &expected);
2105                    assert_eq!(v.cos().as_ref(), &expected);
2106                }
2107
2108                #[test]
2109                fn tan_real_valid() {
2110                    let v = RealValidated::one();
2111                    let expected = 1.5574077246549023;
2112                    assert_ulps_eq!(v.try_tan().unwrap().as_ref(), &expected);
2113                    assert_ulps_eq!(v.tan().as_ref(), &expected);
2114                }
2115
2116                #[test]
2117                fn asin_real_valid() {
2118                    let v = RealValidated::one();
2119
2120                    let expected = std::f64::consts::FRAC_PI_2; // π/2
2121                    assert_eq!(v.try_asin().unwrap().as_ref(), &expected);
2122                    assert_eq!(v.asin().as_ref(), &expected);
2123                }
2124
2125                #[test]
2126                fn acos_real_valid() {
2127                    let v = RealValidated::one();
2128
2129                    let expected = 0.;
2130                    assert_eq!(v.try_acos().unwrap().as_ref(), &expected);
2131                    assert_eq!(v.acos().as_ref(), &expected);
2132                }
2133
2134                #[test]
2135                fn atan_real_valid() {
2136                    let v = RealValidated::one();
2137
2138                    let expected = std::f64::consts::FRAC_PI_4; // π/4
2139                    assert_eq!(v.try_atan().unwrap().as_ref(), &expected);
2140                    assert_eq!(v.atan().as_ref(), &expected);
2141                }
2142
2143                #[test]
2144                fn atan2_valid() {
2145                    let one = RealValidated::one();
2146                    let zero = RealValidated::zero();
2147
2148                    let expected = std::f64::consts::FRAC_PI_2; // π/2
2149                    assert_eq!(one.try_atan2(&zero).unwrap().as_ref(), &expected);
2150                    assert_eq!(one.atan2(&zero).as_ref(), &expected);
2151
2152                    let expected = 0.;
2153                    assert_eq!(zero.try_atan2(&one).unwrap().as_ref(), &expected);
2154                    assert_eq!(zero.atan2(&one).as_ref(), &expected);
2155
2156                    let expected = std::f64::consts::FRAC_PI_4; // π/4
2157                    assert_eq!(one.try_atan2(&one).unwrap().as_ref(), &expected);
2158                    assert_eq!(one.atan2(&one).as_ref(), &expected);
2159                }
2160
2161                #[test]
2162                fn atan2_zero_over_zero() {
2163                    let zero_val = RealValidated::zero();
2164                    let res = zero_val.try_atan2(&RealValidated::zero());
2165                    assert!(matches!(
2166                        res,
2167                        Err(ATan2Errors::Input {
2168                            source: ATan2InputErrors::ZeroOverZero { .. }
2169                        })
2170                    ));
2171                }
2172
2173                /*
2174                #[test]
2175                #[ignore = "at the moment we cannot create a pole for the Tan function"]
2176                fn tan_real_pole() {
2177                    // tan(PI/2) is a pole
2178                    let pi_half = RealValidated::pi_div_2();
2179                    let res = pi_half.try_tan();
2180                    println!("Result: {:?}", res);
2181                    assert!(matches!(
2182                        res,
2183                        Err(TanRealErrors::Input {
2184                            source: TanRealInputErrors::ArgumentIsPole { .. }
2185                        })
2186                    ));
2187                }
2188                */
2189
2190                #[test]
2191                fn asin_real_out_of_domain() {
2192                    let val_gt_1 = RealValidated::try_new(1.5).unwrap();
2193                    assert!(matches!(
2194                        val_gt_1.try_asin(),
2195                        Err(ASinRealErrors::Input {
2196                            source: ASinRealInputErrors::OutOfDomain { .. }
2197                        })
2198                    ));
2199                    let val_lt_neg1 = RealValidated::try_new(-1.5).unwrap();
2200                    assert!(matches!(
2201                        val_lt_neg1.try_asin(),
2202                        Err(ASinRealErrors::Input {
2203                            source: ASinRealInputErrors::OutOfDomain { .. }
2204                        })
2205                    ));
2206                }
2207
2208                #[test]
2209                fn acos_real_out_of_domain() {
2210                    let val_gt_1 = RealValidated::try_new(1.5).unwrap();
2211                    assert!(matches!(
2212                        val_gt_1.try_acos(),
2213                        Err(ACosRealErrors::Input {
2214                            source: ACosRealInputErrors::OutOfDomain { .. }
2215                        })
2216                    ));
2217                    let val_lt_neg1 = RealValidated::try_new(-1.5).unwrap();
2218                    assert!(matches!(
2219                        val_lt_neg1.try_acos(),
2220                        Err(ACosRealErrors::Input {
2221                            source: ACosRealInputErrors::OutOfDomain { .. }
2222                        })
2223                    ));
2224                }
2225            } // end mod real
2226
2227            mod complex {
2228                use super::*;
2229
2230                #[test]
2231                fn sin_complex_valid() {
2232                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2233
2234                    let expected = if cfg!(target_arch = "x86_64") {
2235                        Complex::new(3.165778513216168, -1.9596010414216063)
2236                    } else if cfg!(target_arch = "aarch64") {
2237                        Complex::new(3.165778513216168, -1.959601041421606)
2238                    } else {
2239                        todo!("Architecture not-tested");
2240                    };
2241                    assert_eq!(v.try_sin().unwrap().as_ref(), &expected);
2242                    assert_eq!(v.sin().as_ref(), &expected);
2243
2244                    let zero = ComplexValidated::zero();
2245                    let expected = Complex::new(0., 0.);
2246                    assert_eq!(zero.try_sin().unwrap().as_ref(), &expected);
2247                    assert_eq!(zero.sin().as_ref(), &expected);
2248                }
2249
2250                #[test]
2251                fn cos_complex_valid() {
2252                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2253
2254                    let expected = if cfg!(target_arch = "x86_64") {
2255                        Complex::new(2.0327230070196656, 3.0518977991518)
2256                    } else if cfg!(target_arch = "aarch64") {
2257                        Complex::new(2.0327230070196656, 3.0518977991517997)
2258                    } else {
2259                        todo!("Architecture not-tested");
2260                    };
2261                    assert_eq!(v.try_cos().unwrap().as_ref(), &expected);
2262                    assert_eq!(v.cos().as_ref(), &expected);
2263
2264                    let zero = ComplexValidated::zero();
2265                    let expected = Complex::new(1., 0.);
2266                    assert_eq!(zero.try_cos().unwrap().as_ref(), &expected);
2267                    assert_eq!(zero.cos().as_ref(), &expected);
2268                }
2269
2270                #[test]
2271                fn tan_complex_valid() {
2272                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2273
2274                    let expected = Complex::new(0.03381282607989669, -1.0147936161466335);
2275                    assert_eq!(v.try_tan().unwrap().as_ref(), &expected);
2276                    assert_eq!(v.tan().as_ref(), &expected);
2277
2278                    let zero = ComplexValidated::zero();
2279                    let expected = Complex::new(0., 0.);
2280                    assert_eq!(zero.try_tan().unwrap().as_ref(), &expected);
2281                    assert_eq!(zero.tan().as_ref(), &expected);
2282                }
2283
2284                #[test]
2285                fn asin_complex_valid() {
2286                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2287
2288                    let expected = Complex::new(0.42707858639247614, -1.528570919480998);
2289                    assert_eq!(v.try_asin().unwrap().as_ref(), &expected);
2290                    assert_eq!(v.asin().as_ref(), &expected);
2291
2292                    let zero = ComplexValidated::zero();
2293                    let expected = Complex::new(0., 0.);
2294                    assert_eq!(zero.try_asin().unwrap().as_ref(), &expected);
2295                    assert_eq!(zero.asin().as_ref(), &expected);
2296                }
2297
2298                #[test]
2299                fn acos_complex_valid() {
2300                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2301
2302                    let expected = Complex::new(1.14371774040242, 1.5285709194809995);
2303                    assert_eq!(v.try_acos().unwrap().as_ref(), &expected);
2304                    assert_eq!(v.acos().as_ref(), &expected);
2305
2306                    let one = ComplexValidated::one();
2307                    let expected = Complex::new(0., 0.);
2308                    assert_eq!(one.try_acos().unwrap().as_ref(), &expected);
2309                    assert_eq!(one.acos().as_ref(), &expected);
2310                }
2311
2312                #[test]
2313                fn atan_complex_valid() {
2314                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2315
2316                    let expected = Complex::new(1.3389725222944935, -0.4023594781085251);
2317                    assert_eq!(v.try_atan().unwrap().as_ref(), &expected);
2318                    assert_eq!(v.atan().as_ref(), &expected);
2319
2320                    let zero = ComplexValidated::zero();
2321                    let expected = Complex::new(0., 0.);
2322                    assert_eq!(zero.try_atan().unwrap().as_ref(), &expected);
2323                    assert_eq!(zero.atan().as_ref(), &expected);
2324                }
2325
2326                #[test]
2327                fn atan_complex_pole() {
2328                    // atan(i) and atan(-i) are poles
2329                    let i_val = ComplexValidated::try_new_pure_imaginary(1.).unwrap();
2330                    assert!(matches!(
2331                        i_val.try_atan(),
2332                        Err(ATanComplexErrors::Input {
2333                            source: ATanComplexInputErrors::ArgumentIsPole { .. }
2334                        })
2335                    ));
2336
2337                    let neg_i_val = ComplexValidated::try_new_pure_imaginary(-1.).unwrap();
2338                    assert!(matches!(
2339                        neg_i_val.try_atan(),
2340                        Err(ATanComplexErrors::Input {
2341                            source: ATanComplexInputErrors::ArgumentIsPole { .. }
2342                        })
2343                    ));
2344                }
2345            } // end mod complex
2346        } // end mod trigonometric
2347
2348        mod hyperbolic {
2349            use super::*;
2350
2351            mod real {
2352                use super::*;
2353
2354                #[test]
2355                fn atanh_real_valid() {
2356                    let v = RealValidated::zero();
2357                    let expected = 0.;
2358                    assert_eq!(v.try_atanh().unwrap().as_ref(), &expected);
2359                    assert_eq!(v.atanh().as_ref(), &expected);
2360                }
2361
2362                #[test]
2363                fn atanh_real_out_of_domain() {
2364                    let val_ge_1 = RealValidated::one(); // atanh(1) is Inf
2365                    assert!(matches!(
2366                        val_ge_1.try_atanh(),
2367                        Err(ATanHErrors::Input {
2368                            source: ATanHInputErrors::OutOfDomain { .. }
2369                        })
2370                    ));
2371
2372                    let val_le_neg1 = RealValidated::negative_one(); // atanh(-1) is -Inf
2373                    assert!(matches!(
2374                        val_le_neg1.try_atanh(),
2375                        Err(ATanHErrors::Input {
2376                            source: ATanHInputErrors::OutOfDomain { .. }
2377                        })
2378                    ));
2379                }
2380
2381                #[test]
2382                fn acosh_real_valid() {
2383                    let v = RealValidated::one();
2384                    let expected = 0.;
2385                    assert_eq!(v.try_acosh().unwrap().as_ref(), &expected);
2386                    assert_eq!(v.acosh().as_ref(), &expected);
2387                }
2388
2389                #[test]
2390                fn acosh_real_out_of_domain() {
2391                    let val_lt_1 = RealValidated::try_new(0.5).unwrap();
2392                    assert!(matches!(
2393                        val_lt_1.try_acosh(),
2394                        Err(ACosHErrors::Input {
2395                            source: ACosHInputErrors::OutOfDomain { .. }
2396                        })
2397                    ));
2398                }
2399
2400                #[test]
2401                fn asinh_real_valid() {
2402                    let v = RealValidated::one();
2403                    let expected = 0.881373587019543;
2404                    assert_eq!(v.try_asinh().unwrap().as_ref(), &expected);
2405                    assert_eq!(v.asinh().as_ref(), &expected);
2406                }
2407
2408                #[test]
2409                fn sinh_real_valid() {
2410                    let v = RealValidated::try_new(0.881373587019543).unwrap();
2411                    let expected = 1.;
2412                    assert_eq!(v.try_sinh().unwrap().as_ref(), &expected);
2413                    assert_eq!(v.sinh().as_ref(), &expected);
2414                }
2415
2416                #[test]
2417                fn cosh_real_valid() {
2418                    let v = RealValidated::one();
2419                    let expected = 1.5430806348152437;
2420                    assert_eq!(v.try_cosh().unwrap().as_ref(), &expected);
2421                    assert_eq!(v.cosh().as_ref(), &expected);
2422                }
2423
2424                #[test]
2425                fn tanh_real_valid() {
2426                    let v = RealValidated::one();
2427                    let expected = 0.7615941559557649;
2428                    assert_eq!(v.try_tanh().unwrap().as_ref(), &expected);
2429                    assert_eq!(v.tanh().as_ref(), &expected);
2430                }
2431            }
2432
2433            mod complex {
2434                use super::*;
2435
2436                #[test]
2437                fn sinh_valid() {
2438                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2439                    let expected = Complex::new(-0.4890562590412937, -1.4031192506220405);
2440                    assert_eq!(v.try_sinh().unwrap().as_ref(), &expected);
2441                    assert_eq!(v.sinh().as_ref(), &expected);
2442                }
2443
2444                #[test]
2445                fn cosh_valid() {
2446                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2447                    let expected = Complex::new(-0.64214812471552, -1.0686074213827783);
2448                    assert_eq!(v.try_cosh().unwrap().as_ref(), &expected);
2449                    assert_eq!(v.cosh().as_ref(), &expected);
2450                }
2451
2452                #[test]
2453                fn tanh_valid() {
2454                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2455                    let expected = if cfg!(target_arch = "x86_64") {
2456                        Complex::new(1.16673625724092, 0.24345820118572523)
2457                    } else if cfg!(target_arch = "aarch64") {
2458                        Complex::new(1.16673625724092, 0.24345820118572528)
2459                    } else {
2460                        todo!("Architecture not-tested");
2461                    };
2462                    assert_eq!(v.try_tanh().unwrap().as_ref(), &expected);
2463                    assert_eq!(v.tanh().as_ref(), &expected);
2464                }
2465
2466                #[test]
2467                fn asinh_valid() {
2468                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2469                    let expected = Complex::new(1.4693517443681852, -1.0634400235777521);
2470                    Complex::new(1.4693517443681852, -1.0634400235777521);
2471                    assert_eq!(v.try_asinh().unwrap().as_ref(), &expected);
2472                    assert_eq!(v.asinh().as_ref(), &expected);
2473                }
2474
2475                #[test]
2476                fn acosh_valid() {
2477                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2478                    let expected = Complex::new(1.528570919480998, -1.1437177404024206);
2479                    assert_eq!(v.try_acosh().unwrap().as_ref(), &expected);
2480                    assert_eq!(v.acosh().as_ref(), &expected);
2481                }
2482
2483                #[test]
2484                fn atanh_valid() {
2485                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2486                    let expected = Complex::new(0.1732867951399864, -1.1780972450961724);
2487                    assert_eq!(v.try_atanh().unwrap().as_ref(), &expected);
2488                    assert_eq!(v.atanh().as_ref(), &expected);
2489                }
2490
2491                /*
2492                #[test]
2493                #[ignore = "at the moment we cannot create a pole for the ATanH function"]
2494                fn tanh_complex_pole() {
2495                    // tanh(z) has poles where cosh(z) = 0. e.g. z = i * (PI/2 + k*PI)
2496                    let pi_half = RealValidated::pi_div_2().into_inner();
2497                    let pole_val =
2498                        Complex64Validated::try_new_pure_imaginary(pi_half).unwrap();
2499                    println!("Atanh(Pole value): {:?}", pole_val.clone().try_tanh());
2500                    assert!(matches!(
2501                        pole_val.try_tanh(),
2502                        Err(TanHComplexErrors::Input {
2503                            source: TanHComplexInputErrors::OutOfDomain { .. }
2504                        })
2505                    ));
2506                }
2507                */
2508
2509                #[test]
2510                fn acosh_out_of_domain() {
2511                    // acosh(z) domain is C \ (-inf, 1) on real axis
2512                    let val_on_branch_cut = ComplexValidated::try_new_pure_real(0.5).unwrap();
2513                    assert!(matches!(
2514                        val_on_branch_cut.try_acosh(),
2515                        Err(ACosHErrors::Input {
2516                            source: ACosHInputErrors::OutOfDomain { .. }
2517                        })
2518                    ));
2519
2520                    let val_on_branch_cut_neg = ComplexValidated::try_new_pure_real(-5.).unwrap();
2521                    assert!(matches!(
2522                        val_on_branch_cut_neg.try_acosh(),
2523                        Err(ACosHErrors::Input {
2524                            source: ACosHInputErrors::OutOfDomain { .. }
2525                        })
2526                    ));
2527                }
2528
2529                #[test]
2530                fn atanh_out_of_domain() {
2531                    let val_ge_1 = ComplexValidated::try_new_pure_real(1.).unwrap();
2532                    assert!(matches!(
2533                        val_ge_1.try_atanh(),
2534                        Err(ATanHErrors::Input {
2535                            source: ATanHInputErrors::OutOfDomain { .. }
2536                        })
2537                    ));
2538
2539                    let val_le_neg1 = ComplexValidated::try_new_pure_real(-1.).unwrap();
2540                    assert!(matches!(
2541                        val_le_neg1.try_atanh(),
2542                        Err(ATanHErrors::Input {
2543                            source: ATanHInputErrors::OutOfDomain { .. }
2544                        })
2545                    ));
2546                }
2547            }
2548
2549            /*
2550            #[test]
2551            #[ignore = "at the moment we cannot create a pole for the TanH function"]
2552            fn tanh_out_of_domain() {
2553                // tanh(z) has poles where cosh(z) = 0. e.g. z = i * (PI/2 + k*PI)
2554                let pi_half = RealValidated::pi_div_2().into_inner();
2555                let pole_val = Complex64Validated::try_new_pure_imaginary(pi_half).unwrap();
2556                println!("TanH(Pole value): {:?}", pole_val.clone().try_tanh());
2557                assert!(matches!(
2558                    pole_val.try_tanh(),
2559                    Err(TanHComplexErrors::Input {
2560                        source: TanHComplexInputErrors::OutOfDomain { .. }
2561                    })
2562                ));
2563            }
2564            */
2565        } // end mod hyperbolic
2566    }
2567
2568    mod summation {
2569        use super::*;
2570
2571        #[test]
2572        fn sum_real() {
2573            let values = vec![
2574                RealValidated::try_new(1.0).unwrap(),
2575                RealValidated::try_new(2.0).unwrap(),
2576                RealValidated::try_new(3.0).unwrap(),
2577                RealValidated::try_new(4.0).unwrap(),
2578                RealValidated::try_new(5.0).unwrap(),
2579            ];
2580            let sum: RealValidated = values.into_iter().sum();
2581            assert_eq!(sum, RealValidated::try_new(15.0).unwrap());
2582        }
2583
2584        #[test]
2585        fn sum_real_compensated() {
2586            // Test case where simple summation might lose precision
2587            let values = vec![
2588                RealValidated::try_new(1.0e100).unwrap(),
2589                RealValidated::try_new(1.0).unwrap(),
2590                RealValidated::try_new(-1.0e100).unwrap(),
2591            ];
2592            let sum: RealValidated = values.into_iter().sum();
2593            // The Neumaier sum should correctly result in 1.0
2594            assert_eq!(sum, RealValidated::try_new(1.0).unwrap());
2595        }
2596
2597        #[test]
2598        fn sum_complex() {
2599            let values = vec![
2600                ComplexValidated::try_new(Complex::new(1.0, 2.0)).unwrap(),
2601                ComplexValidated::try_new(Complex::new(3.0, 4.0)).unwrap(),
2602                ComplexValidated::try_new(Complex::new(5.0, 6.0)).unwrap(),
2603            ];
2604            let sum: ComplexValidated = values.into_iter().sum();
2605            assert_eq!(
2606                sum,
2607                ComplexValidated::try_new(Complex::new(9.0, 12.0)).unwrap()
2608            );
2609        }
2610
2611        #[test]
2612        fn sum_complex_compensated() {
2613            let values = vec![
2614                ComplexValidated::try_new(Complex::new(1.0e100, -1.0e100)).unwrap(),
2615                ComplexValidated::try_new(Complex::new(1.0, 2.0)).unwrap(),
2616                ComplexValidated::try_new(Complex::new(-1.0e100, 1.0e100)).unwrap(),
2617            ];
2618            let sum: ComplexValidated = values.into_iter().sum();
2619            assert_eq!(
2620                sum,
2621                ComplexValidated::try_new(Complex::new(1.0, 2.0)).unwrap()
2622            );
2623        }
2624    } // end mod summation
2625
2626    mod neumaier_sum {
2627        use crate::algorithms::neumaier_sum::NeumaierSum;
2628        use try_create::TryNewValidated;
2629
2630        use super::*;
2631
2632        mod real {
2633            use super::*;
2634
2635            #[test]
2636            fn new() {
2637                let neumaier = NeumaierSum::new(RealValidated::try_new_validated(1.0).unwrap());
2638                assert_eq!(neumaier.sum_before_compensation(), &1.0);
2639                assert_eq!(neumaier.compensation(), &0.0);
2640            }
2641
2642            #[test]
2643            fn zero() {
2644                let neumaier = NeumaierSum::<RealValidated>::zero();
2645                assert_eq!(neumaier.sum_before_compensation(), &0.0);
2646                assert_eq!(neumaier.compensation(), &0.0);
2647            }
2648
2649            #[test]
2650            fn add() {
2651                let mut neumaier = NeumaierSum::zero();
2652                neumaier.add(RealValidated::try_new_validated(1.0).unwrap());
2653                neumaier.add(RealValidated::try_new_validated(1e-16).unwrap());
2654                neumaier.add(RealValidated::try_new_validated(-1.0).unwrap());
2655                assert_eq!(neumaier.sum_before_compensation(), &0.0);
2656                assert_eq!(neumaier.compensation(), &1e-16);
2657            }
2658
2659            #[test]
2660            fn sum() {
2661                let mut neumaier = NeumaierSum::zero();
2662                neumaier.add(RealValidated::try_new_validated(1.0).unwrap());
2663                neumaier.add(RealValidated::try_new_validated(1e-16).unwrap());
2664                neumaier.add(RealValidated::try_new_validated(-1.0).unwrap());
2665                assert_eq!(neumaier.sum_before_compensation(), &0.0);
2666                assert_eq!(neumaier.compensation(), &1e-16);
2667                assert_eq!(neumaier.sum().as_ref(), &1e-16);
2668                println!("compensated sum = {}", neumaier.sum());
2669            }
2670
2671            #[test]
2672            fn reset() {
2673                let mut neumaier = NeumaierSum::zero();
2674                neumaier.add(RealValidated::try_new_validated(1.0).unwrap());
2675                neumaier.add(RealValidated::try_new_validated(1e-16).unwrap());
2676                assert_eq!(neumaier.sum_before_compensation(), &1.0);
2677                assert_eq!(neumaier.compensation(), &1e-16);
2678
2679                neumaier.reset();
2680                assert_eq!(neumaier.sum_before_compensation(), &0.0);
2681                assert_eq!(neumaier.compensation(), &0.0);
2682            }
2683
2684            #[test]
2685            fn sum_big_values() {
2686                let values = [1.0, 1e100, 1.0, -1e100]
2687                    .iter()
2688                    .map(|&v| RealValidated::try_new_validated(v).unwrap())
2689                    .collect::<Vec<_>>();
2690                let sum = values.iter().cloned().sum::<RealValidated>();
2691                assert_eq!(sum, 2.0);
2692
2693                let neumaier = NeumaierSum::new_sequential(values);
2694                assert_eq!(neumaier.sum(), 2.0);
2695                println!("compensated sum = {}", neumaier.sum());
2696            }
2697
2698            #[test]
2699            fn sum_small_values() {
2700                let values = [1.0, 1e-100, -1.0]
2701                    .iter()
2702                    .map(|&v| RealValidated::try_new_validated(v).unwrap())
2703                    .collect::<Vec<_>>();
2704                let sum = values.iter().cloned().sum::<RealValidated>();
2705                assert_eq!(sum, 1e-100);
2706
2707                let neumaier = NeumaierSum::new_sequential(values);
2708                assert_eq!(neumaier.sum(), 1e-100);
2709                println!("compensated sum = {}", neumaier.sum());
2710            }
2711        }
2712
2713        mod complex {
2714            use super::*;
2715
2716            #[test]
2717            fn new() {
2718                let neumaier = NeumaierSum::new(
2719                    ComplexValidated::try_new_validated(Complex::new(1.0, 2.0)).unwrap(),
2720                );
2721                assert_eq!(
2722                    neumaier.sum_before_compensation().as_ref(),
2723                    &Complex::new(1.0, 2.0)
2724                );
2725                assert_eq!(neumaier.compensation().as_ref(), &Complex::new(0.0, 0.0));
2726            }
2727
2728            #[test]
2729            fn zero() {
2730                let neumaier = NeumaierSum::<ComplexValidated>::zero();
2731
2732                let zero = Complex::new(0.0, 0.0);
2733                assert_eq!(neumaier.sum_before_compensation().as_ref(), &zero);
2734                assert_eq!(neumaier.compensation().as_ref(), &zero);
2735            }
2736
2737            #[test]
2738            fn add() {
2739                let zero = Complex::new(0.0, 0.0);
2740                let v = Complex::new(1e-16, 2e-16);
2741
2742                let mut neumaier = NeumaierSum::zero();
2743                neumaier.add(ComplexValidated::try_new_validated(Complex::new(1.0, 2.0)).unwrap());
2744                neumaier.add(ComplexValidated::try_new_validated(v).unwrap());
2745                neumaier
2746                    .add(ComplexValidated::try_new_validated(Complex::new(-1.0, -2.0)).unwrap());
2747
2748                assert_eq!(neumaier.sum_before_compensation().as_ref(), &zero);
2749                assert_eq!(neumaier.compensation().as_ref(), &v);
2750            }
2751
2752            #[test]
2753            fn sum() {
2754                let zero = Complex::new(0.0, 0.0);
2755                let v = Complex::new(1e-16, 2e-16);
2756
2757                let mut neumaier = NeumaierSum::zero();
2758                neumaier.add(ComplexValidated::try_new_validated(Complex::new(1.0, 2.0)).unwrap());
2759                neumaier.add(ComplexValidated::try_new_validated(v).unwrap());
2760                neumaier
2761                    .add(ComplexValidated::try_new_validated(Complex::new(-1.0, -2.0)).unwrap());
2762                assert_eq!(neumaier.sum_before_compensation().as_ref(), &zero);
2763                assert_eq!(neumaier.compensation().as_ref(), &v);
2764                assert_eq!(neumaier.sum().as_ref(), &v);
2765                println!("compensated sum = {}", neumaier.sum());
2766            }
2767
2768            #[test]
2769            fn reset() {
2770                let zero = Complex::new(0.0, 0.0);
2771                let a = Complex::new(1.0, 2.0);
2772                let v = Complex::new(1e-16, 2e-16);
2773
2774                let mut neumaier = NeumaierSum::zero();
2775                neumaier.add(ComplexValidated::try_new_validated(a).unwrap());
2776                neumaier.add(ComplexValidated::try_new_validated(v).unwrap());
2777                assert_eq!(neumaier.sum_before_compensation().as_ref(), &a);
2778                assert_eq!(neumaier.compensation().as_ref(), &v);
2779
2780                neumaier.reset();
2781                assert_eq!(neumaier.sum_before_compensation().as_ref(), &zero);
2782                assert_eq!(neumaier.compensation().as_ref(), &zero);
2783            }
2784
2785            #[test]
2786            fn sum_big_values() {
2787                let values = [
2788                    Complex::new(1.0, 2.0),
2789                    Complex::new(1e100, 2e100),
2790                    Complex::new(1.0, 2.0),
2791                    Complex::new(-1e100, -2e100),
2792                ]
2793                .iter()
2794                .map(|&v| ComplexValidated::try_new_validated(v).unwrap())
2795                .collect::<Vec<_>>();
2796                let sum = values.clone().into_iter().sum::<ComplexValidated>();
2797                let expected_sum = Complex::new(2., 4.);
2798                assert_eq!(sum.as_ref(), &expected_sum);
2799
2800                let neumaier = NeumaierSum::new_sequential(values);
2801                assert_eq!(neumaier.sum().as_ref(), &expected_sum);
2802                println!("compensated sum = {}", neumaier.sum());
2803            }
2804
2805            #[test]
2806            fn sum_small_values() {
2807                let v = Complex::new(1e-100, 2e-100);
2808
2809                let values = [Complex::new(1.0, 2.0), v, Complex::new(-1.0, -2.0)]
2810                    .iter()
2811                    .map(|&v| ComplexValidated::try_new_validated(v).unwrap())
2812                    .collect::<Vec<_>>();
2813                let sum = values.iter().cloned().sum::<ComplexValidated>();
2814                let sum_expected = v;
2815                assert_eq!(sum.as_ref(), &sum_expected);
2816
2817                let neumaier = NeumaierSum::new_sequential(values);
2818                assert_eq!(neumaier.sum().as_ref(), &sum_expected);
2819                println!("compensated sum = {}", neumaier.sum());
2820            }
2821        }
2822    }
2823
2824    mod random {
2825        use super::*;
2826        use super::{ComplexNative64StrictFinite, RealNative64StrictFinite};
2827        use crate::{RandomSampleFromF64, new_random_vec};
2828        use rand::{SeedableRng, distr::Uniform, rngs::StdRng};
2829
2830        /// Tests the random generation of a `RealValidated` value.
2831        /// It uses a seeded RNG to ensure deterministic results and checks
2832        /// if the generated value falls within the expected [0, 1) range.
2833        #[test]
2834        fn test_random_real_validated() {
2835            let seed = [42; 32];
2836            let mut rng = StdRng::from_seed(seed);
2837
2838            let random_real: RealNative64StrictFinite = rng.random();
2839
2840            // rng.random::<f64>() produces a value in [0, 1), so the converted value should be in the same range.
2841            assert_eq!(random_real, 0.23713468825474326);
2842
2843            // Check for determinism
2844            let mut rng2 = StdRng::from_seed(seed);
2845            let random_real2: RealNative64StrictFinite = rng2.random();
2846            assert_eq!(random_real, random_real2);
2847        }
2848
2849        /// Tests the random generation of a `ComplexValidated` value.
2850        /// It uses a seeded RNG for determinism and verifies that both the real
2851        /// and imaginary parts of the generated complex number are within the
2852        /// expected [0, 1) range.
2853        #[test]
2854        fn test_random_complex_validated() {
2855            let seed = [99; 32];
2856            let mut rng = StdRng::from_seed(seed);
2857
2858            let random_complex: ComplexNative64StrictFinite = rng.random();
2859
2860            // The real and imaginary parts are generated independently,
2861            // so both should be in the [0, 1) range.
2862            let real_part = random_complex.real_part();
2863            let imag_part = random_complex.imag_part();
2864
2865            assert_eq!(real_part, 0.9995546882627792);
2866            assert_eq!(imag_part, 0.08932180682540247);
2867
2868            // Check for determinism
2869            let mut rng2 = StdRng::from_seed(seed);
2870            let random_complex2: ComplexNative64StrictFinite = rng2.random();
2871            assert_eq!(random_complex, random_complex2);
2872        }
2873
2874        const SEED: [u8; 32] = [42; 32];
2875
2876        #[test]
2877        fn test_sample_real_validated() {
2878            let mut rng = StdRng::from_seed(SEED);
2879            let dist = Uniform::new(-10.0, 10.0).unwrap();
2880
2881            let val = RealNative64StrictFinite::sample_from(&dist, &mut rng);
2882            assert_eq!(val, -5.257306234905137);
2883
2884            // Check determinism
2885            let mut rng2 = StdRng::from_seed(SEED);
2886            let val2 = RealNative64StrictFinite::sample_from(&dist, &mut rng2);
2887            assert_eq!(val, val2);
2888        }
2889
2890        #[test]
2891        fn test_sample_complex_validated() {
2892            let mut rng = StdRng::from_seed(SEED);
2893            let dist = Uniform::new(-10.0, 10.0).unwrap();
2894
2895            let val = ComplexNative64StrictFinite::sample_from(&dist, &mut rng);
2896            assert_eq!(val.real_part(), -5.257306234905137);
2897            assert_eq!(val.imag_part(), 7.212119776268775);
2898
2899            // Check determinism
2900            let mut rng2 = StdRng::from_seed(SEED);
2901            let val2 = ComplexNative64StrictFinite::sample_from(&dist, &mut rng2);
2902            assert_eq!(val, val2);
2903        }
2904
2905        #[test]
2906        fn new_random_vec_real() {
2907            let mut rng = StdRng::from_seed(SEED);
2908            let dist = Uniform::new(-10.0, 10.0).unwrap();
2909            let vec: Vec<RealNative64StrictFinite> = new_random_vec(3, &dist, &mut rng);
2910            assert_eq!(vec.len(), 3);
2911            assert_eq!(vec[0], -5.257306234905137);
2912            assert_eq!(vec[1], 7.212119776268775);
2913            assert_eq!(vec[2], -4.666248990558111);
2914
2915            // Check determinism
2916            let mut rng2 = StdRng::from_seed(SEED);
2917            let vec2: Vec<RealNative64StrictFinite> = new_random_vec(3, &dist, &mut rng2);
2918            assert_eq!(vec, vec2);
2919        }
2920
2921        #[test]
2922        fn new_random_vec_complex() {
2923            let mut rng = StdRng::from_seed(SEED);
2924            let dist = Uniform::new(-10.0, 10.0).unwrap();
2925            let vec: Vec<ComplexNative64StrictFinite> = new_random_vec(3, &dist, &mut rng);
2926            assert_eq!(vec.len(), 3);
2927            assert_eq!(vec[0].real_part(), -5.257306234905137);
2928            assert_eq!(vec[0].imag_part(), 7.212119776268775);
2929            assert_eq!(vec[1].real_part(), -4.666248990558111);
2930            assert_eq!(vec[1].imag_part(), 9.66047141517383);
2931            assert_eq!(vec[2].real_part(), -9.04279551029691);
2932            assert_eq!(vec[2].imag_part(), -1.026624649331671);
2933
2934            // Check determinism
2935            let mut rng2 = StdRng::from_seed(SEED);
2936            let vec2: Vec<ComplexNative64StrictFinite> = new_random_vec(3, &dist, &mut rng2);
2937            assert_eq!(vec, vec2);
2938        }
2939    }
2940
2941    mod hash_map_key_usage {
2942        use crate::{
2943            backends::native64::validated::{
2944                ComplexNative64StrictFinite, RealNative64StrictFinite,
2945                RealNative64StrictFiniteInDebug,
2946            },
2947            functions::Sign,
2948        };
2949        use num::Complex;
2950        use std::collections::HashMap;
2951        use try_create::TryNew;
2952
2953        #[test]
2954        fn test_native64_as_hashmap_key() {
2955            let mut map = HashMap::new();
2956            let key1 = RealNative64StrictFinite::try_new(1.0).unwrap();
2957            let key2 = RealNative64StrictFinite::try_new(2.5).unwrap();
2958
2959            map.insert(key1, "one");
2960            map.insert(key2, "two_point_five");
2961
2962            assert_eq!(
2963                map.get(&RealNative64StrictFinite::try_new(1.0).unwrap()),
2964                Some(&"one")
2965            );
2966            assert_eq!(map.len(), 2);
2967
2968            // Overwrite an existing key
2969            let old_value = map.insert(key1, "new_one");
2970            assert_eq!(old_value, Some("one"));
2971            assert_eq!(map.get(&key1), Some(&"new_one"));
2972        }
2973
2974        #[test]
2975        fn test_native64_debug_as_hashmap_key() {
2976            let mut map = HashMap::new();
2977            let key1 = RealNative64StrictFiniteInDebug::try_new(1.0).unwrap();
2978            let key2 = RealNative64StrictFiniteInDebug::try_new(2.5).unwrap();
2979
2980            map.insert(key1, "one_debug");
2981            map.insert(key2, "two_point_five_debug");
2982
2983            assert_eq!(
2984                map.get(&RealNative64StrictFiniteInDebug::try_new(1.0).unwrap()),
2985                Some(&"one_debug")
2986            );
2987            assert_eq!(map.len(), 2);
2988
2989            // Overwrite an existing key
2990            let old_value = map.insert(key1, "new_one_debug");
2991            assert_eq!(old_value, Some("one_debug"));
2992            assert_eq!(map.get(&key1), Some(&"new_one_debug"));
2993        }
2994
2995        #[test]
2996        fn test_hashmap_basic_operations() {
2997            let mut map = HashMap::new();
2998            let key1 = RealNative64StrictFinite::try_new(1.0).unwrap();
2999            let key2 = RealNative64StrictFinite::try_new(2.5).unwrap();
3000            let key3 = RealNative64StrictFinite::try_new(1.0).unwrap(); // Same as key1
3001
3002            // Insert and verify
3003            assert_eq!(map.insert(key1, "one"), None);
3004            assert_eq!(map.insert(key2, "two_point_five"), None);
3005            assert_eq!(map.len(), 2);
3006
3007            // Test key equality (key3 should be equal to key1)
3008            assert_eq!(map.get(&key3), Some(&"one"));
3009
3010            // Overwrite existing key
3011            assert_eq!(map.insert(key3, "one_updated"), Some("one"));
3012            assert_eq!(map.len(), 2); // Size shouldn't change
3013        }
3014
3015        #[test]
3016        fn test_hashset_operations() {
3017            use std::collections::HashSet;
3018            let mut set = HashSet::new();
3019
3020            let val1 = RealNative64StrictFinite::try_new(1.0).unwrap();
3021            let val2 = RealNative64StrictFinite::try_new(2.0).unwrap();
3022            let val1_duplicate = RealNative64StrictFinite::try_new(1.0).unwrap();
3023
3024            assert!(set.insert(val1));
3025            assert!(set.insert(val2));
3026            assert!(!set.insert(val1_duplicate)); // Should return false (already exists)
3027
3028            assert_eq!(set.len(), 2);
3029            assert!(set.contains(&RealNative64StrictFinite::try_new(1.0).unwrap()));
3030        }
3031
3032        #[test]
3033        fn test_hash_consistency() {
3034            use std::collections::hash_map::DefaultHasher;
3035            use std::hash::{Hash, Hasher};
3036
3037            let val1 = RealNative64StrictFinite::try_new(1.234).unwrap();
3038            let val2 = RealNative64StrictFinite::try_new(1.234).unwrap();
3039
3040            // Equal values should have equal hashes
3041            let mut hasher1 = DefaultHasher::new();
3042            let mut hasher2 = DefaultHasher::new();
3043
3044            val1.hash(&mut hasher1);
3045            val2.hash(&mut hasher2);
3046
3047            assert_eq!(hasher1.finish(), hasher2.finish());
3048            assert_eq!(val1, val2); // Verify they're actually equal
3049        }
3050
3051        #[test]
3052        fn test_hash_signed_zero() {
3053            use std::collections::hash_map::DefaultHasher;
3054            use std::hash::{Hash, Hasher};
3055
3056            let val1 = RealNative64StrictFinite::try_new(0.0).unwrap();
3057            assert!(val1.kernel_is_sign_positive());
3058            let val2 = RealNative64StrictFinite::try_new(-0.0).unwrap();
3059            assert!(val2.kernel_is_sign_negative());
3060
3061            // Verify the underlying f64 values have different bit patterns
3062            assert_ne!(
3063                0.0f64.to_bits(),
3064                (-0.0f64).to_bits(),
3065                "Sanity check: +0.0 and -0.0 should have different bit patterns"
3066            );
3067
3068            assert_eq!(val1, val2); // Verify they're actually equal
3069
3070            // Equal values should have equal hashes
3071            let mut hasher1 = DefaultHasher::new();
3072            let mut hasher2 = DefaultHasher::new();
3073
3074            val1.hash(&mut hasher1);
3075            val2.hash(&mut hasher2);
3076
3077            assert_eq!(hasher1.finish(), hasher2.finish());
3078        }
3079
3080        #[test]
3081        fn test_complex_as_hashmap_key() {
3082            let mut map = HashMap::new();
3083            let key1 = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
3084            let key2 = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
3085
3086            map.insert(key1, "one_plus_two_i");
3087            map.insert(key2, "three_plus_four_i");
3088
3089            assert_eq!(
3090                map.get(&ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap()),
3091                Some(&"one_plus_two_i")
3092            );
3093            assert_eq!(map.len(), 2);
3094
3095            // Overwrite an existing key
3096            let old_value = map.insert(key1, "updated_complex");
3097            assert_eq!(old_value, Some("one_plus_two_i"));
3098            assert_eq!(map.get(&key1), Some(&"updated_complex"));
3099        }
3100
3101        #[test]
3102        fn test_complex_hash_consistency() {
3103            use std::collections::hash_map::DefaultHasher;
3104            use std::hash::{Hash, Hasher};
3105
3106            let val1 = ComplexNative64StrictFinite::try_new(Complex::new(1.234, 5.678)).unwrap();
3107            let val2 = ComplexNative64StrictFinite::try_new(Complex::new(1.234, 5.678)).unwrap();
3108
3109            // Equal values should have equal hashes
3110            let mut hasher1 = DefaultHasher::new();
3111            let mut hasher2 = DefaultHasher::new();
3112
3113            val1.hash(&mut hasher1);
3114            val2.hash(&mut hasher2);
3115
3116            assert_eq!(hasher1.finish(), hasher2.finish());
3117            assert_eq!(val1, val2); // Verify they're actually equal
3118        }
3119
3120        #[test]
3121        fn test_complex_hash_signed_zero() {
3122            use std::collections::hash_map::DefaultHasher;
3123            use std::hash::{Hash, Hasher};
3124
3125            // Test all combinations of signed zeros
3126            let val1 = ComplexNative64StrictFinite::try_new(Complex::new(0.0, 0.0)).unwrap();
3127            let val2 = ComplexNative64StrictFinite::try_new(Complex::new(-0.0, 0.0)).unwrap();
3128            let val3 = ComplexNative64StrictFinite::try_new(Complex::new(0.0, -0.0)).unwrap();
3129            let val4 = ComplexNative64StrictFinite::try_new(Complex::new(-0.0, -0.0)).unwrap();
3130
3131            // All should be equal
3132            assert_eq!(val1, val2);
3133            assert_eq!(val1, val3);
3134            assert_eq!(val1, val4);
3135
3136            // All should have the same hash
3137            let mut hasher1 = DefaultHasher::new();
3138            let mut hasher2 = DefaultHasher::new();
3139            let mut hasher3 = DefaultHasher::new();
3140            let mut hasher4 = DefaultHasher::new();
3141
3142            val1.hash(&mut hasher1);
3143            val2.hash(&mut hasher2);
3144            val3.hash(&mut hasher3);
3145            val4.hash(&mut hasher4);
3146
3147            let hash1 = hasher1.finish();
3148            let hash2 = hasher2.finish();
3149            let hash3 = hasher3.finish();
3150            let hash4 = hasher4.finish();
3151
3152            assert_eq!(hash1, hash2);
3153            assert_eq!(hash1, hash3);
3154            assert_eq!(hash1, hash4);
3155        }
3156
3157        #[test]
3158        fn test_complex_different_values_different_hashes() {
3159            use std::collections::hash_map::DefaultHasher;
3160            use std::hash::{Hash, Hasher};
3161
3162            let val1 = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
3163            let val2 = ComplexNative64StrictFinite::try_new(Complex::new(2.0, 1.0)).unwrap();
3164            let val3 = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.001)).unwrap();
3165
3166            // Different values should (very likely) have different hashes
3167            let mut hasher1 = DefaultHasher::new();
3168            let mut hasher2 = DefaultHasher::new();
3169            let mut hasher3 = DefaultHasher::new();
3170
3171            val1.hash(&mut hasher1);
3172            val2.hash(&mut hasher2);
3173            val3.hash(&mut hasher3);
3174
3175            let hash1 = hasher1.finish();
3176            let hash2 = hasher2.finish();
3177            let hash3 = hasher3.finish();
3178
3179            // These are not guaranteed but extremely likely
3180            assert_ne!(val1, val2);
3181            assert_ne!(val1, val3);
3182            assert_ne!(hash1, hash2);
3183            assert_ne!(hash1, hash3);
3184        }
3185
3186        #[test]
3187        fn test_complex_hashset_operations() {
3188            use std::collections::HashSet;
3189
3190            let mut set = HashSet::new();
3191
3192            let val1 = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
3193            let val2 = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
3194            let val1_duplicate =
3195                ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
3196
3197            assert!(set.insert(val1));
3198            assert!(set.insert(val2));
3199            assert!(!set.insert(val1_duplicate)); // Should return false (already exists)
3200
3201            assert_eq!(set.len(), 2);
3202            assert!(
3203                set.contains(
3204                    &ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap()
3205                )
3206            );
3207        }
3208    }
3209
3210    mod test_truncate_to_usize {
3211        use super::*;
3212        use crate::core::errors::ErrorsRawRealToInteger;
3213
3214        #[test]
3215        fn test_positive_integers() {
3216            // Whole numbers should convert exactly
3217            let value = RealNative64StrictFinite::try_new(42.0).unwrap();
3218            assert_eq!(value.truncate_to_usize().unwrap(), 42);
3219
3220            let value = RealNative64StrictFinite::try_new(1.0).unwrap();
3221            assert_eq!(value.truncate_to_usize().unwrap(), 1);
3222
3223            let value = RealNative64StrictFinite::try_new(100.0).unwrap();
3224            assert_eq!(value.truncate_to_usize().unwrap(), 100);
3225        }
3226
3227        #[test]
3228        fn test_positive_fractionals_truncate() {
3229            // Positive fractional parts should be discarded (truncated toward zero)
3230            let value = RealNative64StrictFinite::try_new(42.9).unwrap();
3231            assert_eq!(value.truncate_to_usize().unwrap(), 42);
3232
3233            let value = RealNative64StrictFinite::try_new(3.7).unwrap();
3234            assert_eq!(value.truncate_to_usize().unwrap(), 3);
3235
3236            let value = RealNative64StrictFinite::try_new(0.9).unwrap();
3237            assert_eq!(value.truncate_to_usize().unwrap(), 0);
3238
3239            let value = RealNative64StrictFinite::try_new(99.999).unwrap();
3240            assert_eq!(value.truncate_to_usize().unwrap(), 99);
3241        }
3242
3243        #[test]
3244        fn test_zero_cases() {
3245            // Zero should convert to 0
3246            let value = RealNative64StrictFinite::try_new(0.0).unwrap();
3247            assert_eq!(value.truncate_to_usize().unwrap(), 0);
3248
3249            // Positive fractional values less than 1 should truncate to 0
3250            let value = RealNative64StrictFinite::try_new(0.1).unwrap();
3251            assert_eq!(value.truncate_to_usize().unwrap(), 0);
3252
3253            let value = RealNative64StrictFinite::try_new(0.5).unwrap();
3254            assert_eq!(value.truncate_to_usize().unwrap(), 0);
3255        }
3256
3257        #[test]
3258        fn test_large_valid_values() {
3259            // Large but representable values within usize range
3260            let value = RealNative64StrictFinite::try_new(1_000_000.7).unwrap();
3261            assert_eq!(value.truncate_to_usize().unwrap(), 1_000_000);
3262
3263            let value = RealNative64StrictFinite::try_new(1_000_000_000.0).unwrap();
3264            assert_eq!(value.truncate_to_usize().unwrap(), 1_000_000_000);
3265
3266            // Test with a value close to but less than usize::MAX (on 64-bit systems)
3267            let max_safe = (usize::MAX as f64) - 2048.0; // Subtract to avoid precision issues
3268            let value = RealNative64StrictFinite::try_new(max_safe).unwrap();
3269            let result = value.truncate_to_usize().unwrap();
3270            assert!(result < usize::MAX);
3271        }
3272
3273        #[test]
3274        fn test_negative_values_error() {
3275            // Negative values should return OutOfRange error
3276            let value = RealNative64StrictFinite::try_new(-1.0).unwrap();
3277            let result = value.truncate_to_usize();
3278            assert!(matches!(
3279                result,
3280                Err(ErrorsRawRealToInteger::OutOfRange { .. })
3281            ));
3282
3283            let value = RealNative64StrictFinite::try_new(-10.5).unwrap();
3284            let result = value.truncate_to_usize();
3285            assert!(matches!(
3286                result,
3287                Err(ErrorsRawRealToInteger::OutOfRange { .. })
3288            ));
3289
3290            let value = RealNative64StrictFinite::try_new(-0.1).unwrap();
3291            let result = value.truncate_to_usize();
3292            assert!(matches!(result, Ok(0)));
3293
3294            let value = RealNative64StrictFinite::try_new(-1000.0).unwrap();
3295            let result = value.truncate_to_usize();
3296            assert!(matches!(
3297                result,
3298                Err(ErrorsRawRealToInteger::OutOfRange { .. })
3299            ));
3300        }
3301
3302        #[test]
3303        fn test_too_large_values_error() {
3304            // Values larger than usize::MAX should return OutOfRange error
3305            let too_large = (usize::MAX as f64) * 2.0;
3306            let value = RealNative64StrictFinite::try_new(too_large).unwrap();
3307            let result = value.truncate_to_usize();
3308            assert!(matches!(
3309                result,
3310                Err(ErrorsRawRealToInteger::OutOfRange { .. })
3311            ));
3312
3313            let value = RealNative64StrictFinite::try_new(1e20).unwrap();
3314            let result = value.truncate_to_usize();
3315            assert!(matches!(
3316                result,
3317                Err(ErrorsRawRealToInteger::OutOfRange { .. })
3318            ));
3319        }
3320
3321        #[test]
3322        fn test_edge_cases() {
3323            // Test values very close to boundaries
3324
3325            // Just above zero
3326            let value = RealNative64StrictFinite::try_new(f64::EPSILON).unwrap();
3327            assert_eq!(value.truncate_to_usize().unwrap(), 0);
3328
3329            // Just below 1
3330            let value = RealNative64StrictFinite::try_new(1.0 - f64::EPSILON).unwrap();
3331            assert_eq!(value.truncate_to_usize().unwrap(), 0);
3332
3333            // Just above 1
3334            let value = RealNative64StrictFinite::try_new(1.0 + f64::EPSILON).unwrap();
3335            assert_eq!(value.truncate_to_usize().unwrap(), 1);
3336        }
3337
3338        #[test]
3339        fn test_truncation_behavior() {
3340            // Verify truncation (toward zero) behavior vs other rounding modes
3341            let test_cases = [
3342                (2.1, 2),
3343                (2.5, 2), // truncate, not round
3344                (2.9, 2),
3345                (3.0, 3),
3346                (3.1, 3),
3347                (99.999, 99),
3348            ];
3349
3350            for (input, expected) in test_cases {
3351                let value = RealNative64StrictFinite::try_new(input)
3352                    .unwrap()
3353                    .truncate_to_usize()
3354                    .unwrap();
3355                assert_eq!(
3356                    value, expected,
3357                    "Failed for input {}: expected {}, got {:?}",
3358                    input, expected, value
3359                );
3360            }
3361        }
3362
3363        #[test]
3364        fn test_error_details() {
3365            // Test that error variants contain expected information
3366
3367            // OutOfRange error for negative value
3368            let value = RealNative64StrictFinite::try_new(-5.0).unwrap();
3369            if let Err(ErrorsRawRealToInteger::OutOfRange {
3370                value: err_val,
3371                min,
3372                max,
3373                ..
3374            }) = value.truncate_to_usize()
3375            {
3376                assert_eq!(err_val, -5.0);
3377                assert_eq!(min, usize::MIN);
3378                assert_eq!(max, usize::MAX);
3379            } else {
3380                panic!("Expected OutOfRange error for negative value");
3381            }
3382
3383            // OutOfRange error for too large value
3384            let large_value = 1e20;
3385            let value = RealNative64StrictFinite::try_new(large_value).unwrap();
3386            if let Err(ErrorsRawRealToInteger::OutOfRange {
3387                value: err_val,
3388                min,
3389                max,
3390                ..
3391            }) = value.truncate_to_usize()
3392            {
3393                assert_eq!(err_val, large_value);
3394                assert_eq!(min, usize::MIN);
3395                assert_eq!(max, usize::MAX);
3396            } else {
3397                panic!("Expected OutOfRange error for large value");
3398            }
3399        }
3400
3401        #[test]
3402        fn test_practical_usage_scenario() {
3403            // Test a realistic usage scenario: creating a vector with calculated size
3404            fn create_vector_with_calculated_size<T: Default + Clone>(
3405                size_float: RealNative64StrictFinite,
3406            ) -> Result<Vec<T>, Box<dyn std::error::Error>> {
3407                let size = size_float.truncate_to_usize()?;
3408                Ok(vec![T::default(); size])
3409            }
3410
3411            // Valid case
3412            let calculated_size = RealNative64StrictFinite::try_new(10.7).unwrap();
3413            let vec: Vec<i32> = create_vector_with_calculated_size(calculated_size).unwrap();
3414            assert_eq!(vec.len(), 10); // Truncated from 10.7
3415
3416            // Error case - negative size
3417            let negative_size = RealNative64StrictFinite::try_new(-5.0).unwrap();
3418            let result: Result<Vec<i32>, _> = create_vector_with_calculated_size(negative_size);
3419            assert!(result.is_err());
3420
3421            // Error case - too large size
3422            let huge_size = RealNative64StrictFinite::try_new(1e20).unwrap();
3423            let result: Result<Vec<i32>, _> = create_vector_with_calculated_size(huge_size);
3424            assert!(result.is_err());
3425        }
3426
3427        #[test]
3428        fn test_consistency_with_f64_behavior() {
3429            // Verify that our implementation behaves consistently with direct f64 operations
3430            let test_values = [0.0, 1.0, 2.5, 42.9, 100.0, 0.1, 0.9];
3431
3432            for &val in &test_values {
3433                let validated = RealNative64StrictFinite::try_new(val).unwrap();
3434                let result = validated.truncate_to_usize().unwrap();
3435
3436                // Compare with direct f64 truncation
3437                let expected = val.trunc() as usize;
3438                assert_eq!(result, expected, "Mismatch for value {}", val);
3439            }
3440        }
3441    }
3442
3443    mod bytemuck_conversions {
3444        use super::*;
3445        use bytemuck::checked::{CheckedCastError, try_from_bytes};
3446
3447        mod real_strict_finite {
3448            use super::*;
3449
3450            #[test]
3451            fn valid_value_from_bytes() {
3452                let value = 42.0_f64;
3453                let bytes = value.to_ne_bytes();
3454
3455                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3456                    try_from_bytes(&bytes);
3457                assert!(result.is_ok());
3458                assert_eq!(*result.unwrap().as_ref(), 42.0);
3459            }
3460
3461            #[test]
3462            fn valid_value_try_cast() {
3463                let value = 42.0_f64;
3464                let bytes = value.to_ne_bytes();
3465                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3466                    try_from_bytes(&bytes);
3467                assert!(result.is_ok());
3468                assert_eq!(*result.unwrap().as_ref(), 42.0);
3469            }
3470
3471            #[test]
3472            fn zero_from_bytes() {
3473                let value = 0.0_f64;
3474                let bytes = value.to_ne_bytes();
3475
3476                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3477                    try_from_bytes(&bytes);
3478                assert!(result.is_ok());
3479                assert_eq!(*result.unwrap().as_ref(), 0.0);
3480            }
3481
3482            #[test]
3483            fn negative_zero_from_bytes() {
3484                let value = -0.0_f64;
3485                let bytes = value.to_ne_bytes();
3486
3487                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3488                    try_from_bytes(&bytes);
3489                assert!(result.is_ok());
3490                assert_eq!(*result.unwrap().as_ref(), -0.0);
3491            }
3492
3493            #[test]
3494            fn max_value_from_bytes() {
3495                let value = f64::MAX;
3496                let bytes = value.to_ne_bytes();
3497
3498                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3499                    try_from_bytes(&bytes);
3500                assert!(result.is_ok());
3501                assert_eq!(*result.unwrap().as_ref(), f64::MAX);
3502            }
3503
3504            #[test]
3505            fn min_value_from_bytes() {
3506                let value = f64::MIN;
3507                let bytes = value.to_ne_bytes();
3508
3509                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3510                    try_from_bytes(&bytes);
3511                assert!(result.is_ok());
3512                assert_eq!(*result.unwrap().as_ref(), f64::MIN);
3513            }
3514
3515            #[test]
3516            fn nan_from_bytes_fails() {
3517                let value = f64::NAN;
3518                let bytes = value.to_ne_bytes();
3519
3520                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3521                    try_from_bytes(&bytes);
3522                assert!(result.is_err());
3523                assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
3524            }
3525
3526            #[test]
3527            fn nan_try_cast_fails() {
3528                let value = f64::NAN;
3529                let bytes = value.to_ne_bytes();
3530                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3531                    try_from_bytes(&bytes);
3532                assert!(result.is_err());
3533                assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
3534            }
3535
3536            #[test]
3537            fn infinity_from_bytes_fails() {
3538                let value = f64::INFINITY;
3539                let bytes = value.to_ne_bytes();
3540
3541                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3542                    try_from_bytes(&bytes);
3543                assert!(result.is_err());
3544                assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
3545            }
3546
3547            #[test]
3548            fn neg_infinity_from_bytes_fails() {
3549                let value = f64::NEG_INFINITY;
3550                let bytes = value.to_ne_bytes();
3551
3552                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3553                    try_from_bytes(&bytes);
3554                assert!(result.is_err());
3555                assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
3556            }
3557
3558            #[test]
3559            fn subnormal_from_bytes_fails() {
3560                let value = f64::MIN_POSITIVE / 2.0; // subnormal
3561                let bytes = value.to_ne_bytes();
3562
3563                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3564                    try_from_bytes(&bytes);
3565                assert!(result.is_err());
3566                assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
3567            }
3568
3569            #[test]
3570            fn round_trip_conversion() {
3571                let original = RealNative64StrictFinite::try_new(123.456).unwrap();
3572                let as_f64 = *original.as_ref();
3573                let bytes = as_f64.to_ne_bytes();
3574
3575                let from_bytes: &RealNative64StrictFinite = try_from_bytes(&bytes).unwrap();
3576                assert_eq!(original, *from_bytes);
3577            }
3578
3579            #[test]
3580            fn vec_conversion() {
3581                let values = vec![
3582                    RealNative64StrictFinite::try_new(1.0).unwrap(),
3583                    RealNative64StrictFinite::try_new(2.0).unwrap(),
3584                    RealNative64StrictFinite::try_new(3.0).unwrap(),
3585                    RealNative64StrictFinite::try_new(4.0).unwrap(),
3586                ];
3587
3588                // Cast to bytes
3589                let bytes = bytemuck::cast_slice::<RealNative64StrictFinite, u8>(&values);
3590
3591                // Try to cast back - should succeed
3592                let result: Result<&[RealNative64StrictFinite], CheckedCastError> =
3593                    bytemuck::checked::try_cast_slice(bytes);
3594                assert!(result.is_ok());
3595
3596                let validated_slice = result.unwrap();
3597                assert_eq!(validated_slice.len(), 4);
3598                assert_eq!(*validated_slice[0].as_ref(), 1.0);
3599                assert_eq!(*validated_slice[3].as_ref(), 4.0);
3600            }
3601
3602            #[test]
3603            fn direct_f64_slice_with_invalid_values() {
3604                // Create bytes representing f64 values, some invalid
3605                let mut bytes = Vec::new();
3606                bytes.extend_from_slice(&1.0_f64.to_ne_bytes());
3607                bytes.extend_from_slice(&f64::NAN.to_ne_bytes());
3608                bytes.extend_from_slice(&3.0_f64.to_ne_bytes());
3609
3610                // Should fail because of NaN
3611                let result: Result<&[RealNative64StrictFinite], CheckedCastError> =
3612                    bytemuck::checked::try_cast_slice(&bytes);
3613                assert!(result.is_err());
3614            }
3615        }
3616
3617        mod vec_conversions {
3618            use super::*;
3619            use try_create::TryNew;
3620
3621            #[test]
3622            fn vec_f64_to_validated_all_valid() {
3623                // Create a Vec<f64> with all valid values
3624                let f64_vec = [1.0, 2.5, -3.7, 0.0, 42.0];
3625
3626                // Convert to Vec<RealNative64StrictFinite>
3627                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3628                    .iter()
3629                    .map(|&x| RealNative64StrictFinite::try_new(x))
3630                    .collect();
3631
3632                assert!(validated_vec.is_ok());
3633                let validated_vec = validated_vec.unwrap();
3634
3635                // Verify length
3636                assert_eq!(validated_vec.len(), 5);
3637
3638                // Verify values
3639                assert_eq!(*validated_vec[0].as_ref(), 1.0);
3640                assert_eq!(*validated_vec[1].as_ref(), 2.5);
3641                assert_eq!(*validated_vec[2].as_ref(), -3.7);
3642                assert_eq!(*validated_vec[3].as_ref(), 0.0);
3643                assert_eq!(*validated_vec[4].as_ref(), 42.0);
3644            }
3645
3646            #[test]
3647            fn vec_f64_to_validated_with_nan() {
3648                // Create a Vec<f64> with a NaN value
3649                let f64_vec = [1.0, 2.5, f64::NAN, 0.0, 42.0];
3650
3651                // Conversion should fail on the NaN
3652                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3653                    .iter()
3654                    .map(|&x| RealNative64StrictFinite::try_new(x))
3655                    .collect();
3656
3657                assert!(validated_vec.is_err());
3658            }
3659
3660            #[test]
3661            fn vec_f64_to_validated_with_infinity() {
3662                // Create a Vec<f64> with an infinity value
3663                let f64_vec = [1.0, f64::INFINITY, 3.0];
3664
3665                // Conversion should fail on the infinity
3666                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3667                    .iter()
3668                    .map(|&x| RealNative64StrictFinite::try_new(x))
3669                    .collect();
3670
3671                assert!(validated_vec.is_err());
3672            }
3673
3674            #[test]
3675            fn vec_f64_to_validated_with_subnormal() {
3676                // Create a Vec<f64> with a subnormal value
3677                let subnormal = f64::MIN_POSITIVE / 2.0;
3678                let f64_vec = [1.0, subnormal, 3.0];
3679
3680                // Conversion should fail on the subnormal
3681                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3682                    .iter()
3683                    .map(|&x| RealNative64StrictFinite::try_new(x))
3684                    .collect();
3685
3686                assert!(validated_vec.is_err());
3687            }
3688
3689            #[test]
3690            fn vec_validated_to_f64() {
3691                // Create a Vec<RealNative64StrictFinite>
3692                let validated_vec = [
3693                    RealNative64StrictFinite::try_new(1.0).unwrap(),
3694                    RealNative64StrictFinite::try_new(2.5).unwrap(),
3695                    RealNative64StrictFinite::try_new(-3.7).unwrap(),
3696                    RealNative64StrictFinite::try_new(0.0).unwrap(),
3697                    RealNative64StrictFinite::try_new(42.0).unwrap(),
3698                ];
3699
3700                // Convert to Vec<f64>
3701                let f64_vec: Vec<f64> = validated_vec.iter().map(|x| *x.as_ref()).collect();
3702
3703                // Verify length
3704                assert_eq!(f64_vec.len(), 5);
3705
3706                // Verify values
3707                assert_eq!(f64_vec[0], 1.0);
3708                assert_eq!(f64_vec[1], 2.5);
3709                assert_eq!(f64_vec[2], -3.7);
3710                assert_eq!(f64_vec[3], 0.0);
3711                assert_eq!(f64_vec[4], 42.0);
3712            }
3713
3714            #[test]
3715            fn vec_round_trip_conversion() {
3716                // Start with Vec<f64>
3717                let original_f64 = vec![1.0, 2.5, -3.7, 0.0, 42.0, -999.123];
3718
3719                // Convert to Vec<RealNative64StrictFinite>
3720                let validated_vec: Vec<RealNative64StrictFinite> = original_f64
3721                    .iter()
3722                    .map(|&x| RealNative64StrictFinite::try_new(x).unwrap())
3723                    .collect();
3724
3725                // Convert back to Vec<f64>
3726                let final_f64: Vec<f64> = validated_vec.iter().map(|x| *x.as_ref()).collect();
3727
3728                let slice_f64 =
3729                    bytemuck::cast_slice::<RealNative64StrictFinite, f64>(&validated_vec);
3730                assert_eq!(slice_f64, &original_f64);
3731
3732                // Should be identical
3733                assert_eq!(original_f64, final_f64);
3734            }
3735
3736            #[test]
3737            fn vec_empty() {
3738                // Empty Vec<f64>
3739                let f64_vec: Vec<f64> = vec![];
3740
3741                // Convert to Vec<RealNative64StrictFinite>
3742                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3743                    .iter()
3744                    .map(|&x| RealNative64StrictFinite::try_new(x))
3745                    .collect();
3746
3747                assert!(validated_vec.is_ok());
3748                assert_eq!(validated_vec.unwrap().len(), 0);
3749            }
3750
3751            #[test]
3752            fn vec_large_values() {
3753                // Test with extreme but valid values
3754                let f64_vec = vec![f64::MAX, f64::MIN, f64::MIN_POSITIVE, -f64::MIN_POSITIVE];
3755
3756                // All should be valid
3757                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3758                    .iter()
3759                    .map(|&x| RealNative64StrictFinite::try_new(x))
3760                    .collect();
3761
3762                assert!(validated_vec.is_ok());
3763                let validated_vec = validated_vec.unwrap();
3764
3765                // Verify round-trip
3766                let f64_back: Vec<f64> = validated_vec.iter().map(|x| *x.as_ref()).collect();
3767
3768                assert_eq!(f64_vec, f64_back);
3769            }
3770
3771            #[test]
3772            fn vec_with_zeros() {
3773                // Test with positive and negative zeros
3774                let f64_vec = [0.0, -0.0, 1.0, -1.0];
3775
3776                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3777                    .iter()
3778                    .map(|&x| RealNative64StrictFinite::try_new(x))
3779                    .collect();
3780
3781                assert!(validated_vec.is_ok());
3782                let validated_vec = validated_vec.unwrap();
3783
3784                assert_eq!(*validated_vec[0].as_ref(), 0.0);
3785                assert_eq!(*validated_vec[1].as_ref(), -0.0);
3786            }
3787
3788            #[test]
3789            fn vec_using_from_iter() {
3790                // Test using from_iter for a more idiomatic approach
3791                let f64_vec = [1.0, 2.0, 3.0, 4.0, 5.0];
3792
3793                // Using from_iter with filter_map to handle errors
3794                let validated_vec: Vec<RealNative64StrictFinite> = f64_vec
3795                    .iter()
3796                    .filter_map(|&x| RealNative64StrictFinite::try_new(x).ok())
3797                    .collect();
3798
3799                assert_eq!(validated_vec.len(), 5);
3800            }
3801
3802            #[test]
3803            fn vec_conversion_preserves_order() {
3804                // Test that order is preserved through conversion
3805                let f64_vec: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
3806
3807                let validated_vec: Vec<RealNative64StrictFinite> = f64_vec
3808                    .iter()
3809                    .map(|&x| RealNative64StrictFinite::try_new(x).unwrap())
3810                    .collect();
3811
3812                // Convert back and verify order
3813                for (i, val) in validated_vec.iter().enumerate() {
3814                    assert_eq!(*val.as_ref(), i as f64 * 0.1);
3815                }
3816            }
3817
3818            #[test]
3819            fn vec_partial_conversion_with_find() {
3820                // Test finding the first invalid value
3821                let f64_vec = [1.0, 2.0, f64::NAN, 4.0, 5.0];
3822
3823                // Find which index has the invalid value
3824                let (invalid_idx, _) = f64_vec
3825                    .iter()
3826                    .enumerate()
3827                    .find(|(_, x)| RealNative64StrictFinite::try_new(**x).is_err())
3828                    .expect("Should find invalid value");
3829
3830                assert_eq!(invalid_idx, 2);
3831            }
3832
3833            #[test]
3834            fn vec_consume_and_convert() {
3835                // Test consuming the original vector
3836                let f64_vec = vec![1.0, 2.0, 3.0];
3837
3838                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3839                    .into_iter()
3840                    .map(RealNative64StrictFinite::try_new)
3841                    .collect();
3842
3843                assert!(validated_vec.is_ok());
3844                assert_eq!(validated_vec.unwrap().len(), 3);
3845
3846                // f64_vec is moved and cannot be used here
3847            }
3848
3849            #[test]
3850            fn vec_validated_to_f64_with_try_cast_vec() {
3851                use bytemuck::allocation::try_cast_vec;
3852
3853                // Create a Vec<RealNative64StrictFinite>
3854                let validated_vec: Vec<RealNative64StrictFinite> = vec![
3855                    RealNative64StrictFinite::try_new(1.0).unwrap(),
3856                    RealNative64StrictFinite::try_new(2.5).unwrap(),
3857                    RealNative64StrictFinite::try_new(-3.7).unwrap(),
3858                    RealNative64StrictFinite::try_new(0.0).unwrap(),
3859                    RealNative64StrictFinite::try_new(42.0).unwrap(),
3860                ];
3861
3862                // Try to cast Vec<RealNative64StrictFinite> -> Vec<f64> using bytemuck
3863                let f64_vec_result: Result<Vec<f64>, _> = try_cast_vec(validated_vec);
3864
3865                // This should work because:
3866                // - RealNative64StrictFinite implements NoUninit āœ“
3867                // - f64 implements AnyBitPattern āœ“
3868                // - Both have same size and alignment (repr(transparent)) āœ“
3869                assert!(
3870                    f64_vec_result.is_ok(),
3871                    "try_cast_vec should work for Vec<RealNative64StrictFinite> -> Vec<f64>"
3872                );
3873
3874                let f64_vec = f64_vec_result.unwrap();
3875                assert_eq!(f64_vec.len(), 5);
3876                assert_eq!(f64_vec[0], 1.0);
3877                assert_eq!(f64_vec[1], 2.5);
3878                assert_eq!(f64_vec[2], -3.7);
3879                assert_eq!(f64_vec[3], 0.0);
3880                assert_eq!(f64_vec[4], 42.0);
3881            }
3882
3883            #[test]
3884            fn vec_f64_to_validated_try_cast_vec_fails() {
3885                // Create a Vec<f64>
3886                let f64_vec = [1.0, 2.5, -3.7, 0.0, 42.0];
3887
3888                // Try to cast Vec<f64> -> Vec<RealNative64StrictFinite> using bytemuck
3889                // This SHOULD NOT compile because RealNative64StrictFinite does not implement AnyBitPattern
3890                // (it only implements CheckedBitPattern, which requires validation)
3891
3892                // Uncomment the following line to verify it doesn't compile:
3893                // let validated_result: Result<Vec<RealNative64StrictFinite>, _> = try_cast_vec(f64_vec);
3894
3895                // Instead, we must use the iterator approach with validation:
3896                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3897                    .iter()
3898                    .map(|&x| RealNative64StrictFinite::try_new(x))
3899                    .collect();
3900
3901                assert!(validated_vec.is_ok());
3902                assert_eq!(validated_vec.unwrap().len(), 5);
3903            }
3904        }
3905
3906        mod real_strict_finite_in_debug {
3907            use super::*;
3908
3909            #[test]
3910            fn valid_value_from_bytes() {
3911                let value = 42.0_f64;
3912                let bytes = value.to_ne_bytes();
3913
3914                let result: Result<&RealNative64StrictFiniteInDebug, CheckedCastError> =
3915                    try_from_bytes(&bytes);
3916                assert!(result.is_ok());
3917                assert_eq!(*result.unwrap().as_ref(), 42.0);
3918            }
3919
3920            #[test]
3921            fn nan_from_bytes() {
3922                let value = f64::NAN;
3923                let bytes = value.to_ne_bytes();
3924
3925                let result: Result<&RealNative64StrictFiniteInDebug, CheckedCastError> =
3926                    try_from_bytes(&bytes);
3927
3928                #[cfg(debug_assertions)]
3929                {
3930                    // In debug mode, should fail
3931                    assert!(result.is_err());
3932                    assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
3933                }
3934
3935                #[cfg(not(debug_assertions))]
3936                {
3937                    // In release mode, validation is skipped
3938                    // This test documents the behavior but is NOT safe
3939                    // Don't use this in production without guarantees!
3940                    assert!(result.is_ok());
3941                }
3942            }
3943
3944            #[test]
3945            fn infinity_from_bytes() {
3946                let value = f64::INFINITY;
3947                let bytes = value.to_ne_bytes();
3948
3949                let result: Result<&RealNative64StrictFiniteInDebug, CheckedCastError> =
3950                    try_from_bytes(&bytes);
3951
3952                #[cfg(debug_assertions)]
3953                {
3954                    assert!(result.is_err());
3955                }
3956
3957                #[cfg(not(debug_assertions))]
3958                {
3959                    assert!(result.is_ok());
3960                }
3961            }
3962
3963            #[test]
3964            fn round_trip_with_valid_value() {
3965                let original = RealNative64StrictFiniteInDebug::try_new(123.456).unwrap();
3966                let as_f64 = *original.as_ref();
3967                let bytes = as_f64.to_ne_bytes();
3968
3969                let from_bytes: &RealNative64StrictFiniteInDebug = try_from_bytes(&bytes).unwrap();
3970                assert_eq!(original, *from_bytes);
3971            }
3972        }
3973
3974        #[test]
3975        fn alignment_check() {
3976            use std::mem;
3977
3978            // Verify that RealNative64StrictFinite has the same alignment as f64
3979            assert_eq!(
3980                mem::align_of::<RealNative64StrictFinite>(),
3981                mem::align_of::<f64>()
3982            );
3983
3984            // Verify size
3985            assert_eq!(
3986                mem::size_of::<RealNative64StrictFinite>(),
3987                mem::size_of::<f64>()
3988            );
3989        }
3990    }
3991
3992    /// Tests for the conditional `Copy` implementation.
3993    ///
3994    /// These tests verify that `RealValidated` and `ComplexValidated` implement `Copy`
3995    /// when their underlying raw types implement `Copy` (e.g., `f64`, `Complex<f64>`).
3996    mod copy_trait_tests {
3997        use super::*;
3998
3999        mod real_copy {
4000            use super::*;
4001
4002            #[test]
4003            fn real_is_copy() {
4004                // Verify RealNative64StrictFinite is Copy
4005                fn assert_copy<T: Copy>() {}
4006                assert_copy::<RealNative64StrictFinite>();
4007                assert_copy::<RealNative64StrictFiniteInDebug>();
4008            }
4009
4010            #[test]
4011            fn real_copy_semantics() {
4012                let x = RealNative64StrictFinite::try_new(3.).unwrap();
4013                let y = x; // Copy, not move
4014                let z = x; // x is still valid because it was copied
4015                assert_eq!(x, y);
4016                assert_eq!(x, z);
4017            }
4018
4019            #[test]
4020            fn real_copy_in_function_call() {
4021                fn takes_by_value(val: RealNative64StrictFinite) -> f64 {
4022                    *val.as_ref()
4023                }
4024
4025                let x = RealNative64StrictFinite::try_new(42.0).unwrap();
4026                let result1 = takes_by_value(x);
4027                let result2 = takes_by_value(x); // x is still valid after first call
4028                assert_eq!(result1, 42.0);
4029                assert_eq!(result2, 42.0);
4030            }
4031
4032            #[test]
4033            fn real_copy_in_loop() {
4034                let x = RealNative64StrictFinite::try_new(1.0).unwrap();
4035                let mut sum = RealNative64StrictFinite::zero();
4036
4037                for _ in 0..5 {
4038                    sum += x; // x is copied each iteration
4039                }
4040
4041                assert_eq!(*sum.as_ref(), 5.0);
4042                assert_eq!(*x.as_ref(), 1.0); // x unchanged
4043            }
4044
4045            #[test]
4046            fn real_copy_with_arithmetic() {
4047                let a = RealNative64StrictFinite::try_new(2.0).unwrap();
4048                let b = RealNative64StrictFinite::try_new(3.0).unwrap();
4049
4050                // All of these use copies of a and b
4051                let sum = a + b;
4052                let diff = a - b;
4053                let prod = a * b;
4054                let quot = a / b;
4055
4056                // a and b still valid
4057                assert_eq!(*a.as_ref(), 2.0);
4058                assert_eq!(*b.as_ref(), 3.0);
4059                assert_eq!(*sum.as_ref(), 5.0);
4060                assert_eq!(*diff.as_ref(), -1.0);
4061                assert_eq!(*prod.as_ref(), 6.0);
4062                assert!((quot.as_ref() - 2.0 / 3.0).abs() < 1e-10);
4063            }
4064        }
4065
4066        mod complex_copy {
4067            use super::*;
4068
4069            #[test]
4070            fn complex_is_copy() {
4071                // Verify ComplexNative64StrictFinite is Copy
4072                fn assert_copy<T: Copy>() {}
4073                assert_copy::<ComplexNative64StrictFinite>();
4074                assert_copy::<ComplexNative64StrictFiniteInDebug>();
4075            }
4076
4077            #[test]
4078            fn complex_copy_semantics() {
4079                let z = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
4080                let w = z; // Copy, not move
4081                let v = z; // z is still valid because it was copied
4082                assert_eq!(z, w);
4083                assert_eq!(z, v);
4084            }
4085
4086            #[test]
4087            fn complex_copy_in_function_call() {
4088                fn takes_by_value(val: ComplexNative64StrictFinite) -> Complex<f64> {
4089                    val.into_inner()
4090                }
4091
4092                let z = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
4093                let result1 = takes_by_value(z);
4094                let result2 = takes_by_value(z); // z is still valid after first call
4095                assert_eq!(result1, Complex::new(3.0, 4.0));
4096                assert_eq!(result2, Complex::new(3.0, 4.0));
4097            }
4098
4099            #[test]
4100            fn complex_copy_with_arithmetic() {
4101                let a = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
4102                let b = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
4103
4104                // All of these use copies of a and b
4105                let sum = a + b;
4106                let diff = a - b;
4107                let prod = a * b;
4108
4109                // a and b still valid
4110                assert_eq!(a.into_inner(), Complex::new(1.0, 2.0));
4111                assert_eq!(b.into_inner(), Complex::new(3.0, 4.0));
4112                assert_eq!(sum.into_inner(), Complex::new(4.0, 6.0));
4113                assert_eq!(diff.into_inner(), Complex::new(-2.0, -2.0));
4114                // (1+2i)(3+4i) = 3 + 4i + 6i + 8i² = 3 + 10i - 8 = -5 + 10i
4115                assert_eq!(prod.into_inner(), Complex::new(-5.0, 10.0));
4116            }
4117
4118            #[test]
4119            fn complex_copy_in_loop() {
4120                let z = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 1.0)).unwrap();
4121                let mut sum = ComplexNative64StrictFinite::zero();
4122
4123                for _ in 0..3 {
4124                    sum += z; // z is copied each iteration
4125                }
4126
4127                assert_eq!(sum.into_inner(), Complex::new(3.0, 3.0));
4128                assert_eq!(z.into_inner(), Complex::new(1.0, 1.0)); // z unchanged
4129            }
4130        }
4131
4132        mod mixed_copy {
4133            use super::*;
4134
4135            #[test]
4136            fn real_and_complex_copy_in_expression() {
4137                let r = RealNative64StrictFinite::try_new(2.0).unwrap();
4138                let z = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 1.0)).unwrap();
4139
4140                // Complex * Real uses copies
4141                let result1 = z * r;
4142                let result2 = z * r;
4143
4144                // Both still valid
4145                assert_eq!(*r.as_ref(), 2.0);
4146                assert_eq!(z.into_inner(), Complex::new(1.0, 1.0));
4147                assert_eq!(result1.into_inner(), Complex::new(2.0, 2.0));
4148                assert_eq!(result2.into_inner(), Complex::new(2.0, 2.0));
4149            }
4150        }
4151    }
4152}