num_valid/backends/native64/
validated.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! # Validated Native 64-bit Kernel Types
4//!
5//! This module provides convenient, pre-configured type aliases for the native `f64`
6//! kernel. These types wrap [`f64`] and [`num::Complex<f64>`] in the [`RealValidated`](crate::core::types::RealValidated)
7//! and [`ComplexValidated`](crate::core::types::ComplexValidated) structs, bundling them with specific *validation policies*.
8//!
9//! These type aliases are the primary entry point for users who want to work with
10//! validated numbers that provide compile-time guarantees about their properties (e.g., finiteness).
11//!
12//! ## Policies
13//!
14//! Two main policies are provided:
15//!
16//! - **`Native64StrictFinite`:** Enforces that all values are finite (not `NaN` or `Infinity`)
17//!   in all build modes. Operations on types using this policy will panic on validation
18//!   failure in debug builds and return a `Result` in release builds. This is the safest and
19//!   most common choice.
20//!
21//! - **`Native64StrictFiniteInDebug`:** Also enforces finiteness, but validation checks that
22//!   would panic are **only performed in debug builds**. In release builds, these checks are
23//!   skipped for performance, and operations assume the inputs are valid. This is for
24//!   performance-critical code where the developer can guarantee the validity of inputs.
25//!
26//! ## Example
27//!
28//! ```rust
29//! use num_valid::{RealNative64StrictFinite, functions::Sqrt};
30//! use try_create::TryNew;
31//!
32//! // Creation succeeds because 4.0 is a valid, finite number.
33//! let x = RealNative64StrictFinite::try_new(4.0).unwrap();
34//!
35//! // Creation fails for non-finite numbers.
36//! assert!(RealNative64StrictFinite::try_new(f64::NAN).is_err());
37//!
38//! // Mathematical operations are available through traits.
39//! let sqrt_x = x.sqrt();
40//! assert_eq!(*sqrt_x.as_ref(), 2.0);
41//! ```
42//!
43//! ## Zero-Copy Conversions with Bytemuck
44//!
45//! The validated types in this module implement [`bytemuck::CheckedBitPattern`] and
46//! [`bytemuck::NoUninit`], enabling safe, zero-copy conversions between `f64` byte
47//! representations and validated types. This is particularly useful for:
48//!
49//! - Interoperability with binary data formats and serialization
50//! - Performance-critical code working with byte arrays
51//! - Loading validated numbers from external data sources
52//!
53//! The conversion automatically validates the bit pattern, rejecting invalid values
54//! (NaN, Infinity, subnormal numbers) while maintaining zero-cost performance for
55//! valid inputs:
56//!
57//! ```rust
58//! use num_valid::RealNative64StrictFinite;
59//! use bytemuck::checked::try_from_bytes;
60//!
61//! // Valid conversion
62//! let value = 42.0_f64;
63//! let bytes = value.to_ne_bytes();
64//! let validated: &RealNative64StrictFinite = try_from_bytes(&bytes).unwrap();
65//! assert_eq!(*validated.as_ref(), 42.0);
66//!
67//! // Invalid values are rejected
68//! let nan_bytes = f64::NAN.to_ne_bytes();
69//! assert!(try_from_bytes::<RealNative64StrictFinite>(&nan_bytes).is_err());
70//! ```
71//!
72//! For comprehensive examples of valid conversions, error handling, and slice operations,
73//! see the test module in the source code.
74
75use crate::kernels::{
76    ComplexValidated, NumKernelStrictFinite, NumKernelStrictFiniteInDebug, RealValidated,
77};
78
79//------------------------------------------------------------------------------------------------------------
80/// A kernel policy that enforces strict finiteness for `f64` and `Complex<f64>` values.
81///
82/// This is a type alias for [`NumKernelStrictFinite<f64, 53>`].
83///
84/// It ensures that all validated values are finite (not `NaN` or `Infinity`).
85/// In debug builds, operations that fail validation will panic. In release builds, they
86/// will return an error. This policy is used by [`RealNative64StrictFinite`] and
87/// [`ComplexNative64StrictFinite`].
88pub type Native64StrictFinite = NumKernelStrictFinite<f64, 53>;
89//------------------------------------------------------------------------------------------------------------
90
91//------------------------------------------------------------------------------------------------------------
92/// A kernel policy that enforces strict finiteness for `f64` values **only in debug builds**.
93///
94/// This is a type alias for [`NumKernelStrictFiniteInDebug<f64, 53>`].
95///
96/// This policy is designed for performance-critical applications. In debug builds, it
97/// behaves identically to [`Native64StrictFinite`], panicking on validation failures.
98/// In **release builds**, these validation checks are **disabled**, and operations proceed
99/// assuming the inputs are valid. Use this policy with caution when you can guarantee
100/// the integrity of your data in release environments.
101pub type Native64StrictFiniteInDebug = NumKernelStrictFiniteInDebug<f64, 53>;
102//------------------------------------------------------------------------------------------------------------
103
104//------------------------------------------------------------------------------------------------------------
105/// A validated real number that guarantees its inner `f64` value is finite.
106///
107/// This is a type alias for [`RealValidated<Native64StrictFinite>`].
108///
109/// It is the standard, safe-to-use validated real number type for the native `f64` kernel.
110/// It prevents the representation of `NaN` and `Infinity`.
111pub type RealNative64StrictFinite = RealValidated<Native64StrictFinite>;
112
113/// A validated complex number that guarantees its inner `f64` parts are finite.
114///
115/// This is a type alias for [`ComplexValidated<Native64StrictFinite>`].
116///
117/// It is the standard, safe-to-use validated complex number type for the native `f64` kernel.
118/// It ensures that both the real and imaginary components are finite values.
119pub type ComplexNative64StrictFinite = ComplexValidated<Native64StrictFinite>;
120//------------------------------------------------------------------------------------------------------------
121
122//------------------------------------------------------------------------------------------------------------
123/// A validated real number that checks for finiteness **only in debug builds**.
124///
125/// This is a type alias for [`RealValidated<Native64StrictFiniteInDebug>`].
126///
127/// Use this type in performance-sensitive contexts where the overhead of validation
128/// in release builds is unacceptable and inputs are known to be valid.
129pub type RealNative64StrictFiniteInDebug = RealValidated<Native64StrictFiniteInDebug>;
130
131/// A validated complex number that checks for finiteness **only in debug builds**.
132///
133/// This is a type alias for [`ComplexValidated<Native64StrictFiniteInDebug>`].
134///
135/// Use this type in performance-sensitive contexts where the overhead of validation
136/// in release builds is unacceptable and inputs are known to be valid.
137pub type ComplexNative64StrictFiniteInDebug = ComplexValidated<Native64StrictFiniteInDebug>;
138//------------------------------------------------------------------------------------------------------------
139
140// --- Hashing Implementation ---------------------------------------------------------
141// Note: The Hash trait is implemented generically in the validation module for all
142// RealValidated<K> types where K::RealPolicy implements GuaranteesFiniteRealValues.
143// This ensures that validated types with finite value guarantees can be used as
144// keys in HashMap and other hash-based collections.
145//
146// The implementation hashes the raw IEEE 754 bit representation of the f64 value,
147// with special handling for signed zeros to maintain the hash contract that
148// a == b implies hash(a) == hash(b).
149//-------------------------------------------------------------
150
151//------------------------------------------------------------------------------------------------
152#[cfg(test)]
153mod tests {
154    use super::*;
155    use crate::{
156        Clamp, ComplexScalarConstructors, ComplexScalarGetParts, ComplexScalarMutateParts,
157        ComplexScalarSetParts, Constants, ExpM1, FpChecks, Hypot, Ln1p, MulAddRef, RealScalar,
158        Rounding, Sign, TotalCmp,
159        core::errors::{ErrorsTryFromf64, ErrorsValidationRawComplex, ErrorsValidationRawReal},
160        functions::{
161            ACos, ACosH, ACosHErrors, ACosHInputErrors, ACosRealErrors, ACosRealInputErrors, ASin,
162            ASinH, ASinRealErrors, ASinRealInputErrors, ATan, ATan2, ATan2Errors,
163            ATanComplexErrors, ATanComplexInputErrors, ATanH, ATanHErrors, ATanHInputErrors, Abs,
164            Arg, Classify, Conjugate, Cos, CosH, Exp, ExpErrors, Ln, Log2, Log10,
165            LogarithmComplexErrors, LogarithmComplexInputErrors, Max, Min, NegAssign, Pow,
166            PowComplexBaseRealExponentErrors, PowIntExponentErrors, PowIntExponentInputErrors,
167            PowRealBaseRealExponentErrors, Reciprocal, ReciprocalErrors, Sin, SinH, Sqrt,
168            SqrtRealErrors, Tan, TanH,
169        },
170    };
171    use approx::assert_ulps_eq;
172    use num::{Complex, One, Zero};
173    use std::{
174        cmp::Ordering,
175        f64::consts::*,
176        num::FpCategory,
177        ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
178    };
179    use try_create::{IntoInner, TryNew, TryNewValidated};
180
181    type RealValidated = RealNative64StrictFinite;
182    type ComplexValidated = ComplexNative64StrictFinite;
183
184    mod fp_checks {
185        use super::*;
186
187        #[test]
188        fn is_finite() {
189            let real = RealValidated::try_new(1.).unwrap();
190            assert!(real.is_finite());
191
192            let real = RealValidated::try_new(f64::INFINITY);
193            assert!(real.is_err());
194
195            let complex = ComplexValidated::try_new(Complex::new(1., 1.)).unwrap();
196            assert!(complex.is_finite());
197
198            let complex = ComplexValidated::try_new(Complex::new(f64::INFINITY, 1.));
199            assert!(complex.is_err());
200        }
201
202        #[test]
203        fn is_infinite() {
204            let real = RealValidated::try_new(1.).unwrap();
205            assert!(!real.is_infinite());
206
207            let real = RealValidated::try_new(f64::INFINITY);
208            assert!(real.is_err());
209
210            let complex = ComplexValidated::try_new(Complex::new(1., 1.)).unwrap();
211            assert!(!complex.is_infinite());
212
213            let complex = ComplexValidated::try_new(Complex::new(f64::INFINITY, 1.));
214            assert!(complex.is_err());
215        }
216
217        #[test]
218        fn is_nan() {
219            let real = RealValidated::try_new(1.).unwrap();
220            assert!(!real.is_nan());
221
222            let real = RealValidated::try_new(f64::NAN);
223            assert!(matches!(real, Err(ErrorsValidationRawReal::IsNaN { .. })));
224
225            let complex = ComplexValidated::try_new(Complex::new(1., 1.)).unwrap();
226            assert!(!complex.is_nan());
227
228            let complex = ComplexValidated::try_new(Complex::new(f64::NAN, 1.));
229            assert!(matches!(
230                complex,
231                Err(ErrorsValidationRawComplex::InvalidRealPart {
232                    source: 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::try_new(1.23).unwrap();
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::try_new(v).unwrap();
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_ref() {
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_ref(&min_val, &max_val), val);
1241            assert_eq!(
1242                RealValidated::try_new(-5.)
1243                    .unwrap()
1244                    .clamp_ref(&min_val, &max_val),
1245                min_val
1246            );
1247            assert_eq!(
1248                RealValidated::try_new(15.)
1249                    .unwrap()
1250                    .clamp_ref(&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_by_ref(&r2), &r2);
1378                assert_eq!(r2.max_by_ref(&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_by_ref(&r2), &r1);
1386                assert_eq!(r2.min_by_ref(&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 = 1.718281828459045;
1408                    assert_ulps_eq!(exponent.exp_m1().as_ref(), &expected);
1409                }
1410
1411                #[test]
1412                fn exp_overflow() {
1413                    let large_val = RealValidated::try_new(1.0e60).unwrap(); // exp(1.0e60) is very large
1414                    let res_large = large_val.try_exp();
1415                    assert!(matches!(
1416                        res_large,
1417                        Err(ExpErrors::Output {
1418                            source: ErrorsValidationRawReal::IsPosInfinity { .. }
1419                        })
1420                    ),);
1421                }
1422            } // end mod 
1423
1424            mod complex {
1425                use super::*;
1426
1427                #[test]
1428                fn exp_valid() {
1429                    let exponent = ComplexValidated::try_new(Complex::new(0., PI)).unwrap();
1430                    let expected = Complex::new(-1., 1.2246467991473532e-16);
1431                    assert_eq!(exponent.try_exp().unwrap().as_ref(), &expected);
1432                    assert_eq!(exponent.exp().as_ref(), &expected);
1433                }
1434            } // end mod complex
1435        } // end mod exp
1436
1437        mod logarithm {
1438            use super::*;
1439
1440            mod real {
1441                use super::*;
1442
1443                #[test]
1444                fn ln_valid() {
1445                    let e = RealValidated::one().exp();
1446                    let expected = 1.0;
1447                    assert_eq!(e.try_ln().unwrap().as_ref(), &expected);
1448                    assert_eq!(e.ln().as_ref(), &expected);
1449                }
1450
1451                #[test]
1452                fn log10_valid() {
1453                    let v = RealValidated::try_new(100.).unwrap();
1454                    let expected = 2.0;
1455                    assert_eq!(v.try_log10().unwrap().as_ref(), &expected);
1456                    assert_eq!(v.log10().as_ref(), &expected);
1457                }
1458
1459                #[test]
1460                fn log2_valid() {
1461                    let v = RealValidated::try_new(4.).unwrap();
1462                    let expected = 2.0;
1463                    assert_eq!(v.try_log2().unwrap().as_ref(), &expected);
1464                    assert_eq!(v.log2().as_ref(), &expected);
1465                }
1466
1467                #[test]
1468                fn ln_1p_valid() {
1469                    // v = e - 1;
1470                    let v = RealValidated::one().exp() - RealValidated::one();
1471
1472                    // ln(1 + v) = ln(1 + e - 1) = ln(e) = 1
1473                    assert_eq!(v.ln_1p().as_ref(), &1.);
1474                }
1475
1476                #[test]
1477                fn ln_domain_errors() {
1478                    let neg_val = RealValidated::try_new(-1.).unwrap();
1479                    assert!(matches!(
1480                        neg_val.try_ln(),
1481                        Err(LogarithmRealErrors::Input {
1482                            source: LogarithmRealInputErrors::NegativeArgument { .. }
1483                        })
1484                    ));
1485
1486                    let zero_val = RealValidated::zero();
1487                    assert!(matches!(
1488                        zero_val.try_ln(),
1489                        Err(LogarithmRealErrors::Input {
1490                            source: LogarithmRealInputErrors::ZeroArgument { .. }
1491                        })
1492                    ));
1493                }
1494
1495                #[test]
1496                fn log10_domain_errors() {
1497                    let neg_val = RealValidated::try_new(-1.).unwrap();
1498                    assert!(matches!(
1499                        neg_val.try_log10(),
1500                        Err(LogarithmRealErrors::Input {
1501                            source: LogarithmRealInputErrors::NegativeArgument { .. }
1502                        })
1503                    ));
1504
1505                    let zero_val = RealValidated::zero();
1506                    assert!(matches!(
1507                        zero_val.try_log10(),
1508                        Err(LogarithmRealErrors::Input {
1509                            source: LogarithmRealInputErrors::ZeroArgument { .. }
1510                        })
1511                    ));
1512                }
1513
1514                #[test]
1515                fn log2_domain_errors() {
1516                    let neg_val = RealValidated::try_new(-1.).unwrap();
1517                    assert!(matches!(
1518                        neg_val.try_log2(),
1519                        Err(LogarithmRealErrors::Input {
1520                            source: LogarithmRealInputErrors::NegativeArgument { .. }
1521                        })
1522                    ));
1523
1524                    let zero_val = RealValidated::zero();
1525                    assert!(matches!(
1526                        zero_val.try_log2(),
1527                        Err(LogarithmRealErrors::Input {
1528                            source: LogarithmRealInputErrors::ZeroArgument { .. }
1529                        })
1530                    ));
1531                }
1532            } // end mod real
1533
1534            mod complex {
1535                use super::*;
1536
1537                #[test]
1538                fn ln_valid() {
1539                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
1540                    let expected = Complex::new(0.8047189562170503, -1.1071487177940904);
1541                    assert_eq!(v.try_ln().unwrap().as_ref(), &expected);
1542                    assert_eq!(v.ln().as_ref(), &expected);
1543                }
1544
1545                #[test]
1546                fn log10_valid() {
1547                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
1548                    let expected = Complex::new(0.3494850021680094, -0.480828578784234);
1549                    assert_eq!(v.try_log10().unwrap().as_ref(), &expected);
1550                    assert_eq!(v.log10().as_ref(), &expected);
1551                }
1552
1553                #[test]
1554                fn log2_valid() {
1555                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
1556                    let expected = Complex::new(1.1609640474436813, -1.5972779646881088);
1557                    assert_eq!(v.try_log2().unwrap().as_ref(), &expected);
1558                    assert_eq!(v.log2().as_ref(), &expected);
1559                }
1560
1561                #[test]
1562                fn ln_zero() {
1563                    let zero_val = ComplexValidated::zero();
1564                    assert!(matches!(
1565                        zero_val.try_ln(),
1566                        Err(LogarithmComplexErrors::Input {
1567                            source: LogarithmComplexInputErrors::ZeroArgument { .. }
1568                        })
1569                    ));
1570                }
1571
1572                #[test]
1573                fn log10_zero() {
1574                    let zero_val = ComplexValidated::zero();
1575                    assert!(matches!(
1576                        zero_val.try_log10(),
1577                        Err(LogarithmComplexErrors::Input {
1578                            source: LogarithmComplexInputErrors::ZeroArgument { .. }
1579                        })
1580                    ));
1581                }
1582
1583                #[test]
1584                fn log2_zero() {
1585                    let zero_val = ComplexValidated::zero();
1586                    assert!(matches!(
1587                        zero_val.try_log2(),
1588                        Err(LogarithmComplexErrors::Input {
1589                            source: LogarithmComplexInputErrors::ZeroArgument { .. }
1590                        })
1591                    ));
1592                }
1593            } // end mod complex
1594        } // end mod logarithm
1595
1596        mod pow {
1597            use super::*;
1598
1599            mod real_base {
1600                use super::*;
1601
1602                #[test]
1603                fn negative_base_real_exponent_error() {
1604                    let base = RealValidated::try_new(-2.).unwrap();
1605                    let exponent = RealValidated::try_new(0.5).unwrap();
1606                    let res = base.try_pow(&exponent);
1607                    assert!(matches!(
1608                        res,
1609                        Err(PowRealBaseRealExponentErrors::Input {
1610                            source: PowRealBaseRealExponentInputErrors::NegativeBase { .. }
1611                        })
1612                    ));
1613                }
1614
1615                #[test]
1616                fn real_base_uint_exponent_valid() {
1617                    let base = RealValidated::try_new(2.).unwrap();
1618                    assert_eq!(
1619                        base.try_pow(3u8).unwrap(),
1620                        RealValidated::try_new(8.).unwrap()
1621                    );
1622                    assert_eq!(
1623                        base.try_pow(3u16).unwrap(),
1624                        RealValidated::try_new(8.).unwrap()
1625                    );
1626                    assert_eq!(
1627                        base.try_pow(3u32).unwrap(),
1628                        RealValidated::try_new(8.).unwrap()
1629                    );
1630                    assert_eq!(
1631                        base.try_pow(3u64).unwrap(),
1632                        RealValidated::try_new(8.).unwrap()
1633                    );
1634                    assert_eq!(
1635                        base.try_pow(3u128).unwrap(),
1636                        RealValidated::try_new(8.).unwrap()
1637                    );
1638                    assert_eq!(
1639                        base.try_pow(3usize).unwrap(),
1640                        RealValidated::try_new(8.).unwrap()
1641                    );
1642
1643                    assert_eq!(base.pow(3u8), RealValidated::try_new(8.).unwrap());
1644                    assert_eq!(base.pow(3u16), RealValidated::try_new(8.).unwrap());
1645                    assert_eq!(base.pow(3u32), RealValidated::try_new(8.).unwrap());
1646                    assert_eq!(base.pow(3u64), RealValidated::try_new(8.).unwrap());
1647                    assert_eq!(base.pow(3u128), RealValidated::try_new(8.).unwrap());
1648                    assert_eq!(base.pow(3usize), RealValidated::try_new(8.).unwrap());
1649                }
1650
1651                #[test]
1652                fn real_base_int_exponent_valid() {
1653                    let base = RealValidated::try_new(2.).unwrap();
1654                    assert_eq!(
1655                        base.try_pow(3i8).unwrap(),
1656                        RealValidated::try_new(8.).unwrap()
1657                    );
1658                    assert_eq!(
1659                        base.try_pow(3i16).unwrap(),
1660                        RealValidated::try_new(8.).unwrap()
1661                    );
1662                    assert_eq!(
1663                        base.try_pow(3i32).unwrap(),
1664                        RealValidated::try_new(8.).unwrap()
1665                    );
1666                    assert_eq!(
1667                        base.try_pow(3i64).unwrap(),
1668                        RealValidated::try_new(8.).unwrap()
1669                    );
1670                    assert_eq!(
1671                        base.try_pow(3i128).unwrap(),
1672                        RealValidated::try_new(8.).unwrap()
1673                    );
1674                    assert_eq!(
1675                        base.try_pow(3isize).unwrap(),
1676                        RealValidated::try_new(8.).unwrap()
1677                    );
1678
1679                    assert_eq!(base.pow(3i8), RealValidated::try_new(8.).unwrap());
1680                    assert_eq!(base.pow(3i16), RealValidated::try_new(8.).unwrap());
1681                    assert_eq!(base.pow(3i32), RealValidated::try_new(8.).unwrap());
1682                    assert_eq!(base.pow(3i64), RealValidated::try_new(8.).unwrap());
1683                    assert_eq!(base.pow(3i128), RealValidated::try_new(8.).unwrap());
1684                    assert_eq!(base.pow(3isize), RealValidated::try_new(8.).unwrap());
1685                }
1686
1687                #[test]
1688                fn real_base_int_exponent_zero_neg_exp_error() {
1689                    let base = RealValidated::zero();
1690                    let exponent: i32 = -2;
1691                    let res = base.try_pow(exponent);
1692                    assert!(matches!(
1693                        res,
1694                        Err(PowIntExponentErrors::Input {
1695                            source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
1696                        })
1697                    ));
1698                }
1699
1700                #[test]
1701                fn real_base_real_exponent_valid() {
1702                    let base = RealValidated::try_new(2.).unwrap();
1703                    let exponent = RealValidated::try_new(3.).unwrap();
1704                    let expected = 8.;
1705                    assert_eq!(base.try_pow(&exponent).unwrap().as_ref(), &expected);
1706                    assert_eq!(base.pow(&exponent).as_ref(), &expected);
1707                }
1708            }
1709
1710            mod complex_base {
1711                use super::*;
1712
1713                #[test]
1714                fn complex_base_uint_exponent_valid() {
1715                    let base = ComplexValidated::try_new(Complex::new(2., 3.)).unwrap();
1716                    let expected_res = ComplexValidated::try_new(Complex::new(-46., 9.)).unwrap();
1717
1718                    assert_eq!(&base.try_pow(3u8).unwrap(), &expected_res);
1719                    assert_eq!(&base.try_pow(3u16).unwrap(), &expected_res);
1720                    assert_eq!(&base.try_pow(3u32).unwrap(), &expected_res);
1721                    assert_eq!(&base.try_pow(3u64).unwrap(), &expected_res);
1722                    assert_eq!(&base.try_pow(3u128).unwrap(), &expected_res);
1723                    assert_eq!(&base.try_pow(3usize).unwrap(), &expected_res);
1724
1725                    assert_eq!(&base.pow(3u8), &expected_res);
1726                    assert_eq!(&base.pow(3u16), &expected_res);
1727                    assert_eq!(&base.pow(3u32), &expected_res);
1728                    assert_eq!(&base.pow(3u64), &expected_res);
1729                    assert_eq!(&base.pow(3u128), &expected_res);
1730                    assert_eq!(&base.pow(3usize), &expected_res);
1731                }
1732
1733                #[test]
1734                fn complex_base_int_exponent_valid() {
1735                    let base = ComplexValidated::try_new(Complex::new(2., 3.)).unwrap();
1736                    let expected_res = ComplexValidated::try_new(Complex::new(-46., 9.)).unwrap();
1737
1738                    assert_eq!(&base.try_pow(3i8).unwrap(), &expected_res);
1739                    assert_eq!(&base.try_pow(3i16).unwrap(), &expected_res);
1740                    assert_eq!(&base.try_pow(3i32).unwrap(), &expected_res);
1741                    assert_eq!(&base.try_pow(3i64).unwrap(), &expected_res);
1742                    assert_eq!(&base.try_pow(3i128).unwrap(), &expected_res);
1743                    assert_eq!(&base.try_pow(3isize).unwrap(), &expected_res);
1744
1745                    assert_eq!(&base.pow(3i8), &expected_res);
1746                    assert_eq!(&base.pow(3i16), &expected_res);
1747                    assert_eq!(&base.pow(3i32), &expected_res);
1748                    assert_eq!(&base.pow(3i64), &expected_res);
1749                    assert_eq!(&base.pow(3i128), &expected_res);
1750                    assert_eq!(&base.pow(3isize), &expected_res);
1751                }
1752
1753                #[test]
1754                fn complex_zero_base_negative_real_exponent_error() {
1755                    let base = ComplexValidated::zero();
1756                    let exponent = RealValidated::try_new(-2.).unwrap();
1757                    let res = base.try_pow(&exponent);
1758                    assert!(matches!(
1759                        res,
1760                        Err(PowComplexBaseRealExponentErrors::Input {
1761                            source:
1762                                PowComplexBaseRealExponentInputErrors::ZeroBaseNegativeExponent { .. }
1763                        })
1764                    ));
1765                }
1766
1767                #[test]
1768                fn complex_zero_base_zero_real_exponent() {
1769                    let base = ComplexValidated::zero();
1770                    let exponent = RealValidated::zero();
1771                    let res = base.try_pow(&exponent).unwrap();
1772                    assert_eq!(res, ComplexValidated::one());
1773                }
1774
1775                #[test]
1776                fn complex_base_int_exponent_zero_neg_exp_error() {
1777                    let base = ComplexValidated::zero();
1778                    let exponent: i32 = -2;
1779                    let res = base.try_pow(exponent);
1780                    assert!(matches!(
1781                        res,
1782                        Err(PowIntExponentErrors::Input {
1783                            source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
1784                        })
1785                    ));
1786                }
1787
1788                #[test]
1789                fn complex_base_real_exponent_valid() {
1790                    let base = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
1791                    let exponent = RealValidated::try_new(3.).unwrap();
1792                    let expected = Complex::new(-11.000000000000004, 1.9999999999999973);
1793                    assert_eq!(base.try_pow(&exponent).unwrap().as_ref(), &expected);
1794                    assert_eq!(base.pow(&exponent).as_ref(), &expected);
1795                }
1796
1797                #[test]
1798                fn complex_zero_base_real_exponent_valid() {
1799                    let base = ComplexValidated::zero();
1800                    let exponent = RealValidated::try_new(3.).unwrap();
1801                    let expected = Complex::new(0., 0.);
1802                    assert_eq!(base.try_pow(&exponent).unwrap().as_ref(), &expected);
1803                    assert_eq!(base.pow(&exponent).as_ref(), &expected);
1804                }
1805            }
1806        }
1807
1808        mod reciprocal {
1809            use super::*;
1810
1811            mod real {
1812                use super::*;
1813
1814                #[test]
1815                fn reciprocal_valid() {
1816                    let v = RealValidated::try_new(2.).unwrap();
1817
1818                    let res = v.try_reciprocal().unwrap();
1819                    assert_eq!(res.into_inner(), 0.5);
1820
1821                    let res = v.reciprocal();
1822                    assert_eq!(res.into_inner(), 0.5);
1823                }
1824
1825                #[test]
1826                fn reciprocal_real_zero() {
1827                    let zero_val = RealValidated::zero();
1828                    let res = zero_val.try_reciprocal();
1829                    assert!(matches!(
1830                        res,
1831                        Err(ReciprocalErrors::Input {
1832                            source: ReciprocalInputErrors::DivisionByZero { .. }
1833                        })
1834                    ));
1835                }
1836            }
1837
1838            mod complex {
1839                use super::*;
1840
1841                #[test]
1842                fn reciprocal_valid() {
1843                    let v = ComplexValidated::try_new(Complex::new(3., 4.)).unwrap();
1844
1845                    let expected = Complex::new(0.12, -0.16);
1846
1847                    let res = v.try_reciprocal().unwrap();
1848                    assert_eq!(res.as_ref(), &expected);
1849
1850                    let res = v.reciprocal();
1851                    assert_eq!(res.as_ref(), &expected);
1852                }
1853
1854                #[test]
1855                fn reciprocal_complex_zero() {
1856                    let zero_val = ComplexValidated::zero();
1857                    let res = zero_val.try_reciprocal();
1858                    assert!(matches!(
1859                        res,
1860                        Err(ReciprocalErrors::Input {
1861                            source: ReciprocalInputErrors::DivisionByZero { .. }
1862                        })
1863                    ));
1864                }
1865            }
1866        } // end mod reciprocal
1867
1868        mod sqrt {
1869            use super::*;
1870
1871            mod real {
1872                use super::*;
1873
1874                #[test]
1875                fn sqrt_valid() {
1876                    let v = RealValidated::try_new(9.).unwrap();
1877                    assert_eq!(v.try_sqrt().unwrap().as_ref(), &3.);
1878                    assert_eq!(v.sqrt().as_ref(), &3.);
1879                }
1880
1881                #[test]
1882                fn sqrt_negative_input() {
1883                    let neg_val = RealValidated::try_new(-4.).unwrap();
1884                    let res = neg_val.try_sqrt();
1885                    assert!(matches!(
1886                        res,
1887                        Err(SqrtRealErrors::Input {
1888                            source: SqrtRealInputErrors::NegativeValue { .. }
1889                        })
1890                    ));
1891                }
1892            } // end mod real
1893
1894            mod complex {
1895                use super::*;
1896
1897                #[test]
1898                fn sqrt_valid() {
1899                    let expected = Complex::new(1., 2.);
1900                    let v = ComplexValidated::try_new(expected * expected).unwrap();
1901
1902                    let expected = Complex::new(1.0000000000000002, 2.);
1903                    assert_eq!(v.try_sqrt().unwrap().as_ref(), &expected);
1904                    assert_eq!(v.sqrt().as_ref(), &expected);
1905                }
1906            }
1907        } // end mod sqrt
1908
1909        mod trigonometric {
1910            use super::*;
1911
1912            mod real {
1913                use super::*;
1914
1915                #[test]
1916                fn sin_real_valid() {
1917                    let v = RealValidated::pi_div_2();
1918
1919                    let expected = 1.;
1920                    assert_eq!(v.try_sin().unwrap().as_ref(), &expected);
1921                    assert_eq!(v.sin().as_ref(), &expected);
1922                }
1923
1924                #[test]
1925                fn cos_real_valid() {
1926                    let v = RealValidated::pi();
1927
1928                    let expected = -1.;
1929                    assert_eq!(v.try_cos().unwrap().as_ref(), &expected);
1930                    assert_eq!(v.cos().as_ref(), &expected);
1931                }
1932
1933                #[test]
1934                fn tan_real_valid() {
1935                    let v = RealValidated::one();
1936                    let expected = 1.5574077246549023;
1937                    assert_ulps_eq!(v.try_tan().unwrap().as_ref(), &expected);
1938                    assert_ulps_eq!(v.tan().as_ref(), &expected);
1939                }
1940
1941                #[test]
1942                fn asin_real_valid() {
1943                    let v = RealValidated::one();
1944
1945                    let expected = std::f64::consts::FRAC_PI_2; // π/2
1946                    assert_eq!(v.try_asin().unwrap().as_ref(), &expected);
1947                    assert_eq!(v.asin().as_ref(), &expected);
1948                }
1949
1950                #[test]
1951                fn acos_real_valid() {
1952                    let v = RealValidated::one();
1953
1954                    let expected = 0.;
1955                    assert_eq!(v.try_acos().unwrap().as_ref(), &expected);
1956                    assert_eq!(v.acos().as_ref(), &expected);
1957                }
1958
1959                #[test]
1960                fn atan_real_valid() {
1961                    let v = RealValidated::one();
1962
1963                    let expected = std::f64::consts::FRAC_PI_4; // π/4
1964                    assert_eq!(v.try_atan().unwrap().as_ref(), &expected);
1965                    assert_eq!(v.atan().as_ref(), &expected);
1966                }
1967
1968                #[test]
1969                fn atan2_valid() {
1970                    let one = RealValidated::one();
1971                    let zero = RealValidated::zero();
1972
1973                    let expected = std::f64::consts::FRAC_PI_2; // π/2
1974                    assert_eq!(one.try_atan2(&zero).unwrap().as_ref(), &expected);
1975                    assert_eq!(one.atan2(&zero).as_ref(), &expected);
1976
1977                    let expected = 0.;
1978                    assert_eq!(zero.try_atan2(&one).unwrap().as_ref(), &expected);
1979                    assert_eq!(zero.atan2(&one).as_ref(), &expected);
1980
1981                    let expected = std::f64::consts::FRAC_PI_4; // π/4
1982                    assert_eq!(one.try_atan2(&one).unwrap().as_ref(), &expected);
1983                    assert_eq!(one.atan2(&one).as_ref(), &expected);
1984                }
1985
1986                #[test]
1987                fn atan2_zero_over_zero() {
1988                    let zero_val = RealValidated::zero();
1989                    let res = zero_val.try_atan2(&RealValidated::zero());
1990                    assert!(matches!(
1991                        res,
1992                        Err(ATan2Errors::Input {
1993                            source: ATan2InputErrors::ZeroOverZero { .. }
1994                        })
1995                    ));
1996                }
1997
1998                /*
1999                #[test]
2000                #[ignore = "at the moment we cannot create a pole for the Tan function"]
2001                fn tan_real_pole() {
2002                    // tan(PI/2) is a pole
2003                    let pi_half = RealValidated::pi_div_2();
2004                    let res = pi_half.try_tan();
2005                    println!("Result: {:?}", res);
2006                    assert!(matches!(
2007                        res,
2008                        Err(TanRealErrors::Input {
2009                            source: TanRealInputErrors::ArgumentIsPole { .. }
2010                        })
2011                    ));
2012                }
2013                */
2014
2015                #[test]
2016                fn asin_real_out_of_domain() {
2017                    let val_gt_1 = RealValidated::try_new(1.5).unwrap();
2018                    assert!(matches!(
2019                        val_gt_1.try_asin(),
2020                        Err(ASinRealErrors::Input {
2021                            source: ASinRealInputErrors::OutOfDomain { .. }
2022                        })
2023                    ));
2024                    let val_lt_neg1 = RealValidated::try_new(-1.5).unwrap();
2025                    assert!(matches!(
2026                        val_lt_neg1.try_asin(),
2027                        Err(ASinRealErrors::Input {
2028                            source: ASinRealInputErrors::OutOfDomain { .. }
2029                        })
2030                    ));
2031                }
2032
2033                #[test]
2034                fn acos_real_out_of_domain() {
2035                    let val_gt_1 = RealValidated::try_new(1.5).unwrap();
2036                    assert!(matches!(
2037                        val_gt_1.try_acos(),
2038                        Err(ACosRealErrors::Input {
2039                            source: ACosRealInputErrors::OutOfDomain { .. }
2040                        })
2041                    ));
2042                    let val_lt_neg1 = RealValidated::try_new(-1.5).unwrap();
2043                    assert!(matches!(
2044                        val_lt_neg1.try_acos(),
2045                        Err(ACosRealErrors::Input {
2046                            source: ACosRealInputErrors::OutOfDomain { .. }
2047                        })
2048                    ));
2049                }
2050            } // end mod real
2051
2052            mod complex {
2053                use super::*;
2054
2055                #[test]
2056                fn sin_complex_valid() {
2057                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2058
2059                    let expected = if cfg!(target_arch = "x86_64") {
2060                        Complex::new(3.165778513216168, -1.9596010414216063)
2061                    } else if cfg!(target_arch = "aarch64") {
2062                        Complex::new(3.165778513216168, -1.959601041421606)
2063                    } else {
2064                        todo!("Architecture not-tested");
2065                    };
2066                    assert_eq!(v.try_sin().unwrap().as_ref(), &expected);
2067                    assert_eq!(v.sin().as_ref(), &expected);
2068
2069                    let zero = ComplexValidated::zero();
2070                    let expected = Complex::new(0., 0.);
2071                    assert_eq!(zero.try_sin().unwrap().as_ref(), &expected);
2072                    assert_eq!(zero.sin().as_ref(), &expected);
2073                }
2074
2075                #[test]
2076                fn cos_complex_valid() {
2077                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2078
2079                    let expected = if cfg!(target_arch = "x86_64") {
2080                        Complex::new(2.0327230070196656, 3.0518977991518)
2081                    } else if cfg!(target_arch = "aarch64") {
2082                        Complex::new(2.0327230070196656, 3.0518977991517997)
2083                    } else {
2084                        todo!("Architecture not-tested");
2085                    };
2086                    assert_eq!(v.try_cos().unwrap().as_ref(), &expected);
2087                    assert_eq!(v.cos().as_ref(), &expected);
2088
2089                    let zero = ComplexValidated::zero();
2090                    let expected = Complex::new(1., 0.);
2091                    assert_eq!(zero.try_cos().unwrap().as_ref(), &expected);
2092                    assert_eq!(zero.cos().as_ref(), &expected);
2093                }
2094
2095                #[test]
2096                fn tan_complex_valid() {
2097                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2098
2099                    let expected = Complex::new(0.03381282607989669, -1.0147936161466335);
2100                    assert_eq!(v.try_tan().unwrap().as_ref(), &expected);
2101                    assert_eq!(v.tan().as_ref(), &expected);
2102
2103                    let zero = ComplexValidated::zero();
2104                    let expected = Complex::new(0., 0.);
2105                    assert_eq!(zero.try_tan().unwrap().as_ref(), &expected);
2106                    assert_eq!(zero.tan().as_ref(), &expected);
2107                }
2108
2109                #[test]
2110                fn asin_complex_valid() {
2111                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2112
2113                    let expected = Complex::new(0.42707858639247614, -1.528570919480998);
2114                    assert_eq!(v.try_asin().unwrap().as_ref(), &expected);
2115                    assert_eq!(v.asin().as_ref(), &expected);
2116
2117                    let zero = ComplexValidated::zero();
2118                    let expected = Complex::new(0., 0.);
2119                    assert_eq!(zero.try_asin().unwrap().as_ref(), &expected);
2120                    assert_eq!(zero.asin().as_ref(), &expected);
2121                }
2122
2123                #[test]
2124                fn acos_complex_valid() {
2125                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2126
2127                    let expected = Complex::new(1.14371774040242, 1.5285709194809995);
2128                    assert_eq!(v.try_acos().unwrap().as_ref(), &expected);
2129                    assert_eq!(v.acos().as_ref(), &expected);
2130
2131                    let one = ComplexValidated::one();
2132                    let expected = Complex::new(0., 0.);
2133                    assert_eq!(one.try_acos().unwrap().as_ref(), &expected);
2134                    assert_eq!(one.acos().as_ref(), &expected);
2135                }
2136
2137                #[test]
2138                fn atan_complex_valid() {
2139                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2140
2141                    let expected = Complex::new(1.3389725222944935, -0.4023594781085251);
2142                    assert_eq!(v.try_atan().unwrap().as_ref(), &expected);
2143                    assert_eq!(v.atan().as_ref(), &expected);
2144
2145                    let zero = ComplexValidated::zero();
2146                    let expected = Complex::new(0., 0.);
2147                    assert_eq!(zero.try_atan().unwrap().as_ref(), &expected);
2148                    assert_eq!(zero.atan().as_ref(), &expected);
2149                }
2150
2151                #[test]
2152                fn atan_complex_pole() {
2153                    // atan(i) and atan(-i) are poles
2154                    let i_val = ComplexValidated::try_new_pure_imaginary(1.).unwrap();
2155                    assert!(matches!(
2156                        i_val.try_atan(),
2157                        Err(ATanComplexErrors::Input {
2158                            source: ATanComplexInputErrors::ArgumentIsPole { .. }
2159                        })
2160                    ));
2161
2162                    let neg_i_val = ComplexValidated::try_new_pure_imaginary(-1.).unwrap();
2163                    assert!(matches!(
2164                        neg_i_val.try_atan(),
2165                        Err(ATanComplexErrors::Input {
2166                            source: ATanComplexInputErrors::ArgumentIsPole { .. }
2167                        })
2168                    ));
2169                }
2170            } // end mod complex
2171        } // end mod trigonometric
2172
2173        mod hyperbolic {
2174            use super::*;
2175
2176            mod real {
2177                use super::*;
2178
2179                #[test]
2180                fn atanh_real_valid() {
2181                    let v = RealValidated::zero();
2182                    let expected = 0.;
2183                    assert_eq!(v.try_atanh().unwrap().as_ref(), &expected);
2184                    assert_eq!(v.atanh().as_ref(), &expected);
2185                }
2186
2187                #[test]
2188                fn atanh_real_out_of_domain() {
2189                    let val_ge_1 = RealValidated::one(); // atanh(1) is Inf
2190                    assert!(matches!(
2191                        val_ge_1.try_atanh(),
2192                        Err(ATanHErrors::Input {
2193                            source: ATanHInputErrors::OutOfDomain { .. }
2194                        })
2195                    ));
2196
2197                    let val_le_neg1 = RealValidated::negative_one(); // atanh(-1) is -Inf
2198                    assert!(matches!(
2199                        val_le_neg1.try_atanh(),
2200                        Err(ATanHErrors::Input {
2201                            source: ATanHInputErrors::OutOfDomain { .. }
2202                        })
2203                    ));
2204                }
2205
2206                #[test]
2207                fn acosh_real_valid() {
2208                    let v = RealValidated::one();
2209                    let expected = 0.;
2210                    assert_eq!(v.try_acosh().unwrap().as_ref(), &expected);
2211                    assert_eq!(v.acosh().as_ref(), &expected);
2212                }
2213
2214                #[test]
2215                fn acosh_real_out_of_domain() {
2216                    let val_lt_1 = RealValidated::try_new(0.5).unwrap();
2217                    assert!(matches!(
2218                        val_lt_1.try_acosh(),
2219                        Err(ACosHErrors::Input {
2220                            source: ACosHInputErrors::OutOfDomain { .. }
2221                        })
2222                    ));
2223                }
2224
2225                #[test]
2226                fn asinh_real_valid() {
2227                    let v = RealValidated::one();
2228                    let expected = 0.881373587019543;
2229                    assert_eq!(v.try_asinh().unwrap().as_ref(), &expected);
2230                    assert_eq!(v.asinh().as_ref(), &expected);
2231                }
2232
2233                #[test]
2234                fn sinh_real_valid() {
2235                    let v = RealValidated::try_new(0.881373587019543).unwrap();
2236                    let expected = 1.;
2237                    assert_eq!(v.try_sinh().unwrap().as_ref(), &expected);
2238                    assert_eq!(v.sinh().as_ref(), &expected);
2239                }
2240
2241                #[test]
2242                fn cosh_real_valid() {
2243                    let v = RealValidated::one();
2244                    let expected = 1.5430806348152437;
2245                    assert_eq!(v.try_cosh().unwrap().as_ref(), &expected);
2246                    assert_eq!(v.cosh().as_ref(), &expected);
2247                }
2248
2249                #[test]
2250                fn tanh_real_valid() {
2251                    let v = RealValidated::one();
2252                    let expected = 0.7615941559557649;
2253                    assert_eq!(v.try_tanh().unwrap().as_ref(), &expected);
2254                    assert_eq!(v.tanh().as_ref(), &expected);
2255                }
2256            }
2257
2258            mod complex {
2259                use super::*;
2260
2261                #[test]
2262                fn sinh_valid() {
2263                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2264                    let expected = Complex::new(-0.4890562590412937, -1.4031192506220405);
2265                    assert_eq!(v.try_sinh().unwrap().as_ref(), &expected);
2266                    assert_eq!(v.sinh().as_ref(), &expected);
2267                }
2268
2269                #[test]
2270                fn cosh_valid() {
2271                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2272                    let expected = Complex::new(-0.64214812471552, -1.0686074213827783);
2273                    assert_eq!(v.try_cosh().unwrap().as_ref(), &expected);
2274                    assert_eq!(v.cosh().as_ref(), &expected);
2275                }
2276
2277                #[test]
2278                fn tanh_valid() {
2279                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2280                    let expected = if cfg!(target_arch = "x86_64") {
2281                        Complex::new(1.16673625724092, 0.24345820118572523)
2282                    } else if cfg!(target_arch = "aarch64") {
2283                        Complex::new(1.16673625724092, 0.24345820118572528)
2284                    } else {
2285                        todo!("Architecture not-tested");
2286                    };
2287                    assert_eq!(v.try_tanh().unwrap().as_ref(), &expected);
2288                    assert_eq!(v.tanh().as_ref(), &expected);
2289                }
2290
2291                #[test]
2292                fn asinh_valid() {
2293                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2294                    let expected = Complex::new(1.4693517443681852, -1.0634400235777521);
2295                    Complex::new(1.4693517443681852, -1.0634400235777521);
2296                    assert_eq!(v.try_asinh().unwrap().as_ref(), &expected);
2297                    assert_eq!(v.asinh().as_ref(), &expected);
2298                }
2299
2300                #[test]
2301                fn acosh_valid() {
2302                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2303                    let expected = Complex::new(1.528570919480998, -1.1437177404024206);
2304                    assert_eq!(v.try_acosh().unwrap().as_ref(), &expected);
2305                    assert_eq!(v.acosh().as_ref(), &expected);
2306                }
2307
2308                #[test]
2309                fn atanh_valid() {
2310                    let v = ComplexValidated::try_new(Complex::new(1., -2.)).unwrap();
2311                    let expected = Complex::new(0.1732867951399864, -1.1780972450961724);
2312                    assert_eq!(v.try_atanh().unwrap().as_ref(), &expected);
2313                    assert_eq!(v.atanh().as_ref(), &expected);
2314                }
2315
2316                /*
2317                #[test]
2318                #[ignore = "at the moment we cannot create a pole for the ATanH function"]
2319                fn tanh_complex_pole() {
2320                    // tanh(z) has poles where cosh(z) = 0. e.g. z = i * (PI/2 + k*PI)
2321                    let pi_half = RealValidated::pi_div_2().into_inner();
2322                    let pole_val =
2323                        Complex64Validated::try_new_pure_imaginary(pi_half).unwrap();
2324                    println!("Atanh(Pole value): {:?}", pole_val.clone().try_tanh());
2325                    assert!(matches!(
2326                        pole_val.try_tanh(),
2327                        Err(TanHComplexErrors::Input {
2328                            source: TanHComplexInputErrors::OutOfDomain { .. }
2329                        })
2330                    ));
2331                }
2332                */
2333
2334                #[test]
2335                fn acosh_out_of_domain() {
2336                    // acosh(z) domain is C \ (-inf, 1) on real axis
2337                    let val_on_branch_cut = ComplexValidated::try_new_pure_real(0.5).unwrap();
2338                    assert!(matches!(
2339                        val_on_branch_cut.try_acosh(),
2340                        Err(ACosHErrors::Input {
2341                            source: ACosHInputErrors::OutOfDomain { .. }
2342                        })
2343                    ));
2344
2345                    let val_on_branch_cut_neg = ComplexValidated::try_new_pure_real(-5.).unwrap();
2346                    assert!(matches!(
2347                        val_on_branch_cut_neg.try_acosh(),
2348                        Err(ACosHErrors::Input {
2349                            source: ACosHInputErrors::OutOfDomain { .. }
2350                        })
2351                    ));
2352                }
2353
2354                #[test]
2355                fn atanh_out_of_domain() {
2356                    let val_ge_1 = ComplexValidated::try_new_pure_real(1.).unwrap();
2357                    assert!(matches!(
2358                        val_ge_1.try_atanh(),
2359                        Err(ATanHErrors::Input {
2360                            source: ATanHInputErrors::OutOfDomain { .. }
2361                        })
2362                    ));
2363
2364                    let val_le_neg1 = ComplexValidated::try_new_pure_real(-1.).unwrap();
2365                    assert!(matches!(
2366                        val_le_neg1.try_atanh(),
2367                        Err(ATanHErrors::Input {
2368                            source: ATanHInputErrors::OutOfDomain { .. }
2369                        })
2370                    ));
2371                }
2372            }
2373
2374            /*
2375            #[test]
2376            #[ignore = "at the moment we cannot create a pole for the TanH function"]
2377            fn tanh_out_of_domain() {
2378                // tanh(z) has poles where cosh(z) = 0. e.g. z = i * (PI/2 + k*PI)
2379                let pi_half = RealValidated::pi_div_2().into_inner();
2380                let pole_val = Complex64Validated::try_new_pure_imaginary(pi_half).unwrap();
2381                println!("TanH(Pole value): {:?}", pole_val.clone().try_tanh());
2382                assert!(matches!(
2383                    pole_val.try_tanh(),
2384                    Err(TanHComplexErrors::Input {
2385                        source: TanHComplexInputErrors::OutOfDomain { .. }
2386                    })
2387                ));
2388            }
2389            */
2390        } // end mod hyperbolic
2391    }
2392
2393    mod summation {
2394        use super::*;
2395
2396        #[test]
2397        fn sum_real() {
2398            let values = vec![
2399                RealValidated::try_new(1.0).unwrap(),
2400                RealValidated::try_new(2.0).unwrap(),
2401                RealValidated::try_new(3.0).unwrap(),
2402                RealValidated::try_new(4.0).unwrap(),
2403                RealValidated::try_new(5.0).unwrap(),
2404            ];
2405            let sum: RealValidated = values.into_iter().sum();
2406            assert_eq!(sum, RealValidated::try_new(15.0).unwrap());
2407        }
2408
2409        #[test]
2410        fn sum_real_compensated() {
2411            // Test case where simple summation might lose precision
2412            let values = vec![
2413                RealValidated::try_new(1.0e100).unwrap(),
2414                RealValidated::try_new(1.0).unwrap(),
2415                RealValidated::try_new(-1.0e100).unwrap(),
2416            ];
2417            let sum: RealValidated = values.into_iter().sum();
2418            // The Neumaier sum should correctly result in 1.0
2419            assert_eq!(sum, RealValidated::try_new(1.0).unwrap());
2420        }
2421
2422        #[test]
2423        fn sum_complex() {
2424            let values = vec![
2425                ComplexValidated::try_new(Complex::new(1.0, 2.0)).unwrap(),
2426                ComplexValidated::try_new(Complex::new(3.0, 4.0)).unwrap(),
2427                ComplexValidated::try_new(Complex::new(5.0, 6.0)).unwrap(),
2428            ];
2429            let sum: ComplexValidated = values.into_iter().sum();
2430            assert_eq!(
2431                sum,
2432                ComplexValidated::try_new(Complex::new(9.0, 12.0)).unwrap()
2433            );
2434        }
2435
2436        #[test]
2437        fn sum_complex_compensated() {
2438            let values = vec![
2439                ComplexValidated::try_new(Complex::new(1.0e100, -1.0e100)).unwrap(),
2440                ComplexValidated::try_new(Complex::new(1.0, 2.0)).unwrap(),
2441                ComplexValidated::try_new(Complex::new(-1.0e100, 1.0e100)).unwrap(),
2442            ];
2443            let sum: ComplexValidated = values.into_iter().sum();
2444            assert_eq!(
2445                sum,
2446                ComplexValidated::try_new(Complex::new(1.0, 2.0)).unwrap()
2447            );
2448        }
2449    } // end mod summation
2450
2451    mod neumaier_sum {
2452        use crate::algorithms::neumaier_sum::NeumaierSum;
2453        use try_create::TryNewValidated;
2454
2455        use super::*;
2456
2457        mod real {
2458            use super::*;
2459
2460            #[test]
2461            fn new() {
2462                let neumaier = NeumaierSum::new(RealValidated::try_new_validated(1.0).unwrap());
2463                assert_eq!(neumaier.sum_before_compensation(), &1.0);
2464                assert_eq!(neumaier.compensation(), &0.0);
2465            }
2466
2467            #[test]
2468            fn zero() {
2469                let neumaier = NeumaierSum::<RealValidated>::zero();
2470                assert_eq!(neumaier.sum_before_compensation(), &0.0);
2471                assert_eq!(neumaier.compensation(), &0.0);
2472            }
2473
2474            #[test]
2475            fn add() {
2476                let mut neumaier = NeumaierSum::zero();
2477                neumaier.add(RealValidated::try_new_validated(1.0).unwrap());
2478                neumaier.add(RealValidated::try_new_validated(1e-16).unwrap());
2479                neumaier.add(RealValidated::try_new_validated(-1.0).unwrap());
2480                assert_eq!(neumaier.sum_before_compensation(), &0.0);
2481                assert_eq!(neumaier.compensation(), &1e-16);
2482            }
2483
2484            #[test]
2485            fn sum() {
2486                let mut neumaier = NeumaierSum::zero();
2487                neumaier.add(RealValidated::try_new_validated(1.0).unwrap());
2488                neumaier.add(RealValidated::try_new_validated(1e-16).unwrap());
2489                neumaier.add(RealValidated::try_new_validated(-1.0).unwrap());
2490                assert_eq!(neumaier.sum_before_compensation(), &0.0);
2491                assert_eq!(neumaier.compensation(), &1e-16);
2492                assert_eq!(neumaier.sum().as_ref(), &1e-16);
2493                println!("compensated sum = {}", neumaier.sum());
2494            }
2495
2496            #[test]
2497            fn reset() {
2498                let mut neumaier = NeumaierSum::zero();
2499                neumaier.add(RealValidated::try_new_validated(1.0).unwrap());
2500                neumaier.add(RealValidated::try_new_validated(1e-16).unwrap());
2501                assert_eq!(neumaier.sum_before_compensation(), &1.0);
2502                assert_eq!(neumaier.compensation(), &1e-16);
2503
2504                neumaier.reset();
2505                assert_eq!(neumaier.sum_before_compensation(), &0.0);
2506                assert_eq!(neumaier.compensation(), &0.0);
2507            }
2508
2509            #[test]
2510            fn sum_big_values() {
2511                let values = [1.0, 1e100, 1.0, -1e100]
2512                    .iter()
2513                    .map(|&v| RealValidated::try_new_validated(v).unwrap())
2514                    .collect::<Vec<_>>();
2515                let sum = values.iter().cloned().sum::<RealValidated>();
2516                assert_eq!(sum, 2.0);
2517
2518                let neumaier = NeumaierSum::new_sequential(values);
2519                assert_eq!(neumaier.sum(), 2.0);
2520                println!("compensated sum = {}", neumaier.sum());
2521            }
2522
2523            #[test]
2524            fn sum_small_values() {
2525                let values = [1.0, 1e-100, -1.0]
2526                    .iter()
2527                    .map(|&v| RealValidated::try_new_validated(v).unwrap())
2528                    .collect::<Vec<_>>();
2529                let sum = values.iter().cloned().sum::<RealValidated>();
2530                assert_eq!(sum, 1e-100);
2531
2532                let neumaier = NeumaierSum::new_sequential(values);
2533                assert_eq!(neumaier.sum(), 1e-100);
2534                println!("compensated sum = {}", neumaier.sum());
2535            }
2536        }
2537
2538        mod complex {
2539            use super::*;
2540
2541            #[test]
2542            fn new() {
2543                let neumaier = NeumaierSum::new(
2544                    ComplexValidated::try_new_validated(Complex::new(1.0, 2.0)).unwrap(),
2545                );
2546                assert_eq!(
2547                    neumaier.sum_before_compensation().as_ref(),
2548                    &Complex::new(1.0, 2.0)
2549                );
2550                assert_eq!(neumaier.compensation().as_ref(), &Complex::new(0.0, 0.0));
2551            }
2552
2553            #[test]
2554            fn zero() {
2555                let neumaier = NeumaierSum::<ComplexValidated>::zero();
2556
2557                let zero = Complex::new(0.0, 0.0);
2558                assert_eq!(neumaier.sum_before_compensation().as_ref(), &zero);
2559                assert_eq!(neumaier.compensation().as_ref(), &zero);
2560            }
2561
2562            #[test]
2563            fn add() {
2564                let zero = Complex::new(0.0, 0.0);
2565                let v = Complex::new(1e-16, 2e-16);
2566
2567                let mut neumaier = NeumaierSum::zero();
2568                neumaier.add(ComplexValidated::try_new_validated(Complex::new(1.0, 2.0)).unwrap());
2569                neumaier.add(ComplexValidated::try_new_validated(v).unwrap());
2570                neumaier
2571                    .add(ComplexValidated::try_new_validated(Complex::new(-1.0, -2.0)).unwrap());
2572
2573                assert_eq!(neumaier.sum_before_compensation().as_ref(), &zero);
2574                assert_eq!(neumaier.compensation().as_ref(), &v);
2575            }
2576
2577            #[test]
2578            fn sum() {
2579                let zero = Complex::new(0.0, 0.0);
2580                let v = Complex::new(1e-16, 2e-16);
2581
2582                let mut neumaier = NeumaierSum::zero();
2583                neumaier.add(ComplexValidated::try_new_validated(Complex::new(1.0, 2.0)).unwrap());
2584                neumaier.add(ComplexValidated::try_new_validated(v).unwrap());
2585                neumaier
2586                    .add(ComplexValidated::try_new_validated(Complex::new(-1.0, -2.0)).unwrap());
2587                assert_eq!(neumaier.sum_before_compensation().as_ref(), &zero);
2588                assert_eq!(neumaier.compensation().as_ref(), &v);
2589                assert_eq!(neumaier.sum().as_ref(), &v);
2590                println!("compensated sum = {}", neumaier.sum());
2591            }
2592
2593            #[test]
2594            fn reset() {
2595                let zero = Complex::new(0.0, 0.0);
2596                let a = Complex::new(1.0, 2.0);
2597                let v = Complex::new(1e-16, 2e-16);
2598
2599                let mut neumaier = NeumaierSum::zero();
2600                neumaier.add(ComplexValidated::try_new_validated(a).unwrap());
2601                neumaier.add(ComplexValidated::try_new_validated(v).unwrap());
2602                assert_eq!(neumaier.sum_before_compensation().as_ref(), &a);
2603                assert_eq!(neumaier.compensation().as_ref(), &v);
2604
2605                neumaier.reset();
2606                assert_eq!(neumaier.sum_before_compensation().as_ref(), &zero);
2607                assert_eq!(neumaier.compensation().as_ref(), &zero);
2608            }
2609
2610            #[test]
2611            fn sum_big_values() {
2612                let values = [
2613                    Complex::new(1.0, 2.0),
2614                    Complex::new(1e100, 2e100),
2615                    Complex::new(1.0, 2.0),
2616                    Complex::new(-1e100, -2e100),
2617                ]
2618                .iter()
2619                .map(|&v| ComplexValidated::try_new_validated(v).unwrap())
2620                .collect::<Vec<_>>();
2621                let sum = values.clone().into_iter().sum::<ComplexValidated>();
2622                let expected_sum = Complex::new(2., 4.);
2623                assert_eq!(sum.as_ref(), &expected_sum);
2624
2625                let neumaier = NeumaierSum::new_sequential(values);
2626                assert_eq!(neumaier.sum().as_ref(), &expected_sum);
2627                println!("compensated sum = {}", neumaier.sum());
2628            }
2629
2630            #[test]
2631            fn sum_small_values() {
2632                let v = Complex::new(1e-100, 2e-100);
2633
2634                let values = [Complex::new(1.0, 2.0), v, Complex::new(-1.0, -2.0)]
2635                    .iter()
2636                    .map(|&v| ComplexValidated::try_new_validated(v).unwrap())
2637                    .collect::<Vec<_>>();
2638                let sum = values.iter().cloned().sum::<ComplexValidated>();
2639                let sum_expected = v;
2640                assert_eq!(sum.as_ref(), &sum_expected);
2641
2642                let neumaier = NeumaierSum::new_sequential(values);
2643                assert_eq!(neumaier.sum().as_ref(), &sum_expected);
2644                println!("compensated sum = {}", neumaier.sum());
2645            }
2646        }
2647    }
2648
2649    mod random {
2650        use super::*;
2651        use super::{ComplexNative64StrictFinite, RealNative64StrictFinite};
2652        use crate::{RandomSampleFromF64, new_random_vec};
2653        use rand::{Rng, SeedableRng, distr::Uniform, rngs::StdRng};
2654
2655        /// Tests the random generation of a `RealValidated` value.
2656        /// It uses a seeded RNG to ensure deterministic results and checks
2657        /// if the generated value falls within the expected [0, 1) range.
2658        #[test]
2659        fn test_random_real_validated() {
2660            let seed = [42; 32];
2661            let mut rng = StdRng::from_seed(seed);
2662
2663            let random_real: RealNative64StrictFinite = rng.random();
2664
2665            // rng.random::<f64>() produces a value in [0, 1), so the converted value should be in the same range.
2666            assert_eq!(random_real, 0.23713468825474326);
2667
2668            // Check for determinism
2669            let mut rng2 = StdRng::from_seed(seed);
2670            let random_real2: RealNative64StrictFinite = rng2.random();
2671            assert_eq!(random_real, random_real2);
2672        }
2673
2674        /// Tests the random generation of a `ComplexValidated` value.
2675        /// It uses a seeded RNG for determinism and verifies that both the real
2676        /// and imaginary parts of the generated complex number are within the
2677        /// expected [0, 1) range.
2678        #[test]
2679        fn test_random_complex_validated() {
2680            let seed = [99; 32];
2681            let mut rng = StdRng::from_seed(seed);
2682
2683            let random_complex: ComplexNative64StrictFinite = rng.random();
2684
2685            // The real and imaginary parts are generated independently,
2686            // so both should be in the [0, 1) range.
2687            let real_part = random_complex.real_part();
2688            let imag_part = random_complex.imag_part();
2689
2690            assert_eq!(real_part, 0.9995546882627792);
2691            assert_eq!(imag_part, 0.08932180682540247);
2692
2693            // Check for determinism
2694            let mut rng2 = StdRng::from_seed(seed);
2695            let random_complex2: ComplexNative64StrictFinite = rng2.random();
2696            assert_eq!(random_complex, random_complex2);
2697        }
2698
2699        const SEED: [u8; 32] = [42; 32];
2700
2701        #[test]
2702        fn test_sample_real_validated() {
2703            let mut rng = StdRng::from_seed(SEED);
2704            let dist = Uniform::new(-10.0, 10.0).unwrap();
2705
2706            let val = RealNative64StrictFinite::sample_from(&dist, &mut rng);
2707            assert_eq!(val, -5.257306234905137);
2708
2709            // Check determinism
2710            let mut rng2 = StdRng::from_seed(SEED);
2711            let val2 = RealNative64StrictFinite::sample_from(&dist, &mut rng2);
2712            assert_eq!(val, val2);
2713        }
2714
2715        #[test]
2716        fn test_sample_complex_validated() {
2717            let mut rng = StdRng::from_seed(SEED);
2718            let dist = Uniform::new(-10.0, 10.0).unwrap();
2719
2720            let val = ComplexNative64StrictFinite::sample_from(&dist, &mut rng);
2721            assert_eq!(val.real_part(), -5.257306234905137);
2722            assert_eq!(val.imag_part(), 7.212119776268775);
2723
2724            // Check determinism
2725            let mut rng2 = StdRng::from_seed(SEED);
2726            let val2 = ComplexNative64StrictFinite::sample_from(&dist, &mut rng2);
2727            assert_eq!(val, val2);
2728        }
2729
2730        #[test]
2731        fn new_random_vec_real() {
2732            let mut rng = StdRng::from_seed(SEED);
2733            let dist = Uniform::new(-10.0, 10.0).unwrap();
2734            let vec: Vec<RealNative64StrictFinite> = new_random_vec(3, &dist, &mut rng);
2735            assert_eq!(vec.len(), 3);
2736            assert_eq!(vec[0], -5.257306234905137);
2737            assert_eq!(vec[1], 7.212119776268775);
2738            assert_eq!(vec[2], -4.666248990558111);
2739
2740            // Check determinism
2741            let mut rng2 = StdRng::from_seed(SEED);
2742            let vec2: Vec<RealNative64StrictFinite> = new_random_vec(3, &dist, &mut rng2);
2743            assert_eq!(vec, vec2);
2744        }
2745
2746        #[test]
2747        fn new_random_vec_complex() {
2748            let mut rng = StdRng::from_seed(SEED);
2749            let dist = Uniform::new(-10.0, 10.0).unwrap();
2750            let vec: Vec<ComplexNative64StrictFinite> = new_random_vec(3, &dist, &mut rng);
2751            assert_eq!(vec.len(), 3);
2752            assert_eq!(vec[0].real_part(), -5.257306234905137);
2753            assert_eq!(vec[0].imag_part(), 7.212119776268775);
2754            assert_eq!(vec[1].real_part(), -4.666248990558111);
2755            assert_eq!(vec[1].imag_part(), 9.66047141517383);
2756            assert_eq!(vec[2].real_part(), -9.04279551029691);
2757            assert_eq!(vec[2].imag_part(), -1.026624649331671);
2758
2759            // Check determinism
2760            let mut rng2 = StdRng::from_seed(SEED);
2761            let vec2: Vec<ComplexNative64StrictFinite> = new_random_vec(3, &dist, &mut rng2);
2762            assert_eq!(vec, vec2);
2763        }
2764    }
2765
2766    mod hash_map_key_usage {
2767        use crate::{
2768            backends::native64::validated::{
2769                ComplexNative64StrictFinite, RealNative64StrictFinite,
2770                RealNative64StrictFiniteInDebug,
2771            },
2772            functions::Sign,
2773        };
2774        use num::Complex;
2775        use std::collections::HashMap;
2776        use try_create::TryNew;
2777
2778        #[test]
2779        fn test_native64_as_hashmap_key() {
2780            let mut map = HashMap::new();
2781            let key1 = RealNative64StrictFinite::try_new(1.0).unwrap();
2782            let key2 = RealNative64StrictFinite::try_new(2.5).unwrap();
2783
2784            map.insert(key1, "one");
2785            map.insert(key2, "two_point_five");
2786
2787            assert_eq!(
2788                map.get(&RealNative64StrictFinite::try_new(1.0).unwrap()),
2789                Some(&"one")
2790            );
2791            assert_eq!(map.len(), 2);
2792
2793            // Overwrite an existing key
2794            let old_value = map.insert(key1, "new_one");
2795            assert_eq!(old_value, Some("one"));
2796            assert_eq!(map.get(&key1), Some(&"new_one"));
2797        }
2798
2799        #[test]
2800        fn test_native64_debug_as_hashmap_key() {
2801            let mut map = HashMap::new();
2802            let key1 = RealNative64StrictFiniteInDebug::try_new(1.0).unwrap();
2803            let key2 = RealNative64StrictFiniteInDebug::try_new(2.5).unwrap();
2804
2805            map.insert(key1, "one_debug");
2806            map.insert(key2, "two_point_five_debug");
2807
2808            assert_eq!(
2809                map.get(&RealNative64StrictFiniteInDebug::try_new(1.0).unwrap()),
2810                Some(&"one_debug")
2811            );
2812            assert_eq!(map.len(), 2);
2813
2814            // Overwrite an existing key
2815            let old_value = map.insert(key1, "new_one_debug");
2816            assert_eq!(old_value, Some("one_debug"));
2817            assert_eq!(map.get(&key1), Some(&"new_one_debug"));
2818        }
2819
2820        #[test]
2821        fn test_hashmap_basic_operations() {
2822            let mut map = HashMap::new();
2823            let key1 = RealNative64StrictFinite::try_new(1.0).unwrap();
2824            let key2 = RealNative64StrictFinite::try_new(2.5).unwrap();
2825            let key3 = RealNative64StrictFinite::try_new(1.0).unwrap(); // Same as key1
2826
2827            // Insert and verify
2828            assert_eq!(map.insert(key1, "one"), None);
2829            assert_eq!(map.insert(key2, "two_point_five"), None);
2830            assert_eq!(map.len(), 2);
2831
2832            // Test key equality (key3 should be equal to key1)
2833            assert_eq!(map.get(&key3), Some(&"one"));
2834
2835            // Overwrite existing key
2836            assert_eq!(map.insert(key3, "one_updated"), Some("one"));
2837            assert_eq!(map.len(), 2); // Size shouldn't change
2838        }
2839
2840        #[test]
2841        fn test_hashset_operations() {
2842            use std::collections::HashSet;
2843            let mut set = HashSet::new();
2844
2845            let val1 = RealNative64StrictFinite::try_new(1.0).unwrap();
2846            let val2 = RealNative64StrictFinite::try_new(2.0).unwrap();
2847            let val1_duplicate = RealNative64StrictFinite::try_new(1.0).unwrap();
2848
2849            assert!(set.insert(val1));
2850            assert!(set.insert(val2));
2851            assert!(!set.insert(val1_duplicate)); // Should return false (already exists)
2852
2853            assert_eq!(set.len(), 2);
2854            assert!(set.contains(&RealNative64StrictFinite::try_new(1.0).unwrap()));
2855        }
2856
2857        #[test]
2858        fn test_hash_consistency() {
2859            use std::collections::hash_map::DefaultHasher;
2860            use std::hash::{Hash, Hasher};
2861
2862            let val1 = RealNative64StrictFinite::try_new(1.234).unwrap();
2863            let val2 = RealNative64StrictFinite::try_new(1.234).unwrap();
2864
2865            // Equal values should have equal hashes
2866            let mut hasher1 = DefaultHasher::new();
2867            let mut hasher2 = DefaultHasher::new();
2868
2869            val1.hash(&mut hasher1);
2870            val2.hash(&mut hasher2);
2871
2872            assert_eq!(hasher1.finish(), hasher2.finish());
2873            assert_eq!(val1, val2); // Verify they're actually equal
2874        }
2875
2876        #[test]
2877        fn test_hash_signed_zero() {
2878            use std::collections::hash_map::DefaultHasher;
2879            use std::hash::{Hash, Hasher};
2880
2881            let val1 = RealNative64StrictFinite::try_new(0.0).unwrap();
2882            assert!(val1.kernel_is_sign_positive());
2883            let val2 = RealNative64StrictFinite::try_new(-0.0).unwrap();
2884            assert!(val2.kernel_is_sign_negative());
2885
2886            // Verify the underlying f64 values have different bit patterns
2887            assert_ne!(
2888                0.0f64.to_bits(),
2889                (-0.0f64).to_bits(),
2890                "Sanity check: +0.0 and -0.0 should have different bit patterns"
2891            );
2892
2893            assert_eq!(val1, val2); // Verify they're actually equal
2894
2895            // Equal values should have equal hashes
2896            let mut hasher1 = DefaultHasher::new();
2897            let mut hasher2 = DefaultHasher::new();
2898
2899            val1.hash(&mut hasher1);
2900            val2.hash(&mut hasher2);
2901
2902            assert_eq!(hasher1.finish(), hasher2.finish());
2903        }
2904
2905        #[test]
2906        fn test_complex_as_hashmap_key() {
2907            let mut map = HashMap::new();
2908            let key1 = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
2909            let key2 = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
2910
2911            map.insert(key1, "one_plus_two_i");
2912            map.insert(key2, "three_plus_four_i");
2913
2914            assert_eq!(
2915                map.get(&ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap()),
2916                Some(&"one_plus_two_i")
2917            );
2918            assert_eq!(map.len(), 2);
2919
2920            // Overwrite an existing key
2921            let old_value = map.insert(key1, "updated_complex");
2922            assert_eq!(old_value, Some("one_plus_two_i"));
2923            assert_eq!(map.get(&key1), Some(&"updated_complex"));
2924        }
2925
2926        #[test]
2927        fn test_complex_hash_consistency() {
2928            use std::collections::hash_map::DefaultHasher;
2929            use std::hash::{Hash, Hasher};
2930
2931            let val1 = ComplexNative64StrictFinite::try_new(Complex::new(1.234, 5.678)).unwrap();
2932            let val2 = ComplexNative64StrictFinite::try_new(Complex::new(1.234, 5.678)).unwrap();
2933
2934            // Equal values should have equal hashes
2935            let mut hasher1 = DefaultHasher::new();
2936            let mut hasher2 = DefaultHasher::new();
2937
2938            val1.hash(&mut hasher1);
2939            val2.hash(&mut hasher2);
2940
2941            assert_eq!(hasher1.finish(), hasher2.finish());
2942            assert_eq!(val1, val2); // Verify they're actually equal
2943        }
2944
2945        #[test]
2946        fn test_complex_hash_signed_zero() {
2947            use std::collections::hash_map::DefaultHasher;
2948            use std::hash::{Hash, Hasher};
2949
2950            // Test all combinations of signed zeros
2951            let val1 = ComplexNative64StrictFinite::try_new(Complex::new(0.0, 0.0)).unwrap();
2952            let val2 = ComplexNative64StrictFinite::try_new(Complex::new(-0.0, 0.0)).unwrap();
2953            let val3 = ComplexNative64StrictFinite::try_new(Complex::new(0.0, -0.0)).unwrap();
2954            let val4 = ComplexNative64StrictFinite::try_new(Complex::new(-0.0, -0.0)).unwrap();
2955
2956            // All should be equal
2957            assert_eq!(val1, val2);
2958            assert_eq!(val1, val3);
2959            assert_eq!(val1, val4);
2960
2961            // All should have the same hash
2962            let mut hasher1 = DefaultHasher::new();
2963            let mut hasher2 = DefaultHasher::new();
2964            let mut hasher3 = DefaultHasher::new();
2965            let mut hasher4 = DefaultHasher::new();
2966
2967            val1.hash(&mut hasher1);
2968            val2.hash(&mut hasher2);
2969            val3.hash(&mut hasher3);
2970            val4.hash(&mut hasher4);
2971
2972            let hash1 = hasher1.finish();
2973            let hash2 = hasher2.finish();
2974            let hash3 = hasher3.finish();
2975            let hash4 = hasher4.finish();
2976
2977            assert_eq!(hash1, hash2);
2978            assert_eq!(hash1, hash3);
2979            assert_eq!(hash1, hash4);
2980        }
2981
2982        #[test]
2983        fn test_complex_different_values_different_hashes() {
2984            use std::collections::hash_map::DefaultHasher;
2985            use std::hash::{Hash, Hasher};
2986
2987            let val1 = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
2988            let val2 = ComplexNative64StrictFinite::try_new(Complex::new(2.0, 1.0)).unwrap();
2989            let val3 = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.001)).unwrap();
2990
2991            // Different values should (very likely) have different hashes
2992            let mut hasher1 = DefaultHasher::new();
2993            let mut hasher2 = DefaultHasher::new();
2994            let mut hasher3 = DefaultHasher::new();
2995
2996            val1.hash(&mut hasher1);
2997            val2.hash(&mut hasher2);
2998            val3.hash(&mut hasher3);
2999
3000            let hash1 = hasher1.finish();
3001            let hash2 = hasher2.finish();
3002            let hash3 = hasher3.finish();
3003
3004            // These are not guaranteed but extremely likely
3005            assert_ne!(val1, val2);
3006            assert_ne!(val1, val3);
3007            assert_ne!(hash1, hash2);
3008            assert_ne!(hash1, hash3);
3009        }
3010
3011        #[test]
3012        fn test_complex_hashset_operations() {
3013            use std::collections::HashSet;
3014
3015            let mut set = HashSet::new();
3016
3017            let val1 = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
3018            let val2 = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
3019            let val1_duplicate =
3020                ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
3021
3022            assert!(set.insert(val1));
3023            assert!(set.insert(val2));
3024            assert!(!set.insert(val1_duplicate)); // Should return false (already exists)
3025
3026            assert_eq!(set.len(), 2);
3027            assert!(
3028                set.contains(
3029                    &ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap()
3030                )
3031            );
3032        }
3033    }
3034
3035    mod test_truncate_to_usize {
3036        use super::*;
3037        use crate::core::errors::ErrorsRawRealToInteger;
3038
3039        #[test]
3040        fn test_positive_integers() {
3041            // Whole numbers should convert exactly
3042            let value = RealNative64StrictFinite::try_new(42.0).unwrap();
3043            assert_eq!(value.truncate_to_usize().unwrap(), 42);
3044
3045            let value = RealNative64StrictFinite::try_new(1.0).unwrap();
3046            assert_eq!(value.truncate_to_usize().unwrap(), 1);
3047
3048            let value = RealNative64StrictFinite::try_new(100.0).unwrap();
3049            assert_eq!(value.truncate_to_usize().unwrap(), 100);
3050        }
3051
3052        #[test]
3053        fn test_positive_fractionals_truncate() {
3054            // Positive fractional parts should be discarded (truncated toward zero)
3055            let value = RealNative64StrictFinite::try_new(42.9).unwrap();
3056            assert_eq!(value.truncate_to_usize().unwrap(), 42);
3057
3058            let value = RealNative64StrictFinite::try_new(3.7).unwrap();
3059            assert_eq!(value.truncate_to_usize().unwrap(), 3);
3060
3061            let value = RealNative64StrictFinite::try_new(0.9).unwrap();
3062            assert_eq!(value.truncate_to_usize().unwrap(), 0);
3063
3064            let value = RealNative64StrictFinite::try_new(99.999).unwrap();
3065            assert_eq!(value.truncate_to_usize().unwrap(), 99);
3066        }
3067
3068        #[test]
3069        fn test_zero_cases() {
3070            // Zero should convert to 0
3071            let value = RealNative64StrictFinite::try_new(0.0).unwrap();
3072            assert_eq!(value.truncate_to_usize().unwrap(), 0);
3073
3074            // Positive fractional values less than 1 should truncate to 0
3075            let value = RealNative64StrictFinite::try_new(0.1).unwrap();
3076            assert_eq!(value.truncate_to_usize().unwrap(), 0);
3077
3078            let value = RealNative64StrictFinite::try_new(0.5).unwrap();
3079            assert_eq!(value.truncate_to_usize().unwrap(), 0);
3080        }
3081
3082        #[test]
3083        fn test_large_valid_values() {
3084            // Large but representable values within usize range
3085            let value = RealNative64StrictFinite::try_new(1_000_000.7).unwrap();
3086            assert_eq!(value.truncate_to_usize().unwrap(), 1_000_000);
3087
3088            let value = RealNative64StrictFinite::try_new(1_000_000_000.0).unwrap();
3089            assert_eq!(value.truncate_to_usize().unwrap(), 1_000_000_000);
3090
3091            // Test with a value close to but less than usize::MAX (on 64-bit systems)
3092            let max_safe = (usize::MAX as f64) - 2048.0; // Subtract to avoid precision issues
3093            let value = RealNative64StrictFinite::try_new(max_safe).unwrap();
3094            let result = value.truncate_to_usize().unwrap();
3095            assert!(result < usize::MAX);
3096        }
3097
3098        #[test]
3099        fn test_negative_values_error() {
3100            // Negative values should return OutOfRange error
3101            let value = RealNative64StrictFinite::try_new(-1.0).unwrap();
3102            let result = value.truncate_to_usize();
3103            assert!(matches!(
3104                result,
3105                Err(ErrorsRawRealToInteger::OutOfRange { .. })
3106            ));
3107
3108            let value = RealNative64StrictFinite::try_new(-10.5).unwrap();
3109            let result = value.truncate_to_usize();
3110            assert!(matches!(
3111                result,
3112                Err(ErrorsRawRealToInteger::OutOfRange { .. })
3113            ));
3114
3115            let value = RealNative64StrictFinite::try_new(-0.1).unwrap();
3116            let result = value.truncate_to_usize();
3117            assert!(matches!(result, Ok(0)));
3118
3119            let value = RealNative64StrictFinite::try_new(-1000.0).unwrap();
3120            let result = value.truncate_to_usize();
3121            assert!(matches!(
3122                result,
3123                Err(ErrorsRawRealToInteger::OutOfRange { .. })
3124            ));
3125        }
3126
3127        #[test]
3128        fn test_too_large_values_error() {
3129            // Values larger than usize::MAX should return OutOfRange error
3130            let too_large = (usize::MAX as f64) * 2.0;
3131            let value = RealNative64StrictFinite::try_new(too_large).unwrap();
3132            let result = value.truncate_to_usize();
3133            assert!(matches!(
3134                result,
3135                Err(ErrorsRawRealToInteger::OutOfRange { .. })
3136            ));
3137
3138            let value = RealNative64StrictFinite::try_new(1e20).unwrap();
3139            let result = value.truncate_to_usize();
3140            assert!(matches!(
3141                result,
3142                Err(ErrorsRawRealToInteger::OutOfRange { .. })
3143            ));
3144        }
3145
3146        #[test]
3147        fn test_edge_cases() {
3148            // Test values very close to boundaries
3149
3150            // Just above zero
3151            let value = RealNative64StrictFinite::try_new(f64::EPSILON).unwrap();
3152            assert_eq!(value.truncate_to_usize().unwrap(), 0);
3153
3154            // Just below 1
3155            let value = RealNative64StrictFinite::try_new(1.0 - f64::EPSILON).unwrap();
3156            assert_eq!(value.truncate_to_usize().unwrap(), 0);
3157
3158            // Just above 1
3159            let value = RealNative64StrictFinite::try_new(1.0 + f64::EPSILON).unwrap();
3160            assert_eq!(value.truncate_to_usize().unwrap(), 1);
3161        }
3162
3163        #[test]
3164        fn test_truncation_behavior() {
3165            // Verify truncation (toward zero) behavior vs other rounding modes
3166            let test_cases = [
3167                (2.1, 2),
3168                (2.5, 2), // truncate, not round
3169                (2.9, 2),
3170                (3.0, 3),
3171                (3.1, 3),
3172                (99.999, 99),
3173            ];
3174
3175            for (input, expected) in test_cases {
3176                let value = RealNative64StrictFinite::try_new(input)
3177                    .unwrap()
3178                    .truncate_to_usize()
3179                    .unwrap();
3180                assert_eq!(
3181                    value, expected,
3182                    "Failed for input {}: expected {}, got {:?}",
3183                    input, expected, value
3184                );
3185            }
3186        }
3187
3188        #[test]
3189        fn test_error_details() {
3190            // Test that error variants contain expected information
3191
3192            // OutOfRange error for negative value
3193            let value = RealNative64StrictFinite::try_new(-5.0).unwrap();
3194            if let Err(ErrorsRawRealToInteger::OutOfRange {
3195                value: err_val,
3196                min,
3197                max,
3198                ..
3199            }) = value.truncate_to_usize()
3200            {
3201                assert_eq!(err_val, -5.0);
3202                assert_eq!(min, usize::MIN);
3203                assert_eq!(max, usize::MAX);
3204            } else {
3205                panic!("Expected OutOfRange error for negative value");
3206            }
3207
3208            // OutOfRange error for too large value
3209            let large_value = 1e20;
3210            let value = RealNative64StrictFinite::try_new(large_value).unwrap();
3211            if let Err(ErrorsRawRealToInteger::OutOfRange {
3212                value: err_val,
3213                min,
3214                max,
3215                ..
3216            }) = value.truncate_to_usize()
3217            {
3218                assert_eq!(err_val, large_value);
3219                assert_eq!(min, usize::MIN);
3220                assert_eq!(max, usize::MAX);
3221            } else {
3222                panic!("Expected OutOfRange error for large value");
3223            }
3224        }
3225
3226        #[test]
3227        fn test_practical_usage_scenario() {
3228            // Test a realistic usage scenario: creating a vector with calculated size
3229            fn create_vector_with_calculated_size<T: Default + Clone>(
3230                size_float: RealNative64StrictFinite,
3231            ) -> Result<Vec<T>, Box<dyn std::error::Error>> {
3232                let size = size_float.truncate_to_usize()?;
3233                Ok(vec![T::default(); size])
3234            }
3235
3236            // Valid case
3237            let calculated_size = RealNative64StrictFinite::try_new(10.7).unwrap();
3238            let vec: Vec<i32> = create_vector_with_calculated_size(calculated_size).unwrap();
3239            assert_eq!(vec.len(), 10); // Truncated from 10.7
3240
3241            // Error case - negative size
3242            let negative_size = RealNative64StrictFinite::try_new(-5.0).unwrap();
3243            let result: Result<Vec<i32>, _> = create_vector_with_calculated_size(negative_size);
3244            assert!(result.is_err());
3245
3246            // Error case - too large size
3247            let huge_size = RealNative64StrictFinite::try_new(1e20).unwrap();
3248            let result: Result<Vec<i32>, _> = create_vector_with_calculated_size(huge_size);
3249            assert!(result.is_err());
3250        }
3251
3252        #[test]
3253        fn test_consistency_with_f64_behavior() {
3254            // Verify that our implementation behaves consistently with direct f64 operations
3255            let test_values = [0.0, 1.0, 2.5, 42.9, 100.0, 0.1, 0.9];
3256
3257            for &val in &test_values {
3258                let validated = RealNative64StrictFinite::try_new(val).unwrap();
3259                let result = validated.truncate_to_usize().unwrap();
3260
3261                // Compare with direct f64 truncation
3262                let expected = val.trunc() as usize;
3263                assert_eq!(result, expected, "Mismatch for value {}", val);
3264            }
3265        }
3266    }
3267
3268    mod bytemuck_conversions {
3269        use super::*;
3270        use bytemuck::checked::{CheckedCastError, try_from_bytes};
3271
3272        mod real_strict_finite {
3273            use super::*;
3274
3275            #[test]
3276            fn valid_value_from_bytes() {
3277                let value = 42.0_f64;
3278                let bytes = value.to_ne_bytes();
3279
3280                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3281                    try_from_bytes(&bytes);
3282                assert!(result.is_ok());
3283                assert_eq!(*result.unwrap().as_ref(), 42.0);
3284            }
3285
3286            #[test]
3287            fn valid_value_try_cast() {
3288                let value = 42.0_f64;
3289                let bytes = value.to_ne_bytes();
3290                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3291                    try_from_bytes(&bytes);
3292                assert!(result.is_ok());
3293                assert_eq!(*result.unwrap().as_ref(), 42.0);
3294            }
3295
3296            #[test]
3297            fn zero_from_bytes() {
3298                let value = 0.0_f64;
3299                let bytes = value.to_ne_bytes();
3300
3301                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3302                    try_from_bytes(&bytes);
3303                assert!(result.is_ok());
3304                assert_eq!(*result.unwrap().as_ref(), 0.0);
3305            }
3306
3307            #[test]
3308            fn negative_zero_from_bytes() {
3309                let value = -0.0_f64;
3310                let bytes = value.to_ne_bytes();
3311
3312                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3313                    try_from_bytes(&bytes);
3314                assert!(result.is_ok());
3315                assert_eq!(*result.unwrap().as_ref(), -0.0);
3316            }
3317
3318            #[test]
3319            fn max_value_from_bytes() {
3320                let value = f64::MAX;
3321                let bytes = value.to_ne_bytes();
3322
3323                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3324                    try_from_bytes(&bytes);
3325                assert!(result.is_ok());
3326                assert_eq!(*result.unwrap().as_ref(), f64::MAX);
3327            }
3328
3329            #[test]
3330            fn min_value_from_bytes() {
3331                let value = f64::MIN;
3332                let bytes = value.to_ne_bytes();
3333
3334                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3335                    try_from_bytes(&bytes);
3336                assert!(result.is_ok());
3337                assert_eq!(*result.unwrap().as_ref(), f64::MIN);
3338            }
3339
3340            #[test]
3341            fn nan_from_bytes_fails() {
3342                let value = f64::NAN;
3343                let bytes = value.to_ne_bytes();
3344
3345                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3346                    try_from_bytes(&bytes);
3347                assert!(result.is_err());
3348                assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
3349            }
3350
3351            #[test]
3352            fn nan_try_cast_fails() {
3353                let value = f64::NAN;
3354                let bytes = value.to_ne_bytes();
3355                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3356                    try_from_bytes(&bytes);
3357                assert!(result.is_err());
3358                assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
3359            }
3360
3361            #[test]
3362            fn infinity_from_bytes_fails() {
3363                let value = f64::INFINITY;
3364                let bytes = value.to_ne_bytes();
3365
3366                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3367                    try_from_bytes(&bytes);
3368                assert!(result.is_err());
3369                assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
3370            }
3371
3372            #[test]
3373            fn neg_infinity_from_bytes_fails() {
3374                let value = f64::NEG_INFINITY;
3375                let bytes = value.to_ne_bytes();
3376
3377                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3378                    try_from_bytes(&bytes);
3379                assert!(result.is_err());
3380                assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
3381            }
3382
3383            #[test]
3384            fn subnormal_from_bytes_fails() {
3385                let value = f64::MIN_POSITIVE / 2.0; // subnormal
3386                let bytes = value.to_ne_bytes();
3387
3388                let result: Result<&RealNative64StrictFinite, CheckedCastError> =
3389                    try_from_bytes(&bytes);
3390                assert!(result.is_err());
3391                assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
3392            }
3393
3394            #[test]
3395            fn round_trip_conversion() {
3396                let original = RealNative64StrictFinite::try_new(123.456).unwrap();
3397                let as_f64 = *original.as_ref();
3398                let bytes = as_f64.to_ne_bytes();
3399
3400                let from_bytes: &RealNative64StrictFinite = try_from_bytes(&bytes).unwrap();
3401                assert_eq!(original, *from_bytes);
3402            }
3403
3404            #[test]
3405            fn vec_conversion() {
3406                let values = vec![
3407                    RealNative64StrictFinite::try_new(1.0).unwrap(),
3408                    RealNative64StrictFinite::try_new(2.0).unwrap(),
3409                    RealNative64StrictFinite::try_new(3.0).unwrap(),
3410                    RealNative64StrictFinite::try_new(4.0).unwrap(),
3411                ];
3412
3413                // Cast to bytes
3414                let bytes = bytemuck::cast_slice::<RealNative64StrictFinite, u8>(&values);
3415
3416                // Try to cast back - should succeed
3417                let result: Result<&[RealNative64StrictFinite], CheckedCastError> =
3418                    bytemuck::checked::try_cast_slice(bytes);
3419                assert!(result.is_ok());
3420
3421                let validated_slice = result.unwrap();
3422                assert_eq!(validated_slice.len(), 4);
3423                assert_eq!(*validated_slice[0].as_ref(), 1.0);
3424                assert_eq!(*validated_slice[3].as_ref(), 4.0);
3425            }
3426
3427            #[test]
3428            fn direct_f64_slice_with_invalid_values() {
3429                // Create bytes representing f64 values, some invalid
3430                let mut bytes = Vec::new();
3431                bytes.extend_from_slice(&1.0_f64.to_ne_bytes());
3432                bytes.extend_from_slice(&f64::NAN.to_ne_bytes());
3433                bytes.extend_from_slice(&3.0_f64.to_ne_bytes());
3434
3435                // Should fail because of NaN
3436                let result: Result<&[RealNative64StrictFinite], CheckedCastError> =
3437                    bytemuck::checked::try_cast_slice(&bytes);
3438                assert!(result.is_err());
3439            }
3440        }
3441
3442        mod vec_conversions {
3443            use super::*;
3444            use try_create::TryNew;
3445
3446            #[test]
3447            fn vec_f64_to_validated_all_valid() {
3448                // Create a Vec<f64> with all valid values
3449                let f64_vec = [1.0, 2.5, -3.7, 0.0, 42.0];
3450
3451                // Convert to Vec<RealNative64StrictFinite>
3452                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3453                    .iter()
3454                    .map(|&x| RealNative64StrictFinite::try_new(x))
3455                    .collect();
3456
3457                assert!(validated_vec.is_ok());
3458                let validated_vec = validated_vec.unwrap();
3459
3460                // Verify length
3461                assert_eq!(validated_vec.len(), 5);
3462
3463                // Verify values
3464                assert_eq!(*validated_vec[0].as_ref(), 1.0);
3465                assert_eq!(*validated_vec[1].as_ref(), 2.5);
3466                assert_eq!(*validated_vec[2].as_ref(), -3.7);
3467                assert_eq!(*validated_vec[3].as_ref(), 0.0);
3468                assert_eq!(*validated_vec[4].as_ref(), 42.0);
3469            }
3470
3471            #[test]
3472            fn vec_f64_to_validated_with_nan() {
3473                // Create a Vec<f64> with a NaN value
3474                let f64_vec = [1.0, 2.5, f64::NAN, 0.0, 42.0];
3475
3476                // Conversion should fail on the NaN
3477                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3478                    .iter()
3479                    .map(|&x| RealNative64StrictFinite::try_new(x))
3480                    .collect();
3481
3482                assert!(validated_vec.is_err());
3483            }
3484
3485            #[test]
3486            fn vec_f64_to_validated_with_infinity() {
3487                // Create a Vec<f64> with an infinity value
3488                let f64_vec = [1.0, f64::INFINITY, 3.0];
3489
3490                // Conversion should fail on the infinity
3491                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3492                    .iter()
3493                    .map(|&x| RealNative64StrictFinite::try_new(x))
3494                    .collect();
3495
3496                assert!(validated_vec.is_err());
3497            }
3498
3499            #[test]
3500            fn vec_f64_to_validated_with_subnormal() {
3501                // Create a Vec<f64> with a subnormal value
3502                let subnormal = f64::MIN_POSITIVE / 2.0;
3503                let f64_vec = [1.0, subnormal, 3.0];
3504
3505                // Conversion should fail on the subnormal
3506                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3507                    .iter()
3508                    .map(|&x| RealNative64StrictFinite::try_new(x))
3509                    .collect();
3510
3511                assert!(validated_vec.is_err());
3512            }
3513
3514            #[test]
3515            fn vec_validated_to_f64() {
3516                // Create a Vec<RealNative64StrictFinite>
3517                let validated_vec = [
3518                    RealNative64StrictFinite::try_new(1.0).unwrap(),
3519                    RealNative64StrictFinite::try_new(2.5).unwrap(),
3520                    RealNative64StrictFinite::try_new(-3.7).unwrap(),
3521                    RealNative64StrictFinite::try_new(0.0).unwrap(),
3522                    RealNative64StrictFinite::try_new(42.0).unwrap(),
3523                ];
3524
3525                // Convert to Vec<f64>
3526                let f64_vec: Vec<f64> = validated_vec.iter().map(|x| *x.as_ref()).collect();
3527
3528                // Verify length
3529                assert_eq!(f64_vec.len(), 5);
3530
3531                // Verify values
3532                assert_eq!(f64_vec[0], 1.0);
3533                assert_eq!(f64_vec[1], 2.5);
3534                assert_eq!(f64_vec[2], -3.7);
3535                assert_eq!(f64_vec[3], 0.0);
3536                assert_eq!(f64_vec[4], 42.0);
3537            }
3538
3539            #[test]
3540            fn vec_round_trip_conversion() {
3541                // Start with Vec<f64>
3542                let original_f64 = vec![1.0, 2.5, -3.7, 0.0, 42.0, -999.123];
3543
3544                // Convert to Vec<RealNative64StrictFinite>
3545                let validated_vec: Vec<RealNative64StrictFinite> = original_f64
3546                    .iter()
3547                    .map(|&x| RealNative64StrictFinite::try_new(x).unwrap())
3548                    .collect();
3549
3550                // Convert back to Vec<f64>
3551                let final_f64: Vec<f64> = validated_vec.iter().map(|x| *x.as_ref()).collect();
3552
3553                let slice_f64 =
3554                    bytemuck::cast_slice::<RealNative64StrictFinite, f64>(&validated_vec);
3555                assert_eq!(slice_f64, &original_f64);
3556
3557                // Should be identical
3558                assert_eq!(original_f64, final_f64);
3559            }
3560
3561            #[test]
3562            fn vec_empty() {
3563                // Empty Vec<f64>
3564                let f64_vec: Vec<f64> = vec![];
3565
3566                // Convert to Vec<RealNative64StrictFinite>
3567                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3568                    .iter()
3569                    .map(|&x| RealNative64StrictFinite::try_new(x))
3570                    .collect();
3571
3572                assert!(validated_vec.is_ok());
3573                assert_eq!(validated_vec.unwrap().len(), 0);
3574            }
3575
3576            #[test]
3577            fn vec_large_values() {
3578                // Test with extreme but valid values
3579                let f64_vec = vec![f64::MAX, f64::MIN, f64::MIN_POSITIVE, -f64::MIN_POSITIVE];
3580
3581                // All should be valid
3582                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3583                    .iter()
3584                    .map(|&x| RealNative64StrictFinite::try_new(x))
3585                    .collect();
3586
3587                assert!(validated_vec.is_ok());
3588                let validated_vec = validated_vec.unwrap();
3589
3590                // Verify round-trip
3591                let f64_back: Vec<f64> = validated_vec.iter().map(|x| *x.as_ref()).collect();
3592
3593                assert_eq!(f64_vec, f64_back);
3594            }
3595
3596            #[test]
3597            fn vec_with_zeros() {
3598                // Test with positive and negative zeros
3599                let f64_vec = [0.0, -0.0, 1.0, -1.0];
3600
3601                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3602                    .iter()
3603                    .map(|&x| RealNative64StrictFinite::try_new(x))
3604                    .collect();
3605
3606                assert!(validated_vec.is_ok());
3607                let validated_vec = validated_vec.unwrap();
3608
3609                assert_eq!(*validated_vec[0].as_ref(), 0.0);
3610                assert_eq!(*validated_vec[1].as_ref(), -0.0);
3611            }
3612
3613            #[test]
3614            fn vec_using_from_iter() {
3615                // Test using from_iter for a more idiomatic approach
3616                let f64_vec = [1.0, 2.0, 3.0, 4.0, 5.0];
3617
3618                // Using from_iter with filter_map to handle errors
3619                let validated_vec: Vec<RealNative64StrictFinite> = f64_vec
3620                    .iter()
3621                    .filter_map(|&x| RealNative64StrictFinite::try_new(x).ok())
3622                    .collect();
3623
3624                assert_eq!(validated_vec.len(), 5);
3625            }
3626
3627            #[test]
3628            fn vec_conversion_preserves_order() {
3629                // Test that order is preserved through conversion
3630                let f64_vec: Vec<f64> = (0..100).map(|i| i as f64 * 0.1).collect();
3631
3632                let validated_vec: Vec<RealNative64StrictFinite> = f64_vec
3633                    .iter()
3634                    .map(|&x| RealNative64StrictFinite::try_new(x).unwrap())
3635                    .collect();
3636
3637                // Convert back and verify order
3638                for (i, val) in validated_vec.iter().enumerate() {
3639                    assert_eq!(*val.as_ref(), i as f64 * 0.1);
3640                }
3641            }
3642
3643            #[test]
3644            fn vec_partial_conversion_with_find() {
3645                // Test finding the first invalid value
3646                let f64_vec = [1.0, 2.0, f64::NAN, 4.0, 5.0];
3647
3648                // Find which index has the invalid value
3649                let (invalid_idx, _) = f64_vec
3650                    .iter()
3651                    .enumerate()
3652                    .find(|(_, x)| RealNative64StrictFinite::try_new(**x).is_err())
3653                    .expect("Should find invalid value");
3654
3655                assert_eq!(invalid_idx, 2);
3656            }
3657
3658            #[test]
3659            fn vec_consume_and_convert() {
3660                // Test consuming the original vector
3661                let f64_vec = vec![1.0, 2.0, 3.0];
3662
3663                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3664                    .into_iter()
3665                    .map(RealNative64StrictFinite::try_new)
3666                    .collect();
3667
3668                assert!(validated_vec.is_ok());
3669                assert_eq!(validated_vec.unwrap().len(), 3);
3670
3671                // f64_vec is moved and cannot be used here
3672            }
3673
3674            #[test]
3675            fn vec_validated_to_f64_with_try_cast_vec() {
3676                use bytemuck::allocation::try_cast_vec;
3677
3678                // Create a Vec<RealNative64StrictFinite>
3679                let validated_vec: Vec<RealNative64StrictFinite> = vec![
3680                    RealNative64StrictFinite::try_new(1.0).unwrap(),
3681                    RealNative64StrictFinite::try_new(2.5).unwrap(),
3682                    RealNative64StrictFinite::try_new(-3.7).unwrap(),
3683                    RealNative64StrictFinite::try_new(0.0).unwrap(),
3684                    RealNative64StrictFinite::try_new(42.0).unwrap(),
3685                ];
3686
3687                // Try to cast Vec<RealNative64StrictFinite> -> Vec<f64> using bytemuck
3688                let f64_vec_result: Result<Vec<f64>, _> = try_cast_vec(validated_vec);
3689
3690                // This should work because:
3691                // - RealNative64StrictFinite implements NoUninit āœ“
3692                // - f64 implements AnyBitPattern āœ“
3693                // - Both have same size and alignment (repr(transparent)) āœ“
3694                assert!(
3695                    f64_vec_result.is_ok(),
3696                    "try_cast_vec should work for Vec<RealNative64StrictFinite> -> Vec<f64>"
3697                );
3698
3699                let f64_vec = f64_vec_result.unwrap();
3700                assert_eq!(f64_vec.len(), 5);
3701                assert_eq!(f64_vec[0], 1.0);
3702                assert_eq!(f64_vec[1], 2.5);
3703                assert_eq!(f64_vec[2], -3.7);
3704                assert_eq!(f64_vec[3], 0.0);
3705                assert_eq!(f64_vec[4], 42.0);
3706            }
3707
3708            #[test]
3709            fn vec_f64_to_validated_try_cast_vec_fails() {
3710                // Create a Vec<f64>
3711                let f64_vec = [1.0, 2.5, -3.7, 0.0, 42.0];
3712
3713                // Try to cast Vec<f64> -> Vec<RealNative64StrictFinite> using bytemuck
3714                // This SHOULD NOT compile because RealNative64StrictFinite does not implement AnyBitPattern
3715                // (it only implements CheckedBitPattern, which requires validation)
3716
3717                // Uncomment the following line to verify it doesn't compile:
3718                // let validated_result: Result<Vec<RealNative64StrictFinite>, _> = try_cast_vec(f64_vec);
3719
3720                // Instead, we must use the iterator approach with validation:
3721                let validated_vec: Result<Vec<RealNative64StrictFinite>, _> = f64_vec
3722                    .iter()
3723                    .map(|&x| RealNative64StrictFinite::try_new(x))
3724                    .collect();
3725
3726                assert!(validated_vec.is_ok());
3727                assert_eq!(validated_vec.unwrap().len(), 5);
3728            }
3729        }
3730
3731        mod real_strict_finite_in_debug {
3732            use super::*;
3733
3734            #[test]
3735            fn valid_value_from_bytes() {
3736                let value = 42.0_f64;
3737                let bytes = value.to_ne_bytes();
3738
3739                let result: Result<&RealNative64StrictFiniteInDebug, CheckedCastError> =
3740                    try_from_bytes(&bytes);
3741                assert!(result.is_ok());
3742                assert_eq!(*result.unwrap().as_ref(), 42.0);
3743            }
3744
3745            #[test]
3746            fn nan_from_bytes() {
3747                let value = f64::NAN;
3748                let bytes = value.to_ne_bytes();
3749
3750                let result: Result<&RealNative64StrictFiniteInDebug, CheckedCastError> =
3751                    try_from_bytes(&bytes);
3752
3753                #[cfg(debug_assertions)]
3754                {
3755                    // In debug mode, should fail
3756                    assert!(result.is_err());
3757                    assert!(matches!(result, Err(CheckedCastError::InvalidBitPattern)));
3758                }
3759
3760                #[cfg(not(debug_assertions))]
3761                {
3762                    // In release mode, validation is skipped
3763                    // This test documents the behavior but is NOT safe
3764                    // Don't use this in production without guarantees!
3765                    assert!(result.is_ok());
3766                }
3767            }
3768
3769            #[test]
3770            fn infinity_from_bytes() {
3771                let value = f64::INFINITY;
3772                let bytes = value.to_ne_bytes();
3773
3774                let result: Result<&RealNative64StrictFiniteInDebug, CheckedCastError> =
3775                    try_from_bytes(&bytes);
3776
3777                #[cfg(debug_assertions)]
3778                {
3779                    assert!(result.is_err());
3780                }
3781
3782                #[cfg(not(debug_assertions))]
3783                {
3784                    assert!(result.is_ok());
3785                }
3786            }
3787
3788            #[test]
3789            fn round_trip_with_valid_value() {
3790                let original = RealNative64StrictFiniteInDebug::try_new(123.456).unwrap();
3791                let as_f64 = *original.as_ref();
3792                let bytes = as_f64.to_ne_bytes();
3793
3794                let from_bytes: &RealNative64StrictFiniteInDebug = try_from_bytes(&bytes).unwrap();
3795                assert_eq!(original, *from_bytes);
3796            }
3797        }
3798
3799        #[test]
3800        fn alignment_check() {
3801            use std::mem;
3802
3803            // Verify that RealNative64StrictFinite has the same alignment as f64
3804            assert_eq!(
3805                mem::align_of::<RealNative64StrictFinite>(),
3806                mem::align_of::<f64>()
3807            );
3808
3809            // Verify size
3810            assert_eq!(
3811                mem::size_of::<RealNative64StrictFinite>(),
3812                mem::size_of::<f64>()
3813            );
3814        }
3815    }
3816
3817    /// Tests for the conditional `Copy` implementation.
3818    ///
3819    /// These tests verify that `RealValidated` and `ComplexValidated` implement `Copy`
3820    /// when their underlying raw types implement `Copy` (e.g., `f64`, `Complex<f64>`).
3821    mod copy_trait_tests {
3822        use super::*;
3823
3824        mod real_copy {
3825            use super::*;
3826
3827            #[test]
3828            fn real_is_copy() {
3829                // Verify RealNative64StrictFinite is Copy
3830                fn assert_copy<T: Copy>() {}
3831                assert_copy::<RealNative64StrictFinite>();
3832                assert_copy::<RealNative64StrictFiniteInDebug>();
3833            }
3834
3835            #[test]
3836            fn real_copy_semantics() {
3837                let x = RealNative64StrictFinite::try_new(3.).unwrap();
3838                let y = x; // Copy, not move
3839                let z = x; // x is still valid because it was copied
3840                assert_eq!(x, y);
3841                assert_eq!(x, z);
3842            }
3843
3844            #[test]
3845            fn real_copy_in_function_call() {
3846                fn takes_by_value(val: RealNative64StrictFinite) -> f64 {
3847                    *val.as_ref()
3848                }
3849
3850                let x = RealNative64StrictFinite::try_new(42.0).unwrap();
3851                let result1 = takes_by_value(x);
3852                let result2 = takes_by_value(x); // x is still valid after first call
3853                assert_eq!(result1, 42.0);
3854                assert_eq!(result2, 42.0);
3855            }
3856
3857            #[test]
3858            fn real_copy_in_loop() {
3859                let x = RealNative64StrictFinite::try_new(1.0).unwrap();
3860                let mut sum = RealNative64StrictFinite::zero();
3861
3862                for _ in 0..5 {
3863                    sum += x; // x is copied each iteration
3864                }
3865
3866                assert_eq!(*sum.as_ref(), 5.0);
3867                assert_eq!(*x.as_ref(), 1.0); // x unchanged
3868            }
3869
3870            #[test]
3871            fn real_copy_with_arithmetic() {
3872                let a = RealNative64StrictFinite::try_new(2.0).unwrap();
3873                let b = RealNative64StrictFinite::try_new(3.0).unwrap();
3874
3875                // All of these use copies of a and b
3876                let sum = a + b;
3877                let diff = a - b;
3878                let prod = a * b;
3879                let quot = a / b;
3880
3881                // a and b still valid
3882                assert_eq!(*a.as_ref(), 2.0);
3883                assert_eq!(*b.as_ref(), 3.0);
3884                assert_eq!(*sum.as_ref(), 5.0);
3885                assert_eq!(*diff.as_ref(), -1.0);
3886                assert_eq!(*prod.as_ref(), 6.0);
3887                assert!((quot.as_ref() - 2.0 / 3.0).abs() < 1e-10);
3888            }
3889        }
3890
3891        mod complex_copy {
3892            use super::*;
3893
3894            #[test]
3895            fn complex_is_copy() {
3896                // Verify ComplexNative64StrictFinite is Copy
3897                fn assert_copy<T: Copy>() {}
3898                assert_copy::<ComplexNative64StrictFinite>();
3899                assert_copy::<ComplexNative64StrictFiniteInDebug>();
3900            }
3901
3902            #[test]
3903            fn complex_copy_semantics() {
3904                let z = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
3905                let w = z; // Copy, not move
3906                let v = z; // z is still valid because it was copied
3907                assert_eq!(z, w);
3908                assert_eq!(z, v);
3909            }
3910
3911            #[test]
3912            fn complex_copy_in_function_call() {
3913                fn takes_by_value(val: ComplexNative64StrictFinite) -> Complex<f64> {
3914                    val.into_inner()
3915                }
3916
3917                let z = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
3918                let result1 = takes_by_value(z);
3919                let result2 = takes_by_value(z); // z is still valid after first call
3920                assert_eq!(result1, Complex::new(3.0, 4.0));
3921                assert_eq!(result2, Complex::new(3.0, 4.0));
3922            }
3923
3924            #[test]
3925            fn complex_copy_with_arithmetic() {
3926                let a = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 2.0)).unwrap();
3927                let b = ComplexNative64StrictFinite::try_new(Complex::new(3.0, 4.0)).unwrap();
3928
3929                // All of these use copies of a and b
3930                let sum = a + b;
3931                let diff = a - b;
3932                let prod = a * b;
3933
3934                // a and b still valid
3935                assert_eq!(a.into_inner(), Complex::new(1.0, 2.0));
3936                assert_eq!(b.into_inner(), Complex::new(3.0, 4.0));
3937                assert_eq!(sum.into_inner(), Complex::new(4.0, 6.0));
3938                assert_eq!(diff.into_inner(), Complex::new(-2.0, -2.0));
3939                // (1+2i)(3+4i) = 3 + 4i + 6i + 8i² = 3 + 10i - 8 = -5 + 10i
3940                assert_eq!(prod.into_inner(), Complex::new(-5.0, 10.0));
3941            }
3942
3943            #[test]
3944            fn complex_copy_in_loop() {
3945                let z = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 1.0)).unwrap();
3946                let mut sum = ComplexNative64StrictFinite::zero();
3947
3948                for _ in 0..3 {
3949                    sum += z; // z is copied each iteration
3950                }
3951
3952                assert_eq!(sum.into_inner(), Complex::new(3.0, 3.0));
3953                assert_eq!(z.into_inner(), Complex::new(1.0, 1.0)); // z unchanged
3954            }
3955        }
3956
3957        mod mixed_copy {
3958            use super::*;
3959
3960            #[test]
3961            fn real_and_complex_copy_in_expression() {
3962                let r = RealNative64StrictFinite::try_new(2.0).unwrap();
3963                let z = ComplexNative64StrictFinite::try_new(Complex::new(1.0, 1.0)).unwrap();
3964
3965                // Complex * Real uses copies
3966                let result1 = z * r;
3967                let result2 = z * r;
3968
3969                // Both still valid
3970                assert_eq!(*r.as_ref(), 2.0);
3971                assert_eq!(z.into_inner(), Complex::new(1.0, 1.0));
3972                assert_eq!(result1.into_inner(), Complex::new(2.0, 2.0));
3973                assert_eq!(result2.into_inner(), Complex::new(2.0, 2.0));
3974            }
3975        }
3976    }
3977}