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