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