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