Skip to main content

num_valid/backends/rug/
validated.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3//! # Validated Arbitrary-Precision Types
4//!
5//! This module provides validated wrapper types for arbitrary-precision arithmetic using
6//! the [`rug`](https://docs.rs/rug/) library, which wraps GNU MPFR.
7//!
8//! ## Overview
9//!
10//! The types in this module combine the power of arbitrary-precision arithmetic with
11//! the safety guarantees of [`num-valid`](crate)'s validation system. All values are
12//! guaranteed to be finite and have the correct precision.
13//!
14//! ## Core Types
15//!
16//! - `RugStrictFinite<PRECISION>`: Kernel configuration for arbitrary-precision with strict validation
17//! - `RealRugStrictFinite<PRECISION>`: Validated arbitrary-precision real numbers
18//! - `ComplexRugStrictFinite<PRECISION>`: Validated arbitrary-precision complex numbers
19//!
20//! ## Precision
21//!
22//! Precision is specified as a const generic parameter representing the number of bits
23//! in the significand:
24//!
25//! - `53` bits: Equivalent to `f64` precision
26//! - `100` bits: ~30 decimal digits
27//! - `200` bits: ~60 decimal digits
28//!
29//! ## Example
30//!
31//! ```rust
32//! use num_valid::{RealRugStrictFinite, functions::Sqrt};
33//! use rug::Float;
34//! use try_create::TryNew;
35//!
36//! const PRECISION: u32 = 100;
37//!
38//! // Create a validated value from a rug::Float
39//! let x = RealRugStrictFinite::<PRECISION>::try_new(
40//!     Float::with_val(PRECISION, 2.0)
41//! ).unwrap();
42//!
43//! // Mathematical operations are available
44//! let sqrt_x = x.sqrt();
45//! ```
46//!
47//! ## Memory Considerations
48//!
49//! Unlike the native `f64` backend, `rug` types are heap-allocated and do **not** implement
50//! `Copy`. Use references where possible to avoid unnecessary cloning.
51
52use crate::{
53    ComplexScalarGetParts, Constants, RealScalar, ScalarCore,
54    core::errors::{ErrorsValidationRawComplex, RawRealConversionError},
55    kernels::{ComplexValidated, NumKernelStrictFinite, RealValidated},
56    scalars::{AbsoluteTolerance, NonNegativeRealScalar},
57};
58use num::Complex;
59use rug::ops::CompleteRound;
60use std::marker::PhantomData;
61use try_create::{IntoInner, TryNew};
62
63//------------------------------------------------------------------------------------------------------------
64/// A type alias for a numerical kernel that uses `rug` for arbitrary-precision arithmetic with strict finiteness checks.
65///
66/// This policy is a specialization of [`NumKernelStrictFinite`] for the `rug` backend.
67/// It bundles the raw `rug` types ([`rug::Float`] and [`rug::Complex`]) with their corresponding
68/// validation logic, [`StrictFinitePolicy`](crate::core::policies::StrictFinitePolicy).
69///
70/// The primary role of this policy is to serve as the generic parameter for the main validated
71/// types, [`RealRugStrictFinite<PRECISION>`] and [`ComplexRugStrictFinite<PRECISION>`], thereby
72/// defining their behavior and ensuring their correctness.
73///
74/// # Validation
75///
76/// This policy enforces the following rules on the underlying [`rug::Float`] values, for both
77/// real numbers and the components of complex numbers:
78///
79/// 1.  **Finiteness**: The value must not be `NaN` or `Infinity`.
80/// 2.  **Precision**: The precision of the [`rug::Float`] must exactly match the `PRECISION`
81///     constant specified in the type. This is a critical check for `rug` types.
82///
83/// # Example
84///
85/// While you typically won't use `RugStrictFinite` directly, it's the engine that
86/// powers the validated `rug` types.
87///
88/// ```rust
89/// use num_valid::{RealRugStrictFinite, ComplexRugStrictFinite};
90/// use rug::{Float, Complex};
91/// use try_create::TryNew;
92///
93/// const PRECISION: u32 = 100;
94///
95/// // This works because the value is finite and has the correct precision.
96/// let valid_real = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.14)).unwrap();
97///
98/// // This fails because the precision is wrong.
99/// let wrong_precision_real = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION + 1, 3.14));
100/// assert!(wrong_precision_real.is_err());
101///
102/// // This fails because the value is NaN.
103/// let nan_real = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, f64::NAN));
104/// assert!(nan_real.is_err());
105///
106/// // The same rules apply to complex numbers.
107/// let valid_complex = ComplexRugStrictFinite::<PRECISION>::try_new(
108///     Complex::with_val(PRECISION, (1.0, 2.0))
109/// ).unwrap();
110///
111/// let invalid_complex = ComplexRugStrictFinite::<PRECISION>::try_new(
112///     Complex::with_val(PRECISION, (1.0, f64::INFINITY))
113/// );
114/// assert!(invalid_complex.is_err());
115/// ```
116pub type RugStrictFinite<const PRECISION: u32> = NumKernelStrictFinite<rug::Float, PRECISION>;
117//------------------------------------------------------------------------------------------------------------
118
119//------------------------------------------------------------------------------------------------------------
120/// A type alias for a validated real scalar using the `Rug` kernel with a specified precision and the `NumKernelStrictFinite` validation policy.
121pub type RealRugStrictFinite<const PRECISION: u32> = RealValidated<RugStrictFinite<PRECISION>>;
122
123/// A type alias for a validated complex scalar using the `Rug` kernel with a specified precision and the `NumKernelStrictFinite` validation policy.
124pub type ComplexRugStrictFinite<const PRECISION: u32> =
125    ComplexValidated<RugStrictFinite<PRECISION>>;
126
127//------------------------------------------------------------------------------------------------------------
128
129//-------------------------------------------------------------
130impl<const PRECISION: u32> TryFrom<Complex<f64>> for ComplexRugStrictFinite<PRECISION> {
131    type Error = ErrorsValidationRawComplex<RawRealConversionError<f64, rug::Float>>;
132
133    fn try_from(value: Complex<f64>) -> Result<Self, Self::Error> {
134        let real_part = RealRugStrictFinite::<PRECISION>::try_from_f64(value.re);
135        let imag_part = RealRugStrictFinite::<PRECISION>::try_from_f64(value.im);
136
137        match (real_part, imag_part) {
138            (Ok(real_part), Ok(imag_part)) => Ok(Self {
139                value: rug::Complex::with_val(
140                    PRECISION,
141                    (real_part.into_inner(), imag_part.into_inner()),
142                ),
143                _phantom: PhantomData,
144            }),
145            (Err(error_real_part), Ok(_)) => Err(ErrorsValidationRawComplex::InvalidRealPart {
146                source: Box::new(error_real_part),
147            }),
148            (Ok(_), Err(error_imaginary_part)) => {
149                Err(ErrorsValidationRawComplex::InvalidImaginaryPart {
150                    source: Box::new(error_imaginary_part),
151                })
152            }
153            (Err(error_real_part), Err(error_imaginary_part)) => {
154                Err(ErrorsValidationRawComplex::InvalidBothParts {
155                    real_error: Box::new(error_real_part),
156                    imag_error: Box::new(error_imaginary_part),
157                })
158            }
159        }
160    }
161}
162//------------------------------------------------------------------------------------------------
163
164//------------------------------------------------------------------------------------------------
165// Approx trait implementations for rug-backed validated types
166//
167// Since `rug::Float` and `rug::Complex` do not implement the `approx` crate traits,
168// we provide manual implementations for `RealRugStrictFinite<P>` and `ComplexRugStrictFinite<P>`.
169// These implementations use the kernel's `epsilon()` as the default epsilon value.
170//
171// # Note on UlpsEq
172//
173// `UlpsEq` (Units in Last Place) is not implemented for rug types because:
174// 1. Arbitrary-precision floats don't have a fixed-size mantissa
175// 2. The concept of ULP is tied to IEEE 754 binary representation
176// 3. For arbitrary precision, `AbsDiffEq` and `RelativeEq` are more appropriate
177//------------------------------------------------------------------------------------------------
178
179impl<const PRECISION: u32> approx::AbsDiffEq for RealRugStrictFinite<PRECISION> {
180    type Epsilon = AbsoluteTolerance<Self>;
181
182    /// Returns the machine epsilon for the given precision.
183    ///
184    /// For `rug::Float`, this is 2^(1-PRECISION), which represents the
185    /// smallest difference between 1.0 and the next representable value.
186    #[inline]
187    fn default_epsilon() -> Self::Epsilon {
188        AbsoluteTolerance::epsilon()
189    }
190
191    /// Compares two values for approximate equality using absolute difference.
192    ///
193    /// Returns `true` if `|self - other| <= epsilon`.
194    #[inline]
195    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
196        let diff = (self.as_raw_scalar_ref() - other.as_raw_scalar_ref()).complete(PRECISION);
197        diff.abs() <= *epsilon.as_raw_scalar_ref()
198    }
199}
200
201impl<const PRECISION: u32> approx::RelativeEq for RealRugStrictFinite<PRECISION> {
202    /// Returns a reasonable default for relative comparisons.
203    ///
204    /// Uses `epsilon() * 8` as a default, allowing for a few ULPs of error.
205    #[inline]
206    fn default_max_relative() -> Self::Epsilon {
207        let eps = Self::epsilon();
208        // Allow for approximately 3 bits of error (8 = 2^3)
209        let eight = rug::Float::with_val(PRECISION, 8);
210        let scaled = NonNegativeRealScalar::new(
211            Self::try_new(eps.into_inner() * eight)
212                .expect("default_max_relative: validation failed unexpectedly"),
213        );
214        AbsoluteTolerance::new(scaled)
215    }
216
217    /// Compares two values for approximate equality using relative difference.
218    ///
219    /// Returns `true` if `|self - other| <= max(epsilon, max_relative * max(|self|, |other|))`.
220    #[inline]
221    fn relative_eq(
222        &self,
223        other: &Self,
224        epsilon: Self::Epsilon,
225        max_relative: Self::Epsilon,
226    ) -> bool {
227        let diff = (self.as_raw_scalar_ref() - other.as_raw_scalar_ref())
228            .complete(PRECISION)
229            .abs();
230
231        if diff <= *epsilon.as_raw_scalar_ref() {
232            return true;
233        }
234
235        let abs_self = self.as_raw_scalar_ref().clone().abs();
236        let abs_other = other.as_raw_scalar_ref().clone().abs();
237        let largest = if abs_self > abs_other {
238            abs_self
239        } else {
240            abs_other
241        };
242
243        diff <= (max_relative.as_raw_scalar_ref() * &largest).complete(PRECISION)
244    }
245}
246
247impl<const PRECISION: u32> approx::AbsDiffEq for ComplexRugStrictFinite<PRECISION> {
248    type Epsilon = AbsoluteTolerance<RealRugStrictFinite<PRECISION>>;
249
250    /// Returns the machine epsilon for the given precision.
251    #[inline]
252    fn default_epsilon() -> Self::Epsilon {
253        AbsoluteTolerance::epsilon()
254    }
255
256    /// Compares two complex values for approximate equality using absolute difference.
257    ///
258    /// Returns `true` if both real and imaginary parts satisfy `|a - b| <= epsilon`.
259    #[inline]
260    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
261        let real_diff = (self.raw_real_part() - other.raw_real_part()).complete(PRECISION);
262        let imag_diff = (self.raw_imag_part() - other.raw_imag_part()).complete(PRECISION);
263        let eps = epsilon.as_raw_scalar_ref();
264
265        real_diff.abs() <= *eps && imag_diff.abs() <= *eps
266    }
267}
268
269impl<const PRECISION: u32> approx::RelativeEq for ComplexRugStrictFinite<PRECISION> {
270    /// Returns a reasonable default for relative comparisons.
271    #[inline]
272    fn default_max_relative() -> Self::Epsilon {
273        RealRugStrictFinite::<PRECISION>::default_max_relative()
274    }
275
276    /// Compares two complex values for approximate equality using relative difference.
277    ///
278    /// Checks that both real and imaginary parts are relatively equal.
279    #[inline]
280    fn relative_eq(
281        &self,
282        other: &Self,
283        epsilon: Self::Epsilon,
284        max_relative: Self::Epsilon,
285    ) -> bool {
286        // Compare real parts
287        let real_self = self.real_part();
288        let real_other = other.real_part();
289        if !real_self.relative_eq(&real_other, epsilon.clone(), max_relative.clone()) {
290            return false;
291        }
292
293        // Compare imaginary parts
294        let imag_self = self.imag_part();
295        let imag_other = other.imag_part();
296        imag_self.relative_eq(&imag_other, epsilon, max_relative)
297    }
298}
299//------------------------------------------------------------------------------------------------
300
301#[cfg(test)]
302mod approx_tests {
303    use super::*;
304    use crate::scalars::AbsoluteTolerance;
305    use approx::{AbsDiffEq, assert_abs_diff_eq, assert_abs_diff_ne, assert_relative_eq};
306    use rug::Float;
307    use try_create::TryNew;
308
309    const PRECISION: u32 = 100;
310
311    mod real_rug {
312        use super::*;
313
314        #[test]
315        fn abs_diff_eq_equal_values() {
316            let a =
317                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
318            let b =
319                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
320            assert_abs_diff_eq!(a, b);
321        }
322
323        #[test]
324        fn abs_diff_eq_close_values() {
325            let a =
326                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
327            // Add a very small difference
328            let mut b_val = Float::with_val(PRECISION, 1.0);
329            b_val += Float::with_val(PRECISION, 1e-25);
330            let b = RealRugStrictFinite::<PRECISION>::try_new(b_val).unwrap();
331
332            // Should be equal with a tolerance larger than 1e-25
333            let eps_val = NonNegativeRealScalar::new(
334                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1e-20))
335                    .unwrap(),
336            );
337            let eps = AbsoluteTolerance::new(eps_val);
338            assert_abs_diff_eq!(a, b, epsilon = eps);
339        }
340
341        #[test]
342        fn abs_diff_ne_different_values() {
343            let a =
344                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
345            let b =
346                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 2.0)).unwrap();
347            assert_abs_diff_ne!(a, b);
348        }
349
350        #[test]
351        fn default_epsilon_is_machine_epsilon() {
352            let eps = RealRugStrictFinite::<PRECISION>::default_epsilon();
353            // Machine epsilon for 100-bit precision is 2^(1-100) = 2^(-99)
354            let expected = AbsoluteTolerance::new(NonNegativeRealScalar::new(
355                RealRugStrictFinite::<PRECISION>::epsilon(),
356            ));
357            assert_eq!(*eps.as_raw_scalar_ref(), *expected.as_raw_scalar_ref());
358        }
359
360        #[test]
361        fn relative_eq_close_values() {
362            let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 100.0))
363                .unwrap();
364            // Use a value within the default relative tolerance (epsilon * 8)
365            let eps = RealRugStrictFinite::<PRECISION>::epsilon();
366            let mut b_val = Float::with_val(PRECISION, 100.0);
367            // Add a tiny relative difference (much smaller than eps * 8)
368            b_val += eps.as_raw_scalar_ref();
369            let b = RealRugStrictFinite::<PRECISION>::try_new(b_val).unwrap();
370            assert_relative_eq!(a, b);
371        }
372
373        #[test]
374        fn relative_eq_with_custom_tolerance() {
375            let a =
376                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
377            let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.001))
378                .unwrap();
379            let max_rel_val = NonNegativeRealScalar::new(
380                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.01))
381                    .unwrap(),
382            );
383            let max_rel = AbsoluteTolerance::new(max_rel_val);
384            let eps = RealRugStrictFinite::<PRECISION>::default_epsilon();
385            assert_relative_eq!(a, b, epsilon = eps, max_relative = max_rel);
386        }
387    }
388
389    mod complex_rug {
390        use super::*;
391
392        #[test]
393        fn abs_diff_eq_equal_values() {
394            let a = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
395                PRECISION,
396                (
397                    Float::with_val(PRECISION, 1.0),
398                    Float::with_val(PRECISION, 2.0),
399                ),
400            ))
401            .unwrap();
402            let b = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
403                PRECISION,
404                (
405                    Float::with_val(PRECISION, 1.0),
406                    Float::with_val(PRECISION, 2.0),
407                ),
408            ))
409            .unwrap();
410            assert_abs_diff_eq!(a, b);
411        }
412
413        #[test]
414        fn abs_diff_eq_close_values() {
415            let a = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
416                PRECISION,
417                (
418                    Float::with_val(PRECISION, 1.0),
419                    Float::with_val(PRECISION, 2.0),
420                ),
421            ))
422            .unwrap();
423            let b = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
424                PRECISION,
425                (
426                    Float::with_val(PRECISION, 1.0) + Float::with_val(PRECISION, 1e-25),
427                    Float::with_val(PRECISION, 2.0) + Float::with_val(PRECISION, 1e-25),
428                ),
429            ))
430            .unwrap();
431            let eps_val = NonNegativeRealScalar::new(
432                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1e-20))
433                    .unwrap(),
434            );
435            let eps = AbsoluteTolerance::new(eps_val);
436            assert_abs_diff_eq!(a, b, epsilon = eps);
437        }
438
439        #[test]
440        fn abs_diff_ne_different_values() {
441            let a = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
442                PRECISION,
443                (
444                    Float::with_val(PRECISION, 1.0),
445                    Float::with_val(PRECISION, 2.0),
446                ),
447            ))
448            .unwrap();
449            let b = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
450                PRECISION,
451                (
452                    Float::with_val(PRECISION, 3.0),
453                    Float::with_val(PRECISION, 4.0),
454                ),
455            ))
456            .unwrap();
457            assert_abs_diff_ne!(a, b);
458        }
459
460        #[test]
461        fn relative_eq_close_values() {
462            let a = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
463                PRECISION,
464                (
465                    Float::with_val(PRECISION, 100.0),
466                    Float::with_val(PRECISION, 200.0),
467                ),
468            ))
469            .unwrap();
470            // Use values within the default relative tolerance
471            let eps = RealRugStrictFinite::<PRECISION>::epsilon();
472            let b = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
473                PRECISION,
474                (
475                    Float::with_val(PRECISION, 100.0) + eps.as_raw_scalar_ref(),
476                    Float::with_val(PRECISION, 200.0) + eps.as_raw_scalar_ref(),
477                ),
478            ))
479            .unwrap();
480            assert_relative_eq!(a, b);
481        }
482    }
483}
484
485#[cfg(test)]
486mod tests {
487    use super::*;
488    use crate::{
489        ComplexRugStrictFinite, ComplexScalarConstructors, ComplexScalarGetParts,
490        ComplexScalarMutateParts, ComplexScalarSetParts, Constants, Max, Min, RawRealTrait,
491        core::{
492            errors::{ErrorsRawRealToInteger, ErrorsValidationRawReal, RawRealConversionError},
493            traits::validation::FpChecks,
494        },
495        functions::{
496            ACos, ACosH, ACosHErrors, ACosHInputErrors, ACosRealErrors, ACosRealInputErrors, ASin,
497            ASinRealErrors, ASinRealInputErrors, ATan, ATan2, ATan2Errors, ATanComplexErrors,
498            ATanComplexInputErrors, ATanH, ATanHErrors, ATanHInputErrors, Abs, Clamp, Exp,
499            ExpErrors, Hypot, Ln, Log2, LogarithmComplexErrors, LogarithmComplexInputErrors,
500            NegAssign, Pow, PowComplexBaseRealExponentErrors, PowIntExponentErrors,
501            PowIntExponentInputErrors, PowRealBaseRealExponentErrors, Reciprocal, ReciprocalErrors,
502            Sign, Sqrt, SqrtRealErrors, TotalCmp,
503        },
504    };
505    use num::{One, Zero};
506    use rug::{Float, float::Constant as MpfrConstant, ops::Pow as RugPow};
507    use std::{assert_matches, cmp::Ordering, ops::Neg};
508    use try_create::TryNew;
509
510    const PRECISION: u32 = 53;
511
512    mod fp_checks {
513        use super::*;
514        use rug::Float;
515
516        #[test]
517        fn is_finite() {
518            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
519            assert!(real.is_finite());
520
521            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::INFINITY));
522            assert!(real.is_err());
523
524            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
525                53,
526                (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
527            ))
528            .unwrap();
529            assert!(complex.is_finite());
530
531            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
532                53,
533                (Float::with_val(53, f64::INFINITY), Float::with_val(53, 1.0)),
534            ));
535            assert!(complex.is_err());
536        }
537
538        #[test]
539        fn is_infinite() {
540            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
541            assert!(!real.is_infinite());
542
543            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::INFINITY));
544            assert!(real.is_err());
545
546            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
547                53,
548                (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
549            ))
550            .unwrap();
551            assert!(!complex.is_infinite());
552
553            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
554                53,
555                (Float::with_val(53, f64::INFINITY), Float::with_val(53, 1.0)),
556            ));
557            assert!(complex.is_err());
558        }
559
560        #[test]
561        fn is_nan() {
562            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
563            assert!(!real.is_nan());
564
565            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::NAN));
566            assert!(matches!(real, Err(ErrorsValidationRawReal::IsNaN { .. })));
567
568            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
569                53,
570                (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
571            ))
572            .unwrap();
573            assert!(!complex.is_nan());
574
575            let err = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
576                53,
577                (Float::with_val(53, f64::NAN), Float::with_val(53, 1.0)),
578            ))
579            .unwrap_err();
580            assert_matches!(
581                err,
582                ErrorsValidationRawComplex::InvalidRealPart {
583                    source
584                } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
585            );
586        }
587
588        #[test]
589        fn is_normal() {
590            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
591            assert!(real.is_normal());
592
593            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
594            assert!(!real.is_normal());
595
596            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
597                53,
598                (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
599            ))
600            .unwrap();
601            assert!(complex.is_normal());
602
603            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
604                53,
605                (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
606            ))
607            .unwrap();
608            assert!(!complex.is_normal());
609        }
610    }
611
612    mod abs {
613        use super::*;
614
615        mod real {
616            use super::*;
617
618            #[test]
619            fn abs_valid() {
620                let value =
621                    RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, -4.0)).unwrap();
622
623                let expected_result =
624                    RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 4.0)).unwrap();
625                assert_eq!(
626                    value.clone().try_abs().unwrap().into_inner(),
627                    expected_result
628                );
629                assert_eq!(value.abs().into_inner(), expected_result);
630            }
631
632            #[test]
633            fn abs_zero() {
634                let value =
635                    RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
636
637                let expected_result =
638                    RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
639                assert_eq!(
640                    value.clone().try_abs().unwrap().into_inner(),
641                    expected_result
642                );
643                assert_eq!(value.abs().into_inner(), expected_result);
644            }
645
646            /*
647            #[cfg(feature = "rug")]
648            #[test]
649            fn abs_nan() {
650                let value =
651                    RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, rug::float::Special::Nan))
652                        .unwrap();
653                let result = value.try_abs();
654                assert!(matches!(result, Err(AbsRealErrors::Input(..))));
655            }
656
657            #[cfg(feature = "rug")]
658            #[test]
659            fn abs_infinite() {
660                let value = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
661                    53,
662                    rug::float::Special::Infinity,
663                ))
664                .unwrap();
665                let result = value.try_abs();
666                assert!(matches!(result, Err(AbsRealErrors::Input(..))));
667            }
668            */
669        }
670
671        mod complex {
672            use super::*;
673
674            #[test]
675            fn abs_valid() {
676                let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
677                    53,
678                    (rug::Float::with_val(53, 3.0), rug::Float::with_val(53, 4.0)),
679                ))
680                .unwrap();
681
682                let expected_result =
683                    RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 5.0)).unwrap();
684                assert_eq!(
685                    value.clone().try_abs().unwrap().into_inner(),
686                    expected_result
687                );
688                assert_eq!(value.abs().into_inner(), expected_result);
689            }
690
691            #[test]
692            fn abs_zero() {
693                let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
694                    53,
695                    (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
696                ))
697                .unwrap();
698
699                let expected_result =
700                    RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
701                assert_eq!(
702                    value.clone().try_abs().unwrap().into_inner(),
703                    expected_result
704                );
705                assert_eq!(value.abs().into_inner(), expected_result);
706            }
707            /*
708            #[test]
709            fn abs_nan() {
710                let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
711                    53,
712                    (
713                        rug::Float::with_val(53, rug::float::Special::Nan),
714                        rug::Float::with_val(53, 0.0),
715                    ),
716                ))
717                .unwrap();
718                assert!(matches!(
719                    value.try_abs(),
720                    Err(AbsComplexErrors::Input(..))
721                ));
722            }
723
724            #[test]
725            fn abs_infinite() {
726                let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
727                    53,
728                    (
729                        rug::Float::with_val(53, rug::float::Special::Infinity),
730                        rug::Float::with_val(53, 0.0),
731                    ),
732                ))
733                .unwrap();
734                assert!(matches!(
735                    value.try_abs(),
736                    Err(AbsComplexErrors::Input(..))
737                ));
738            }
739            */
740        }
741    }
742
743    mod max_min {
744        use super::*;
745
746        #[test]
747        fn test_realrug_max() {
748            let value =
749                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
750            let other =
751                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
752            let expected =
753                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
754            assert_eq!(Max::max_by_ref(&value, &other), &expected);
755
756            let neg_value =
757                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
758                    .unwrap();
759            let neg_other =
760                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
761                    .unwrap();
762            let neg_expected =
763                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
764                    .unwrap();
765            assert_eq!(Max::max_by_ref(&neg_value, &neg_other), &neg_expected);
766        }
767
768        #[test]
769        fn test_realrug_min() {
770            let value =
771                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
772            let other =
773                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
774            let expected =
775                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
776            assert_eq!(Min::min_by_ref(&value, &other), &expected);
777
778            let neg_value =
779                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
780                    .unwrap();
781            let neg_other =
782                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
783                    .unwrap();
784            let neg_expected =
785                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
786                    .unwrap();
787            assert_eq!(Min::min_by_ref(&neg_value, &neg_other), &neg_expected);
788        }
789    }
790
791    mod builders {
792        use super::*;
793
794        mod real {
795            use super::*;
796
797            #[test]
798            fn try_new_nan() {
799                let nan = rug::Float::with_val(PRECISION, f64::NAN);
800                let err = RealRugStrictFinite::<PRECISION>::try_new(nan).unwrap_err();
801                assert!(matches!(err, ErrorsValidationRawReal::IsNaN { .. }));
802            }
803
804            #[test]
805            fn try_new_pos_infinity() {
806                let pos_infinity = rug::Float::with_val(PRECISION, f64::INFINITY);
807                let err = RealRugStrictFinite::<PRECISION>::try_new(pos_infinity).unwrap_err();
808                assert!(matches!(err, ErrorsValidationRawReal::IsPosInfinity { .. }));
809            }
810
811            #[test]
812            fn try_new_neg_infinity() {
813                let neg_infinity = rug::Float::with_val(PRECISION, f64::NEG_INFINITY);
814                let err = RealRugStrictFinite::<PRECISION>::try_new(neg_infinity).unwrap_err();
815                assert!(matches!(err, ErrorsValidationRawReal::IsNegInfinity { .. }));
816            }
817        }
818
819        mod complex {
820            use super::*;
821
822            #[test]
823            fn real_part() {
824                let c1 = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
825                    PRECISION,
826                    (1.23, 4.56),
827                ))
828                .unwrap();
829                assert_eq!(c1.real_part().as_raw_scalar_ref(), &1.23);
830
831                let c2 = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
832                    PRECISION,
833                    (-7.89, 0.12),
834                ))
835                .unwrap();
836                assert_eq!(c2.real_part().as_raw_scalar_ref(), &-7.89);
837
838                let c3 = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
839                    PRECISION,
840                    (0.0, 10.0),
841                ))
842                .unwrap();
843                assert_eq!(c3.real_part().as_raw_scalar_ref(), &0.0);
844
845                let c_nan_re = ComplexRugStrictFinite::<PRECISION>::try_new(
846                    rug::Complex::with_val(PRECISION, (f64::NAN, 5.0)),
847                )
848                .unwrap_err();
849                assert_matches!(
850                    c_nan_re,
851                    ErrorsValidationRawComplex::InvalidRealPart {
852                        source
853                    } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
854                );
855
856                let c_inf_re = ComplexRugStrictFinite::<PRECISION>::try_new(
857                    rug::Complex::with_val(PRECISION, (f64::INFINITY, 5.0)),
858                )
859                .unwrap_err();
860                assert_matches!(
861                    c_inf_re,
862                    ErrorsValidationRawComplex::InvalidRealPart {
863                        source
864                    } if matches!(*source, ErrorsValidationRawReal::IsPosInfinity { .. })
865                );
866
867                let c_neg_inf_re = ComplexRugStrictFinite::<PRECISION>::try_new(
868                    rug::Complex::with_val(PRECISION, (f64::NEG_INFINITY, 5.0)),
869                )
870                .unwrap_err();
871                assert_matches!(
872                    c_neg_inf_re,
873                    ErrorsValidationRawComplex::InvalidRealPart {
874                        source
875                    } if matches!(*source, ErrorsValidationRawReal::IsNegInfinity { .. })
876                );
877            }
878
879            #[test]
880            fn imag_part() {
881                let c1 = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
882                    PRECISION,
883                    (1.23, 4.56),
884                ))
885                .unwrap();
886                assert_eq!(c1.imag_part().as_raw_scalar_ref(), &4.56);
887
888                let c2 = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
889                    PRECISION,
890                    (-7.89, 0.12),
891                ))
892                .unwrap();
893                assert_eq!(c2.imag_part().as_raw_scalar_ref(), &0.12);
894
895                let c3 = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
896                    PRECISION,
897                    (10.0, 0.0),
898                ))
899                .unwrap();
900                assert_eq!(c3.imag_part().as_raw_scalar_ref(), &0.0);
901
902                let c_nan_im = ComplexRugStrictFinite::<PRECISION>::try_new(
903                    rug::Complex::with_val(PRECISION, (5.0, f64::NAN)),
904                )
905                .unwrap_err();
906                assert_matches!(
907                    c_nan_im,
908                    ErrorsValidationRawComplex::InvalidImaginaryPart {
909                        source
910                    } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
911                );
912
913                let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new(
914                    rug::Complex::with_val(PRECISION, (5.0, f64::INFINITY)),
915                )
916                .unwrap_err();
917                assert_matches!(
918                    c_inf_im,
919                    ErrorsValidationRawComplex::InvalidImaginaryPart {
920                        source
921                    } if matches!(*source, ErrorsValidationRawReal::IsPosInfinity { .. })
922                );
923
924                let c_neg_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new(
925                    rug::Complex::with_val(PRECISION, (5.0, f64::NEG_INFINITY)),
926                )
927                .unwrap_err();
928                assert_matches!(
929                    c_neg_inf_im,
930                    ErrorsValidationRawComplex::InvalidImaginaryPart {
931                        source
932                    } if matches!(*source, ErrorsValidationRawReal::IsNegInfinity { .. })
933                );
934            }
935
936            #[test]
937            fn try_new_complex() {
938                let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
939                let i1 = RealRugStrictFinite::<PRECISION>::try_from_f64(4.56).unwrap();
940                let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
941                    r1.as_raw_scalar_ref().clone(),
942                    i1.as_raw_scalar_ref().clone(),
943                )
944                .unwrap();
945                assert_eq!(c1.real_part(), r1);
946                assert_eq!(c1.imag_part(), i1);
947
948                let r2 = RealRugStrictFinite::<PRECISION>::try_from_f64(-7.89).unwrap();
949                let i2 = RealRugStrictFinite::<PRECISION>::try_from_f64(-0.12).unwrap();
950                let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
951                    r2.as_raw_scalar_ref().clone(),
952                    i2.as_raw_scalar_ref().clone(),
953                )
954                .unwrap();
955                assert_eq!(c2.real_part(), r2);
956                assert_eq!(c2.imag_part(), i2);
957
958                let r3 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
959                let i3 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
960                let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
961                    r3.as_raw_scalar_ref().clone(),
962                    i3.as_raw_scalar_ref().clone(),
963                )
964                .unwrap();
965                assert_eq!(c3.real_part(), r3);
966                assert_eq!(c3.real_part(), i3);
967                assert!(c3.is_zero());
968
969                let c_nan_re = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
970                    Float::with_val(PRECISION, f64::NAN),
971                    Float::with_val(PRECISION, 5.0),
972                )
973                .unwrap_err();
974                assert!(matches!(
975                    c_nan_re,
976                    ErrorsValidationRawComplex::InvalidRealPart { .. }
977                ));
978
979                let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
980                    Float::with_val(PRECISION, 10.0),
981                    Float::with_val(PRECISION, f64::INFINITY),
982                )
983                .unwrap_err();
984                assert!(matches!(
985                    c_inf_im,
986                    ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
987                ));
988
989                let c_nan_re_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
990                    Float::with_val(PRECISION, f64::NAN),
991                    Float::with_val(PRECISION, f64::INFINITY),
992                )
993                .unwrap_err();
994                assert!(matches!(
995                    c_nan_re_inf_im,
996                    ErrorsValidationRawComplex::InvalidBothParts { .. }
997                ));
998            }
999
1000            #[test]
1001            fn try_from_complexf64() {
1002                let c1_in = num::Complex::new(1.23, 4.56);
1003                let c1 = ComplexRugStrictFinite::<PRECISION>::try_from(c1_in).unwrap();
1004                assert_eq!(c1.real_part().as_raw_scalar_ref(), &c1_in.re);
1005                assert_eq!(c1.imag_part().as_raw_scalar_ref(), &c1_in.im);
1006
1007                let c2_in = num::Complex::new(-7.89, -0.12);
1008                let c2 = ComplexRugStrictFinite::<PRECISION>::try_from(c2_in).unwrap();
1009                assert_eq!(c2.real_part().as_raw_scalar_ref(), &c2_in.re);
1010                assert_eq!(c2.imag_part().as_raw_scalar_ref(), &c2_in.im);
1011
1012                let c3_in = num::Complex::new(0., 0.);
1013                let c3 = ComplexRugStrictFinite::<PRECISION>::try_from(c3_in).unwrap();
1014                assert_eq!(c3.real_part().as_raw_scalar_ref(), &c3_in.re);
1015                assert_eq!(c3.imag_part().as_raw_scalar_ref(), &c3_in.im);
1016
1017                let c_nan_re =
1018                    ComplexRugStrictFinite::<PRECISION>::try_from(num::Complex::new(f64::NAN, 5.0))
1019                        .unwrap_err();
1020                assert!(matches!(
1021                    c_nan_re,
1022                    ErrorsValidationRawComplex::InvalidRealPart { .. }
1023                ));
1024
1025                let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_from(num::Complex::new(
1026                    10.0,
1027                    f64::INFINITY,
1028                ))
1029                .unwrap_err();
1030                assert!(matches!(
1031                    c_inf_im,
1032                    ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
1033                ));
1034
1035                let c_nan_re_inf_im = ComplexRugStrictFinite::<PRECISION>::try_from(
1036                    num::Complex::new(f64::NAN, f64::INFINITY),
1037                )
1038                .unwrap_err();
1039                assert!(matches!(
1040                    c_nan_re_inf_im,
1041                    ErrorsValidationRawComplex::InvalidBothParts { .. }
1042                ));
1043            }
1044
1045            #[test]
1046            fn try_new_pure_real() {
1047                let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
1048                let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
1049                    r1.as_raw_scalar_ref().clone(),
1050                )
1051                .unwrap();
1052                assert_eq!(c1.real_part(), r1);
1053                assert!(c1.imag_part().is_zero());
1054
1055                let c_nan = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
1056                    Float::with_val(PRECISION, f64::NAN),
1057                )
1058                .unwrap_err();
1059                assert_matches!(
1060                    c_nan,
1061                    ErrorsValidationRawComplex::InvalidRealPart {
1062                        source
1063                    } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
1064                );
1065            }
1066
1067            #[test]
1068            fn try_new_pure_imaginary() {
1069                let i1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
1070                let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
1071                    i1.as_raw_scalar_ref().clone(),
1072                )
1073                .unwrap();
1074                assert!(c1.real_part().is_zero());
1075                assert_eq!(c1.imag_part(), i1);
1076
1077                let c_nan = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
1078                    Float::with_val(PRECISION, f64::NAN),
1079                )
1080                .unwrap_err();
1081                assert_matches!(
1082                    c_nan,
1083                    ErrorsValidationRawComplex::InvalidImaginaryPart {
1084                        source
1085                    } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
1086                );
1087            }
1088
1089            #[test]
1090            fn add_to_real_part() {
1091                let mut c = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
1092                    PRECISION,
1093                    (1.0, 2.0),
1094                ))
1095                .unwrap();
1096                c.add_to_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1097                assert_eq!(c.real_part().as_raw_scalar_ref(), &4.0);
1098                assert_eq!(c.imag_part().as_raw_scalar_ref(), &2.0);
1099
1100                c.add_to_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0).unwrap());
1101                assert_eq!(c.real_part().as_raw_scalar_ref(), &-1.0);
1102                assert_eq!(c.imag_part().as_raw_scalar_ref(), &2.0);
1103            }
1104
1105            #[test]
1106            fn add_to_imaginary_part() {
1107                let mut c = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
1108                    PRECISION,
1109                    (1.0, 2.0),
1110                ))
1111                .unwrap();
1112                c.add_to_imaginary_part(
1113                    &RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(),
1114                );
1115                assert_eq!(c.real_part().as_raw_scalar_ref(), &1.0);
1116                assert_eq!(c.imag_part().as_raw_scalar_ref(), &5.0);
1117
1118                c.add_to_imaginary_part(
1119                    &RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap(),
1120                );
1121                assert_eq!(c.real_part().as_raw_scalar_ref(), &1.0);
1122                assert_eq!(c.imag_part().as_raw_scalar_ref(), &1.0);
1123            }
1124
1125            #[test]
1126            fn multiply_real_part() {
1127                let mut c = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
1128                    PRECISION,
1129                    (1.0, 2.0),
1130                ))
1131                .unwrap();
1132                c.multiply_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1133                assert_eq!(c.real_part().as_raw_scalar_ref(), &3.0);
1134                assert_eq!(c.imag_part().as_raw_scalar_ref(), &2.0);
1135
1136                c.multiply_real_part(
1137                    &RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap(),
1138                );
1139                assert_eq!(c.real_part().as_raw_scalar_ref(), &-6.0);
1140                assert_eq!(c.imag_part().as_raw_scalar_ref(), &2.0);
1141            }
1142
1143            #[test]
1144            fn multiply_imaginary_part() {
1145                let mut c = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
1146                    PRECISION,
1147                    (1.0, 2.0),
1148                ))
1149                .unwrap();
1150                c.multiply_imaginary_part(
1151                    &RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(),
1152                );
1153                assert_eq!(c.real_part().as_raw_scalar_ref(), &1.0);
1154                assert_eq!(c.imag_part().as_raw_scalar_ref(), &6.0);
1155
1156                c.multiply_imaginary_part(
1157                    &RealRugStrictFinite::<PRECISION>::try_from_f64(-0.5).unwrap(),
1158                );
1159                assert_eq!(c.real_part().as_raw_scalar_ref(), &1.0);
1160                assert_eq!(c.imag_part().as_raw_scalar_ref(), &-3.0);
1161            }
1162
1163            #[test]
1164            fn set_real_part() {
1165                let mut c = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
1166                    PRECISION,
1167                    (1.0, 2.0),
1168                ))
1169                .unwrap();
1170                c.set_real_part(RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1171                assert_eq!(c.real_part().as_raw_scalar_ref(), &3.0);
1172                assert_eq!(c.imag_part().as_raw_scalar_ref(), &2.0);
1173
1174                c.set_real_part(RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap());
1175                assert_eq!(c.real_part().as_raw_scalar_ref(), &-4.0);
1176                assert_eq!(c.imag_part().as_raw_scalar_ref(), &2.0);
1177            }
1178
1179            #[test]
1180            fn set_imaginary_part() {
1181                let mut c = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
1182                    PRECISION,
1183                    (1.0, 2.0),
1184                ))
1185                .unwrap();
1186                c.set_imaginary_part(RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1187                assert_eq!(c.real_part().as_raw_scalar_ref(), &1.0);
1188                assert_eq!(c.imag_part().as_raw_scalar_ref(), &3.0);
1189
1190                c.set_imaginary_part(RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap());
1191                assert_eq!(c.real_part().as_raw_scalar_ref(), &1.0);
1192                assert_eq!(c.imag_part().as_raw_scalar_ref(), &-4.0);
1193            }
1194        }
1195    }
1196
1197    mod mul {
1198        use super::*;
1199
1200        mod real {
1201            use super::*;
1202
1203            #[test]
1204            fn multiply_ref() {
1205                let r1 =
1206                    RealRugStrictFinite::<PRECISION>::try_new(rug::Float::with_val(PRECISION, 3.0))
1207                        .unwrap();
1208                let r2 =
1209                    RealRugStrictFinite::<PRECISION>::try_new(rug::Float::with_val(PRECISION, 4.0))
1210                        .unwrap();
1211                let result = r1 * &r2;
1212                assert_eq!(
1213                    result,
1214                    RealRugStrictFinite::<PRECISION>::try_new(rug::Float::with_val(
1215                        PRECISION, 12.0
1216                    ))
1217                    .unwrap()
1218                );
1219            }
1220        }
1221
1222        mod complex {
1223            use super::*;
1224
1225            #[test]
1226            fn multiply_ref() {
1227                let c1 = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
1228                    PRECISION,
1229                    (1.0, 2.0),
1230                ))
1231                .unwrap();
1232                let c2 = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
1233                    PRECISION,
1234                    (3.0, 4.0),
1235                ))
1236                .unwrap();
1237                let result = c1 * &c2;
1238                assert_eq!(
1239                    result,
1240                    ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
1241                        PRECISION,
1242                        (-5.0, 10.0),
1243                    ))
1244                    .unwrap()
1245                ); // (1*3 - 2*4) + (1*4 + 2*3)i
1246            }
1247
1248            #[test]
1249            fn complex_times_real() {
1250                let r =
1251                    RealRugStrictFinite::<PRECISION>::try_new(rug::Float::with_val(PRECISION, 2.0))
1252                        .unwrap();
1253                let c = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
1254                    PRECISION,
1255                    (3.0, 4.0),
1256                ))
1257                .unwrap();
1258
1259                let result_expected = ComplexRugStrictFinite::<PRECISION>::try_new(
1260                    rug::Complex::with_val(PRECISION, (6.0, 8.0)),
1261                )
1262                .unwrap(); // 2 * (3 + 4i) = 6 + 8i
1263
1264                let result = c.clone() * &r;
1265                assert_eq!(&result, &result_expected);
1266
1267                let result = c.clone() * r.clone();
1268                assert_eq!(&result, &result_expected);
1269
1270                let mut result = c.clone();
1271                result *= &r;
1272                assert_eq!(&result, &result_expected);
1273
1274                let mut result = c.clone();
1275                result *= r;
1276                assert_eq!(&result, &result_expected);
1277            }
1278
1279            #[test]
1280            fn real_times_complex() {
1281                let r =
1282                    RealRugStrictFinite::<PRECISION>::try_new(rug::Float::with_val(PRECISION, 2.0))
1283                        .unwrap();
1284                let c = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
1285                    PRECISION,
1286                    (3.0, 4.0),
1287                ))
1288                .unwrap();
1289
1290                let result_expected = ComplexRugStrictFinite::<PRECISION>::try_new(
1291                    rug::Complex::with_val(PRECISION, (6.0, 8.0)),
1292                )
1293                .unwrap(); // 2 * (3 + 4i) = 6 + 8i
1294
1295                let result = &r * c.clone();
1296                assert_eq!(&result, &result_expected);
1297
1298                let result = r * c.clone();
1299                assert_eq!(&result, &result_expected);
1300            }
1301        }
1302    }
1303
1304    mod arithmetic {
1305        use super::*;
1306
1307        mod real {
1308            use super::*;
1309
1310            #[test]
1311            fn neg_assign() {
1312                let mut a = rug::Float::with_val(PRECISION, 1.);
1313                a.neg_assign();
1314                let a_expected = rug::Float::with_val(PRECISION, -1.);
1315                assert_eq!(a, a_expected);
1316
1317                let mut b = RealRugStrictFinite::<PRECISION>::one();
1318                b.neg_assign();
1319                let b_expected =
1320                    RealRugStrictFinite::<PRECISION>::try_new(rug::Float::with_val(PRECISION, -1.))
1321                        .unwrap();
1322                assert_eq!(&b, &b_expected);
1323            }
1324
1325            #[test]
1326            #[should_panic(expected = "Division failed validation")]
1327            fn div_by_zero() {
1328                let one = RealRugStrictFinite::<PRECISION>::one();
1329                let zero = RealRugStrictFinite::<PRECISION>::zero();
1330                let _ = &one / &zero;
1331            }
1332
1333            #[test]
1334            #[should_panic(expected = "Division failed validation")]
1335            fn div_assign_by_zero() {
1336                let mut num = RealRugStrictFinite::<PRECISION>::one();
1337                let zero_ref = &RealRugStrictFinite::<PRECISION>::zero();
1338                num /= zero_ref;
1339            }
1340        }
1341
1342        mod complex {
1343            use super::*;
1344
1345            #[test]
1346            fn neg_assign() {
1347                let re = rug::Float::with_val(PRECISION, 1.);
1348                let im = rug::Float::with_val(PRECISION, 2.);
1349                let mut num = rug::Complex::with_val(PRECISION, (re, im));
1350                num.neg_assign();
1351                let expected = rug::Complex::with_val(
1352                    PRECISION,
1353                    (
1354                        rug::Float::with_val(PRECISION, -1.),
1355                        rug::Float::with_val(PRECISION, -2.),
1356                    ),
1357                );
1358                assert_eq!(&num, &expected);
1359
1360                let mut num = ComplexRugStrictFinite::<PRECISION>::try_new(num).unwrap();
1361                let expected = num.clone().neg();
1362                num.neg_assign();
1363                assert_eq!(&num, &expected);
1364            }
1365
1366            #[test]
1367            #[should_panic(expected = "Division failed validation")]
1368            fn div_by_zero() {
1369                let one = ComplexRugStrictFinite::<PRECISION>::one();
1370                let zero = ComplexRugStrictFinite::<PRECISION>::zero();
1371                let _ = &one / &zero;
1372            }
1373
1374            #[test]
1375            #[should_panic(expected = "Division failed validation")]
1376            fn div_assign_by_zero() {
1377                let mut num = ComplexRugStrictFinite::<PRECISION>::one();
1378                let zero_ref = &ComplexRugStrictFinite::<PRECISION>::zero();
1379                num /= zero_ref;
1380            }
1381        }
1382    }
1383
1384    mod real_scalar_methods {
1385        use super::*;
1386
1387        #[test]
1388        fn epsilon() {
1389            let eps = RealRugStrictFinite::<PRECISION>::epsilon();
1390            assert!(eps.is_finite() && eps > RealRugStrictFinite::<PRECISION>::zero());
1391            let expected_eps_val =
1392                rug::Float::with_val(PRECISION, 2.0).pow(1i32 - PRECISION as i32);
1393            let expected_eps = RealRugStrictFinite::<PRECISION>::try_new(expected_eps_val).unwrap();
1394            assert_eq!(eps, expected_eps, "Epsilon value mismatch");
1395        }
1396
1397        #[test]
1398        fn clamp_ref() {
1399            let val = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap();
1400            let min_val = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
1401            let max_val = RealRugStrictFinite::<PRECISION>::try_from_f64(10.0).unwrap();
1402
1403            assert_eq!(val.clone().clamp_ref(&min_val, &max_val), val);
1404            assert_eq!(
1405                RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0)
1406                    .unwrap()
1407                    .clamp_ref(&min_val, &max_val),
1408                min_val
1409            );
1410            assert_eq!(
1411                RealRugStrictFinite::<PRECISION>::try_from_f64(15.0)
1412                    .unwrap()
1413                    .clamp_ref(&min_val, &max_val),
1414                max_val
1415            );
1416        }
1417
1418        #[test]
1419        fn hypot() {
1420            let a = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap();
1421            let b = RealRugStrictFinite::<PRECISION>::try_from_f64(4.0).unwrap();
1422            let expected = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap();
1423            assert_eq!(a.hypot(&b), expected);
1424        }
1425
1426        #[test]
1427        fn signum() {
1428            assert_eq!(
1429                RealRugStrictFinite::<PRECISION>::try_from_f64(5.0)
1430                    .unwrap()
1431                    .kernel_signum(),
1432                RealRugStrictFinite::<PRECISION>::one()
1433            );
1434            assert_eq!(
1435                RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0)
1436                    .unwrap()
1437                    .kernel_signum(),
1438                RealRugStrictFinite::<PRECISION>::negative_one()
1439            );
1440            // rug::Float::signum of 0.0 is 1.0
1441            assert_eq!(
1442                RealRugStrictFinite::<PRECISION>::zero().kernel_signum(),
1443                RealRugStrictFinite::<PRECISION>::one()
1444            );
1445        }
1446
1447        #[test]
1448        fn total_cmp() {
1449            let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0).unwrap();
1450            let r2 = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1451            assert_eq!(r1.total_cmp(&r1), Ordering::Equal);
1452            assert_eq!(r1.total_cmp(&r2), Ordering::Less);
1453            assert_eq!(r2.total_cmp(&r1), Ordering::Greater);
1454        }
1455
1456        #[test]
1457        fn mul_add_mul_mut() {
1458            let mut a = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1459            let b = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(); // mul
1460            let c = RealRugStrictFinite::<PRECISION>::try_from_f64(4.0).unwrap(); // add_mul1
1461            let d = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap(); // add_mul2
1462            // Expected: a = a*b + c*d = 2*3 + 4*5 = 6 + 20 = 26
1463            a.kernel_mul_add_mul_mut(&b, &c, &d);
1464            assert_eq!(
1465                a,
1466                RealRugStrictFinite::<PRECISION>::try_from_f64(26.0).unwrap()
1467            );
1468        }
1469
1470        #[test]
1471        fn mul_sub_mul_mut() {
1472            let mut a = RealRugStrictFinite::<PRECISION>::try_from_f64(10.0).unwrap();
1473            let b = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap(); // mul
1474            let c = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(); // sub_mul1
1475            let d = RealRugStrictFinite::<PRECISION>::try_from_f64(4.0).unwrap(); // sub_mul2
1476            // Expected: a = a*b - c*d = 10*2 - 3*4 = 20 - 12 = 8
1477            a.kernel_mul_sub_mul_mut(&b, &c, &d);
1478            assert_eq!(
1479                a,
1480                RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1481            );
1482        }
1483
1484        #[test]
1485        fn test_real_rug_constants() {
1486            // Helper to create a raw rug::Float for comparison
1487            let raw_float = |f: f64| Float::with_val(PRECISION, f);
1488
1489            // PI - should use MPFR Constant::Pi
1490            let pi = RealRugStrictFinite::<PRECISION>::pi();
1491            let expected_pi = Float::with_val(PRECISION, MpfrConstant::Pi);
1492            assert_eq!(pi.as_raw_scalar_ref(), &expected_pi);
1493
1494            // TWO_PI - should be 2 * MPFR Pi
1495            let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
1496            let expected_two_pi = Float::with_val(PRECISION, MpfrConstant::Pi) * 2;
1497            assert_eq!(two_pi.as_raw_scalar_ref(), &expected_two_pi);
1498
1499            // PI_DIV_2 - should be MPFR Pi / 2
1500            let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1501            let expected_pi_div_2 = Float::with_val(PRECISION, MpfrConstant::Pi) / 2;
1502            assert_eq!(pi_div_2.as_raw_scalar_ref(), &expected_pi_div_2);
1503
1504            // E - must be calculated as exp(1)
1505            let e = RealRugStrictFinite::<PRECISION>::e();
1506            let expected_e = raw_float(1.0).exp();
1507            assert_eq!(e.as_raw_scalar_ref(), &expected_e);
1508
1509            // LOG2_E - should use 1/MPFR Log2
1510            let log2_e = RealRugStrictFinite::<PRECISION>::log2_e();
1511            let expected_log2_e = Float::with_val(PRECISION, MpfrConstant::Log2).recip();
1512            assert_eq!(log2_e.as_raw_scalar_ref(), &expected_log2_e);
1513
1514            // LOG10_E - should be 1/(MPFR Log2 * log2(10))
1515            let log10_e = RealRugStrictFinite::<PRECISION>::log10_e();
1516            let ln2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1517            let log2_10 = raw_float(10.0).log2();
1518            let expected_log10_e = (ln2 * log2_10).recip();
1519            assert_eq!(log10_e.as_raw_scalar_ref(), &expected_log10_e);
1520
1521            // LN_2 - should use MPFR Constant::Log2
1522            let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1523            let expected_ln_2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1524            assert_eq!(ln_2.as_raw_scalar_ref(), &expected_ln_2);
1525
1526            // LN_10 - should be MPFR Log2 * log2(10)
1527            let ln_10 = RealRugStrictFinite::<PRECISION>::ln_10();
1528            let ln2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1529            let log2_10 = raw_float(10.0).log2();
1530            let expected_ln_10 = ln2 * log2_10;
1531            assert_eq!(ln_10.as_raw_scalar_ref(), &expected_ln_10);
1532
1533            // LOG2_10
1534            let log2_10 = RealRugStrictFinite::<PRECISION>::log2_10();
1535            let expected_log2_10 = raw_float(10.0).log2();
1536            assert_eq!(log2_10.as_raw_scalar_ref(), &expected_log2_10);
1537
1538            // LOG10_2
1539            let log10_2 = RealRugStrictFinite::<PRECISION>::log10_2();
1540            let expected_log10_2 = raw_float(2.0).log10();
1541            assert_eq!(log10_2.as_raw_scalar_ref(), &expected_log10_2);
1542
1543            // MAX_FINITE
1544            let max_finite = RealRugStrictFinite::<PRECISION>::max_finite();
1545            let expected_max_finite = <rug::Float as RawRealTrait>::raw_max_finite(PRECISION);
1546            assert_eq!(max_finite.as_raw_scalar_ref(), &expected_max_finite);
1547
1548            // MIN_FINITE
1549            let min_finite = RealRugStrictFinite::<PRECISION>::min_finite();
1550            let expected_min_finite = <rug::Float as RawRealTrait>::raw_min_finite(PRECISION);
1551            assert_eq!(min_finite.as_raw_scalar_ref(), &expected_min_finite);
1552
1553            // EPSILON
1554            let epsilon = RealRugStrictFinite::<PRECISION>::epsilon();
1555            let expected_epsilon = <rug::Float as RawRealTrait>::raw_epsilon(PRECISION);
1556            assert_eq!(epsilon.as_raw_scalar_ref(), &expected_epsilon);
1557
1558            // NEGATIVE_ONE
1559            assert_eq!(
1560                RealRugStrictFinite::<PRECISION>::negative_one().as_raw_scalar_ref(),
1561                &raw_float(-1.0)
1562            );
1563
1564            // TWO
1565            assert_eq!(
1566                RealRugStrictFinite::<PRECISION>::two().as_raw_scalar_ref(),
1567                &raw_float(2.0)
1568            );
1569
1570            // ONE_DIV_2
1571            assert_eq!(
1572                RealRugStrictFinite::<PRECISION>::one_div_2().as_raw_scalar_ref(),
1573                &raw_float(0.5)
1574            );
1575        }
1576
1577        /// Test that MPFR optimized constants are used instead of calculations.
1578        /// This verifies that pi() uses Constant::Pi (not acos(-1)) and
1579        /// ln_2() uses Constant::Log2 (not ln(2)).
1580        #[test]
1581        fn test_real_rug_constants_mpfr_optimization() {
1582            // π should use MpfrConstant::Pi (not acos(-1))
1583            let pi = RealRugStrictFinite::<PRECISION>::pi();
1584            let expected_pi = Float::with_val(PRECISION, MpfrConstant::Pi);
1585            assert_eq!(pi.as_raw_scalar_ref(), &expected_pi);
1586
1587            // ln(2) should use MpfrConstant::Log2 (not ln(2) calculation)
1588            let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1589            let expected_ln_2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1590            assert_eq!(ln_2.as_raw_scalar_ref(), &expected_ln_2);
1591
1592            // Derived constants should be computed from MPFR base constants
1593            let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
1594            let expected_two_pi = Float::with_val(PRECISION, MpfrConstant::Pi) * 2;
1595            assert_eq!(two_pi.as_raw_scalar_ref(), &expected_two_pi);
1596
1597            let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1598            let expected_pi_div_2 = Float::with_val(PRECISION, MpfrConstant::Pi) / 2;
1599            assert_eq!(pi_div_2.as_raw_scalar_ref(), &expected_pi_div_2);
1600        }
1601
1602        /// Test that constants with different precisions are independent and correct.
1603        #[test]
1604        fn test_real_rug_constants_precision_independence() {
1605            type Real100 = RealRugStrictFinite<100>;
1606            type Real200 = RealRugStrictFinite<200>;
1607            type Real500 = RealRugStrictFinite<500>;
1608
1609            // Get π at different precisions
1610            let pi_100 = Real100::pi();
1611            let pi_200 = Real200::pi();
1612            let pi_500 = Real500::pi();
1613
1614            // They should all represent π, but with different precisions
1615            // Convert to f64 for comparison (all should be close to π)
1616            let pi_100_f64 = pi_100.as_raw_scalar_ref().to_f64();
1617            let pi_200_f64 = pi_200.as_raw_scalar_ref().to_f64();
1618            let pi_500_f64 = pi_500.as_raw_scalar_ref().to_f64();
1619
1620            let pi_expected = std::f64::consts::PI;
1621            assert!((pi_100_f64 - pi_expected).abs() < 1e-15);
1622            assert!((pi_200_f64 - pi_expected).abs() < 1e-15);
1623            assert!((pi_500_f64 - pi_expected).abs() < 1e-15);
1624
1625            // Test e at different precisions
1626            let e_100 = Real100::e();
1627            let e_200 = Real200::e();
1628
1629            let e_100_f64 = e_100.as_raw_scalar_ref().to_f64();
1630            let e_200_f64 = e_200.as_raw_scalar_ref().to_f64();
1631
1632            let e_expected = std::f64::consts::E;
1633            assert!((e_100_f64 - e_expected).abs() < 1e-15);
1634            assert!((e_200_f64 - e_expected).abs() < 1e-15);
1635        }
1636
1637        /// Test mathematical correctness of constant relationships.
1638        #[test]
1639        fn test_real_rug_constants_mathematical_relationships() {
1640            let pi = RealRugStrictFinite::<PRECISION>::pi();
1641            let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
1642            let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1643
1644            // two_pi = 2 * pi
1645            let expected_two_pi = pi.as_raw_scalar_ref() * Float::with_val(PRECISION, 2);
1646            assert_eq!(two_pi.as_raw_scalar_ref(), &expected_two_pi);
1647
1648            // pi_div_2 = pi / 2
1649            let expected_pi_div_2 = pi.as_raw_scalar_ref() / Float::with_val(PRECISION, 2);
1650            assert_eq!(pi_div_2.as_raw_scalar_ref(), &expected_pi_div_2);
1651
1652            let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1653            let ln_10 = RealRugStrictFinite::<PRECISION>::ln_10();
1654            let log2_e = RealRugStrictFinite::<PRECISION>::log2_e();
1655            let log10_e = RealRugStrictFinite::<PRECISION>::log10_e();
1656
1657            // log2_e * ln_2 should equal 1 (since logâ‚‚(e) = 1/ln(2))
1658            let product =
1659                (log2_e.as_raw_scalar_ref() * ln_2.as_raw_scalar_ref()).complete(PRECISION);
1660            let one = Float::with_val(PRECISION, 1);
1661            let epsilon = Float::with_val(PRECISION, 1e-10);
1662            let diff = (product - &one).abs();
1663            assert!(diff < epsilon);
1664
1665            // log10_e * ln_10 should equal 1
1666            let product =
1667                (log10_e.as_raw_scalar_ref() * ln_10.as_raw_scalar_ref()).complete(PRECISION);
1668            let diff = (product - &one).abs();
1669            assert!(diff < epsilon);
1670        }
1671
1672        /// Test that multiple calls to the same constant produce identical values.
1673        /// This verifies computational consistency (MPFR constants are deterministic).
1674        #[test]
1675        fn test_real_rug_constants_consistency() {
1676            // Call each constant twice and verify they produce identical values
1677            let pi1 = RealRugStrictFinite::<PRECISION>::pi();
1678            let pi2 = RealRugStrictFinite::<PRECISION>::pi();
1679            assert_eq!(pi1.as_raw_scalar_ref(), pi2.as_raw_scalar_ref());
1680
1681            let e1 = RealRugStrictFinite::<PRECISION>::e();
1682            let e2 = RealRugStrictFinite::<PRECISION>::e();
1683            assert_eq!(e1.as_raw_scalar_ref(), e2.as_raw_scalar_ref());
1684
1685            let ln2_1 = RealRugStrictFinite::<PRECISION>::ln_2();
1686            let ln2_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1687            assert_eq!(ln2_1.as_raw_scalar_ref(), ln2_2.as_raw_scalar_ref());
1688
1689            let two_pi1 = RealRugStrictFinite::<PRECISION>::two_pi();
1690            let two_pi2 = RealRugStrictFinite::<PRECISION>::two_pi();
1691            assert_eq!(two_pi1.as_raw_scalar_ref(), two_pi2.as_raw_scalar_ref());
1692
1693            let pi_div_2_1 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1694            let pi_div_2_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1695            assert_eq!(
1696                pi_div_2_1.as_raw_scalar_ref(),
1697                pi_div_2_2.as_raw_scalar_ref()
1698            );
1699        }
1700    }
1701
1702    mod scalar_constructors {
1703        use super::*;
1704        use crate::{
1705            core::errors::ErrorsValidationRawReal,
1706            functions::{
1707                ATan2InputErrors, LogarithmRealErrors, LogarithmRealInputErrors,
1708                PowComplexBaseRealExponentInputErrors, PowRealBaseRealExponentInputErrors,
1709                ReciprocalInputErrors, SqrtRealInputErrors,
1710            },
1711        };
1712
1713        mod real {
1714            use super::*;
1715
1716            #[test]
1717            fn exp_overflow() {
1718                let large_val = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0e60).unwrap(); // exp(1.0e60) is very large
1719                let res_large = large_val.try_exp();
1720                assert!(matches!(
1721                    res_large,
1722                    Err(ExpErrors::Output {
1723                        source: ErrorsValidationRawReal::IsPosInfinity { .. }
1724                    })
1725                ),);
1726            }
1727
1728            #[test]
1729            fn ln_domain_errors() {
1730                let neg_val = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.0).unwrap();
1731                assert!(matches!(
1732                    neg_val.try_ln(),
1733                    Err(LogarithmRealErrors::Input(
1734                        LogarithmRealInputErrors::NegativeArgument { .. }
1735                    ))
1736                ));
1737
1738                let zero_val = RealRugStrictFinite::<PRECISION>::zero();
1739                assert!(matches!(
1740                    zero_val.try_ln(),
1741                    Err(LogarithmRealErrors::Input(
1742                        LogarithmRealInputErrors::ZeroArgument { .. }
1743                    ))
1744                ));
1745            }
1746        } // end mod real
1747
1748        mod complex {
1749            use super::*;
1750
1751            #[test]
1752            fn log2_zero() {
1753                let zero_val = ComplexRugStrictFinite::<PRECISION>::zero();
1754                assert!(matches!(
1755                    zero_val.try_log2(),
1756                    Err(LogarithmComplexErrors::Input(
1757                        LogarithmComplexInputErrors::ZeroArgument { .. }
1758                    ))
1759                ));
1760            }
1761        } // end mod complex
1762
1763        mod pow {
1764            use super::*;
1765
1766            mod real_base {
1767                use super::*;
1768
1769                #[test]
1770                fn negative_base_real_exponent_error() {
1771                    let base = RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap();
1772                    let exponent = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
1773                    let res = base.try_pow(&exponent);
1774                    assert!(matches!(
1775                        res,
1776                        Err(PowRealBaseRealExponentErrors::Input(
1777                            PowRealBaseRealExponentInputErrors::NegativeBase { .. }
1778                        ))
1779                    ));
1780                }
1781
1782                #[test]
1783                fn real_base_uint_exponent() {
1784                    let base = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1785                    assert_eq!(
1786                        base.clone().try_pow(3u8).unwrap(),
1787                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1788                    );
1789                    assert_eq!(
1790                        base.clone().try_pow(3u16).unwrap(),
1791                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1792                    );
1793                    assert_eq!(
1794                        base.clone().try_pow(3u32).unwrap(),
1795                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1796                    );
1797                    assert_eq!(
1798                        base.clone().try_pow(3u64).unwrap(),
1799                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1800                    );
1801                    assert_eq!(
1802                        base.clone().try_pow(3u128).unwrap(),
1803                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1804                    );
1805                    assert_eq!(
1806                        base.clone().try_pow(3usize).unwrap(),
1807                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1808                    );
1809
1810                    assert_eq!(
1811                        base.clone().pow(3u8),
1812                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1813                    );
1814                    assert_eq!(
1815                        base.clone().pow(3u16),
1816                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1817                    );
1818                    assert_eq!(
1819                        base.clone().pow(3u32),
1820                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1821                    );
1822                    assert_eq!(
1823                        base.clone().pow(3u64),
1824                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1825                    );
1826                    assert_eq!(
1827                        base.clone().pow(3u128),
1828                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1829                    );
1830                    assert_eq!(
1831                        base.clone().pow(3usize),
1832                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1833                    );
1834                }
1835
1836                #[test]
1837                fn real_base_int_exponent() {
1838                    let base = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1839                    assert_eq!(
1840                        base.clone().try_pow(3i8).unwrap(),
1841                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1842                    );
1843                    assert_eq!(
1844                        base.clone().try_pow(3i16).unwrap(),
1845                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1846                    );
1847                    assert_eq!(
1848                        base.clone().try_pow(3i32).unwrap(),
1849                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1850                    );
1851                    assert_eq!(
1852                        base.clone().try_pow(3i64).unwrap(),
1853                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1854                    );
1855                    assert_eq!(
1856                        base.clone().try_pow(3i128).unwrap(),
1857                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1858                    );
1859                    assert_eq!(
1860                        base.clone().try_pow(3isize).unwrap(),
1861                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1862                    );
1863
1864                    assert_eq!(
1865                        base.clone().pow(3i8),
1866                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1867                    );
1868                    assert_eq!(
1869                        base.clone().pow(3i16),
1870                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1871                    );
1872                    assert_eq!(
1873                        base.clone().pow(3i32),
1874                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1875                    );
1876                    assert_eq!(
1877                        base.clone().pow(3i64),
1878                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1879                    );
1880                    assert_eq!(
1881                        base.clone().pow(3i128),
1882                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1883                    );
1884                    assert_eq!(
1885                        base.clone().pow(3isize),
1886                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1887                    );
1888                }
1889
1890                #[test]
1891                fn real_base_int_exponent_zero_neg_exp_error() {
1892                    let base = RealRugStrictFinite::<PRECISION>::zero();
1893                    let exponent: i32 = -2;
1894                    let res = base.try_pow(exponent);
1895                    assert!(matches!(
1896                        res,
1897                        Err(PowIntExponentErrors::Input(
1898                            PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
1899                        ))
1900                    ));
1901                }
1902            }
1903
1904            mod complex_base {
1905                use super::*;
1906
1907                #[test]
1908                fn complex_base_uint_exponent() {
1909                    let base = ComplexRugStrictFinite::<PRECISION>::try_new(
1910                        rug::Complex::with_val(PRECISION, (2.0, 3.0)),
1911                    )
1912                    .unwrap();
1913                    let expected_res = ComplexRugStrictFinite::<PRECISION>::try_new(
1914                        rug::Complex::with_val(PRECISION, (-46.0, 9.0)),
1915                    )
1916                    .unwrap();
1917
1918                    assert_eq!(&base.clone().try_pow(3u8).unwrap(), &expected_res);
1919                    assert_eq!(&base.clone().try_pow(3u16).unwrap(), &expected_res);
1920                    assert_eq!(&base.clone().try_pow(3u32).unwrap(), &expected_res);
1921                    assert_eq!(&base.clone().try_pow(3u64).unwrap(), &expected_res);
1922                    assert_eq!(&base.clone().try_pow(3u128).unwrap(), &expected_res);
1923                    assert_eq!(&base.clone().try_pow(3usize).unwrap(), &expected_res);
1924
1925                    assert_eq!(&base.clone().pow(3u8), &expected_res);
1926                    assert_eq!(&base.clone().pow(3u16), &expected_res);
1927                    assert_eq!(&base.clone().pow(3u32), &expected_res);
1928                    assert_eq!(&base.clone().pow(3u64), &expected_res);
1929                    assert_eq!(&base.clone().pow(3u128), &expected_res);
1930                    assert_eq!(&base.clone().pow(3usize), &expected_res);
1931                }
1932
1933                #[test]
1934                fn complex_base_int_exponent() {
1935                    let base = ComplexRugStrictFinite::<PRECISION>::try_new(
1936                        rug::Complex::with_val(PRECISION, (2.0, 3.0)),
1937                    )
1938                    .unwrap();
1939                    let expected_res = ComplexRugStrictFinite::<PRECISION>::try_new(
1940                        rug::Complex::with_val(PRECISION, (-46.0, 9.0)),
1941                    )
1942                    .unwrap();
1943
1944                    assert_eq!(&base.clone().try_pow(3i8).unwrap(), &expected_res);
1945                    assert_eq!(&base.clone().try_pow(3i16).unwrap(), &expected_res);
1946                    assert_eq!(&base.clone().try_pow(3i32).unwrap(), &expected_res);
1947                    assert_eq!(&base.clone().try_pow(3i64).unwrap(), &expected_res);
1948                    assert_eq!(&base.clone().try_pow(3i128).unwrap(), &expected_res);
1949                    assert_eq!(&base.clone().try_pow(3isize).unwrap(), &expected_res);
1950
1951                    assert_eq!(&base.clone().pow(3i8), &expected_res);
1952                    assert_eq!(&base.clone().pow(3i16), &expected_res);
1953                    assert_eq!(&base.clone().pow(3i32), &expected_res);
1954                    assert_eq!(&base.clone().pow(3i64), &expected_res);
1955                    assert_eq!(&base.clone().pow(3i128), &expected_res);
1956                    assert_eq!(&base.clone().pow(3isize), &expected_res);
1957                }
1958
1959                #[test]
1960                fn complex_zero_base_negative_real_exponent_error() {
1961                    let base = ComplexRugStrictFinite::<PRECISION>::zero();
1962                    let exponent = RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap();
1963                    let res = base.try_pow(&exponent);
1964                    assert!(matches!(
1965                        res,
1966                        Err(PowComplexBaseRealExponentErrors::Input(
1967                            PowComplexBaseRealExponentInputErrors::ZeroBaseNegativeExponent { .. }
1968                        ))
1969                    ));
1970                }
1971
1972                #[test]
1973                fn complex_zero_base_zero_real_exponent() {
1974                    let base = ComplexRugStrictFinite::<PRECISION>::zero();
1975                    let exponent = RealRugStrictFinite::<PRECISION>::zero();
1976                    let res = base.try_pow(&exponent).unwrap();
1977                    assert_eq!(res, ComplexRugStrictFinite::<PRECISION>::one());
1978                }
1979
1980                #[test]
1981                fn complex_base_int_exponent_zero_neg_exp_error() {
1982                    let base = ComplexRugStrictFinite::<PRECISION>::zero();
1983                    let exponent: i32 = -2;
1984                    let res = base.try_pow(exponent);
1985                    assert!(matches!(
1986                        res,
1987                        Err(PowIntExponentErrors::Input(
1988                            PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
1989                        ))
1990                    ));
1991                }
1992            }
1993        }
1994
1995        #[test]
1996        fn reciprocal_real_rug_zero() {
1997            let zero_val = RealRugStrictFinite::<PRECISION>::zero();
1998            let res = zero_val.try_reciprocal();
1999            assert!(matches!(
2000                res,
2001                Err(ReciprocalErrors::Input(
2002                    ReciprocalInputErrors::DivisionByZero { .. }
2003                ))
2004            ));
2005        }
2006
2007        #[test]
2008        fn reciprocal_complex_rug_zero() {
2009            let zero_val = ComplexRugStrictFinite::<PRECISION>::zero();
2010            let res = zero_val.try_reciprocal();
2011            assert!(matches!(
2012                res,
2013                Err(ReciprocalErrors::Input(
2014                    ReciprocalInputErrors::DivisionByZero { .. }
2015                ))
2016            ));
2017        }
2018
2019        #[test]
2020        fn sqrt_real_rug_negative_input() {
2021            let neg_val = RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap();
2022            let res = neg_val.try_sqrt();
2023            assert!(matches!(
2024                res,
2025                Err(SqrtRealErrors::Input(
2026                    SqrtRealInputErrors::NegativeValue { .. }
2027                ))
2028            ));
2029        }
2030
2031        mod trigonometric {
2032            use super::*;
2033
2034            #[test]
2035            fn atan2_real_rug_zero_over_zero() {
2036                let zero_val = RealRugStrictFinite::<PRECISION>::zero();
2037                let res = zero_val.try_atan2(&RealRugStrictFinite::<PRECISION>::zero());
2038                assert!(matches!(
2039                    res,
2040                    Err(ATan2Errors::Input(ATan2InputErrors::ZeroOverZero { .. }))
2041                ));
2042            }
2043
2044            /*
2045            #[test]
2046            #[ignore = "at the moment we cannot create a pole for the Tan function"]
2047            fn tan_real_rug_pole() {
2048                // tan(PI/2) is a pole
2049                let pi_half = RealRugStrictFinite::<PRECISION>::pi_div_2();
2050                let res = pi_half.try_tan();
2051                println!("Result: {:?}", res);
2052                assert!(matches!(
2053                    res,
2054                    Err(TanRealErrors::Input(TanRealInputErrors::ArgumentIsPole { .. }))
2055                ));
2056            }
2057            */
2058
2059            #[test]
2060            fn asin_real_rug_out_of_domain() {
2061                let val_gt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.5).unwrap();
2062                assert!(matches!(
2063                    val_gt_1.try_asin(),
2064                    Err(ASinRealErrors::Input(
2065                        ASinRealInputErrors::OutOfDomain { .. }
2066                    ))
2067                ));
2068                let val_lt_neg1 = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.5).unwrap();
2069                assert!(matches!(
2070                    val_lt_neg1.try_asin(),
2071                    Err(ASinRealErrors::Input(
2072                        ASinRealInputErrors::OutOfDomain { .. }
2073                    ))
2074                ));
2075            }
2076
2077            #[test]
2078            fn acos_real_rug_out_of_domain() {
2079                let val_gt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.5).unwrap();
2080                assert!(matches!(
2081                    val_gt_1.try_acos(),
2082                    Err(ACosRealErrors::Input(
2083                        ACosRealInputErrors::OutOfDomain { .. }
2084                    ))
2085                ));
2086                let val_lt_neg1 = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.5).unwrap();
2087                assert!(matches!(
2088                    val_lt_neg1.try_acos(),
2089                    Err(ACosRealErrors::Input(
2090                        ACosRealInputErrors::OutOfDomain { .. }
2091                    ))
2092                ));
2093            }
2094
2095            #[test]
2096            fn atan_complex_rug_pole() {
2097                // atan(i) and atan(-i) are poles
2098                let i_val = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
2099                    Float::with_val(PRECISION, 1.0),
2100                )
2101                .unwrap();
2102                assert!(matches!(
2103                    i_val.try_atan(),
2104                    Err(ATanComplexErrors::Input(
2105                        ATanComplexInputErrors::ArgumentIsPole { .. }
2106                    ))
2107                ));
2108
2109                let neg_i_val = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
2110                    Float::with_val(PRECISION, -1.0),
2111                )
2112                .unwrap();
2113                assert!(matches!(
2114                    neg_i_val.try_atan(),
2115                    Err(ATanComplexErrors::Input(
2116                        ATanComplexInputErrors::ArgumentIsPole { .. }
2117                    ))
2118                ));
2119            }
2120        } // endmod trigonometric
2121
2122        mod hyperbolic {
2123            use super::*;
2124
2125            mod real {
2126                use super::*;
2127
2128                #[test]
2129                fn atanh_real_rug_out_of_domain() {
2130                    let val_ge_1 = RealRugStrictFinite::<PRECISION>::one(); // atanh(1) is Inf
2131                    assert!(matches!(
2132                        val_ge_1.try_atanh(),
2133                        Err(ATanHErrors::Input(ATanHInputErrors::OutOfDomain { .. }))
2134                    ));
2135
2136                    let val_le_neg1 = RealRugStrictFinite::<PRECISION>::negative_one(); // atanh(-1) is -Inf
2137                    assert!(matches!(
2138                        val_le_neg1.try_atanh(),
2139                        Err(ATanHErrors::Input(ATanHInputErrors::OutOfDomain { .. }))
2140                    ));
2141                }
2142
2143                #[test]
2144                fn acosh_real_rug_out_of_domain() {
2145                    let val_lt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
2146                    assert!(matches!(
2147                        val_lt_1.try_acosh(),
2148                        Err(ACosHErrors::Input(ACosHInputErrors::OutOfDomain { .. }))
2149                    ));
2150                }
2151            }
2152
2153            mod complex {
2154                use super::*;
2155
2156                /*
2157                #[test]
2158                #[ignore = "at the moment we cannot create a pole for the ATanH function"]
2159                fn tanh_complex_rug_pole() {
2160                    // tanh(z) has poles where cosh(z) = 0. e.g. z = i * (PI/2 + k*PI)
2161                    let pi_half = RealRugStrictFinite::<PRECISION>::pi_div_2().into_inner();
2162                    let pole_val =
2163                        ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(pi_half).unwrap();
2164                    println!("Atanh(Pole value): {:?}", pole_val.clone().try_tanh());
2165                    assert!(matches!(
2166                        pole_val.try_tanh(),
2167                        Err(TanHComplexErrors::Input(TanHComplexInputErrors::OutOfDomain { .. }))
2168                    ));
2169                }
2170                */
2171
2172                #[test]
2173                fn acosh_out_of_domain() {
2174                    // acosh(z) domain is C \ (-inf, 1) on real axis
2175                    let val_on_branch_cut = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2176                        Float::with_val(PRECISION, 0.5),
2177                    )
2178                    .unwrap();
2179                    assert!(matches!(
2180                        val_on_branch_cut.try_acosh(),
2181                        Err(ACosHErrors::Input(ACosHInputErrors::OutOfDomain { .. }))
2182                    ));
2183
2184                    let val_on_branch_cut_neg =
2185                        ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(Float::with_val(
2186                            PRECISION, -5.0,
2187                        ))
2188                        .unwrap();
2189                    assert!(matches!(
2190                        val_on_branch_cut_neg.try_acosh(),
2191                        Err(ACosHErrors::Input(ACosHInputErrors::OutOfDomain { .. }))
2192                    ));
2193                }
2194
2195                #[test]
2196                fn atanh_out_of_domain() {
2197                    let val_ge_1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2198                        Float::with_val(PRECISION, 1.0),
2199                    )
2200                    .unwrap();
2201                    assert!(matches!(
2202                        val_ge_1.try_atanh(),
2203                        Err(ATanHErrors::Input(ATanHInputErrors::OutOfDomain { .. }))
2204                    ));
2205
2206                    let val_le_neg1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2207                        Float::with_val(PRECISION, -1.0),
2208                    )
2209                    .unwrap();
2210                    assert!(matches!(
2211                        val_le_neg1.try_atanh(),
2212                        Err(ATanHErrors::Input(ATanHInputErrors::OutOfDomain { .. }))
2213                    ));
2214                }
2215            }
2216
2217            /*
2218            #[test]
2219            #[ignore = "at the moment we cannot create a pole for the TanH function"]
2220            fn tanh_out_of_domain() {
2221                // tanh(z) has poles where cosh(z) = 0. e.g. z = i * (PI/2 + k*PI)
2222                let pi_half = RealRugStrictFinite::<PRECISION>::pi_div_2().into_inner();
2223                let pole_val = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(pi_half).unwrap();
2224                println!("TanH(Pole value): {:?}", pole_val.clone().try_tanh());
2225                assert!(matches!(
2226                    pole_val.try_tanh(),
2227                    Err(TanHComplexErrors::Input(TanHComplexInputErrors::OutOfDomain { .. }))
2228                ));
2229            }
2230            */
2231        } // end mod hyperbolic
2232    }
2233
2234    mod summation {
2235        use super::*;
2236
2237        const PRECISION: u32 = 53;
2238
2239        type RealValidated = RealRugStrictFinite<PRECISION>;
2240        type ComplexValidated = ComplexRugStrictFinite<PRECISION>;
2241
2242        #[test]
2243        fn sum_real() {
2244            let values = vec![
2245                RealValidated::try_from_f64(1.0).unwrap(),
2246                RealValidated::try_from_f64(2.0).unwrap(),
2247                RealValidated::try_from_f64(3.0).unwrap(),
2248                RealValidated::try_from_f64(4.0).unwrap(),
2249                RealValidated::try_from_f64(5.0).unwrap(),
2250            ];
2251            let sum: RealValidated = values.into_iter().sum();
2252            assert_eq!(sum, RealValidated::try_from_f64(15.0).unwrap());
2253        }
2254
2255        #[test]
2256        fn sum_real_compensated() {
2257            // Test case where simple summation might lose precision
2258            let values = vec![
2259                RealValidated::try_from_f64(1.0e100).unwrap(),
2260                RealValidated::try_from_f64(1.0).unwrap(),
2261                RealValidated::try_from_f64(-1.0e100).unwrap(),
2262            ];
2263            let sum: RealValidated = values.into_iter().sum();
2264            // The Neumaier sum should correctly result in 1.0
2265            assert_eq!(sum, RealValidated::try_from_f64(1.0).unwrap());
2266        }
2267
2268        #[test]
2269        fn sum_complex() {
2270            let values = vec![
2271                ComplexValidated::try_new_complex(
2272                    rug::Float::with_val(PRECISION, 1.),
2273                    rug::Float::with_val(PRECISION, 2.),
2274                )
2275                .unwrap(),
2276                ComplexValidated::try_new_complex(
2277                    rug::Float::with_val(PRECISION, 3.),
2278                    rug::Float::with_val(PRECISION, 4.),
2279                )
2280                .unwrap(),
2281                ComplexValidated::try_new_complex(
2282                    rug::Float::with_val(PRECISION, 5.),
2283                    rug::Float::with_val(PRECISION, 6.),
2284                )
2285                .unwrap(),
2286            ];
2287            let sum: ComplexValidated = values.into_iter().sum();
2288            assert_eq!(
2289                sum,
2290                ComplexValidated::try_new_complex(
2291                    rug::Float::with_val(PRECISION, 9.),
2292                    rug::Float::with_val(PRECISION, 12.)
2293                )
2294                .unwrap()
2295            );
2296        }
2297
2298        #[test]
2299        fn sum_complex_compensated() {
2300            let values = [
2301                ComplexValidated::try_new_complex(
2302                    rug::Float::with_val(PRECISION, 1.0e100),
2303                    rug::Float::with_val(PRECISION, -1.0e100),
2304                )
2305                .unwrap(),
2306                ComplexValidated::try_new_complex(
2307                    rug::Float::with_val(PRECISION, 1.),
2308                    rug::Float::with_val(PRECISION, 2.),
2309                )
2310                .unwrap(),
2311                ComplexValidated::try_new_complex(
2312                    rug::Float::with_val(PRECISION, -1.0e100),
2313                    rug::Float::with_val(PRECISION, 1.0e100),
2314                )
2315                .unwrap(),
2316            ];
2317            let sum: ComplexValidated = values.iter().cloned().sum();
2318            assert_eq!(
2319                sum,
2320                ComplexValidated::try_new_complex(
2321                    rug::Float::with_val(PRECISION, 1.),
2322                    rug::Float::with_val(PRECISION, 2.)
2323                )
2324                .unwrap()
2325            );
2326        }
2327    } // end mod summation
2328
2329    mod random {
2330        use super::*;
2331        use crate::{TryRandomSampleFrom, try_random_vec};
2332        use rand::{RngExt, SeedableRng, distr::Uniform, rngs::StdRng};
2333
2334        const PRECISION: u32 = 53;
2335
2336        type RealValidated = RealRugStrictFinite<PRECISION>;
2337        type ComplexValidated = ComplexRugStrictFinite<PRECISION>;
2338
2339        /// Tests the random generation of a `RealValidated` value.
2340        /// It uses a seeded RNG to ensure deterministic results and checks
2341        /// if the generated value falls within the expected [0, 1) range.
2342        #[test]
2343        fn test_random_real_validated() {
2344            let seed = [42; 32];
2345            let mut rng = StdRng::from_seed(seed);
2346
2347            let random_real: RealValidated = rng.random();
2348
2349            // rng.random::<f64>() produces a value in [0, 1), so the converted value should be in the same range.
2350            assert_eq!(random_real.as_raw_scalar_ref(), &0.23713468825474326);
2351
2352            // Check for determinism
2353            let mut rng2 = StdRng::from_seed(seed);
2354            let random_real2: RealValidated = rng2.random();
2355            assert_eq!(random_real, random_real2);
2356        }
2357
2358        /// Tests the random generation of a `ComplexValidated` value.
2359        /// It uses a seeded RNG for determinism and verifies that both the real
2360        /// and imaginary parts of the generated complex number are within the
2361        /// expected [0, 1) range.
2362        #[test]
2363        fn test_random_complex_validated() {
2364            let seed = [99; 32];
2365            let mut rng = StdRng::from_seed(seed);
2366
2367            let random_complex: ComplexValidated = rng.random();
2368
2369            // The real and imaginary parts are generated independently,
2370            // so both should be in the [0, 1) range.
2371            let real_part = random_complex.real_part();
2372            let imag_part = random_complex.imag_part();
2373
2374            assert_eq!(real_part.as_raw_scalar_ref(), &0.9995546882627792);
2375            assert_eq!(imag_part.as_raw_scalar_ref(), &0.08932180682540247);
2376
2377            // Check for determinism
2378            let mut rng2 = StdRng::from_seed(seed);
2379            let random_complex2: ComplexValidated = rng2.random();
2380            assert_eq!(random_complex, random_complex2);
2381        }
2382
2383        const SEED: [u8; 32] = [42; 32];
2384
2385        #[test]
2386        fn test_sample_real_validated() {
2387            let mut rng = StdRng::from_seed(SEED);
2388            let dist = Uniform::new(-10.0, 10.0).unwrap();
2389
2390            let val = RealValidated::try_sample_from(&dist, &mut rng, PRECISION).unwrap();
2391            assert_eq!(val.as_raw_scalar_ref(), &-5.257306234905137);
2392
2393            // Check determinism
2394            let mut rng2 = StdRng::from_seed(SEED);
2395            let val2 = RealValidated::try_sample_from(&dist, &mut rng2, PRECISION).unwrap();
2396            assert_eq!(val, val2);
2397        }
2398
2399        #[test]
2400        fn test_sample_complex_validated() {
2401            let mut rng = StdRng::from_seed(SEED);
2402            let dist = Uniform::new(-10.0, 10.0).unwrap();
2403
2404            let val = ComplexValidated::try_sample_from(&dist, &mut rng, PRECISION).unwrap();
2405            assert_eq!(val.real_part().as_raw_scalar_ref(), &-5.257306234905137);
2406            assert_eq!(val.imag_part().as_raw_scalar_ref(), &7.212119776268775);
2407
2408            // Check determinism
2409            let mut rng2 = StdRng::from_seed(SEED);
2410            let val2 = ComplexValidated::try_sample_from(&dist, &mut rng2, PRECISION).unwrap();
2411            assert_eq!(val, val2);
2412        }
2413
2414        #[test]
2415        fn new_random_vec_real() {
2416            let mut rng = StdRng::from_seed(SEED);
2417            let dist = Uniform::new(-10.0, 10.0).unwrap();
2418            let vec: Vec<RealValidated> = try_random_vec(3, &dist, &mut rng, PRECISION).unwrap();
2419            assert_eq!(vec.len(), 3);
2420            assert_eq!(vec[0].as_raw_scalar_ref(), &-5.257306234905137);
2421            assert_eq!(vec[1].as_raw_scalar_ref(), &7.212119776268775);
2422            assert_eq!(vec[2].as_raw_scalar_ref(), &-4.666248990558111);
2423
2424            // Check determinism
2425            let mut rng2 = StdRng::from_seed(SEED);
2426            let vec2: Vec<RealValidated> = try_random_vec(3, &dist, &mut rng2, PRECISION).unwrap();
2427            assert_eq!(vec, vec2);
2428        }
2429
2430        #[test]
2431        fn new_random_vec_complex() {
2432            let mut rng = StdRng::from_seed(SEED);
2433            let dist = Uniform::new(-10.0, 10.0).unwrap();
2434            let vec: Vec<ComplexValidated> = try_random_vec(3, &dist, &mut rng, PRECISION).unwrap();
2435            assert_eq!(vec.len(), 3);
2436            assert_eq!(vec[0].real_part().as_raw_scalar_ref(), &-5.257306234905137);
2437            assert_eq!(vec[0].imag_part().as_raw_scalar_ref(), &7.212119776268775);
2438            assert_eq!(vec[1].real_part().as_raw_scalar_ref(), &-4.666248990558111);
2439            assert_eq!(vec[1].imag_part().as_raw_scalar_ref(), &9.66047141517383);
2440            assert_eq!(vec[2].real_part().as_raw_scalar_ref(), &-9.04279551029691);
2441            assert_eq!(vec[2].imag_part().as_raw_scalar_ref(), &-1.026624649331671);
2442
2443            // Check determinism
2444            let mut rng2 = StdRng::from_seed(SEED);
2445            let vec2: Vec<ComplexValidated> =
2446                try_random_vec(3, &dist, &mut rng2, PRECISION).unwrap();
2447            assert_eq!(vec, vec2);
2448        }
2449    }
2450
2451    mod hash_map_key_usage {
2452        use super::*;
2453        use rug::Float;
2454        use std::collections::HashMap;
2455        use try_create::TryNew;
2456
2457        const PRECISION: u32 = 128;
2458        type RealRugValidated = RealRugStrictFinite<PRECISION>;
2459
2460        #[test]
2461        fn test_rug_as_hashmap_key() {
2462            let mut map = HashMap::new();
2463            let key1 = RealRugValidated::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
2464            let key2 = RealRugValidated::try_new(Float::with_val(PRECISION, 2.5)).unwrap();
2465
2466            map.insert(key1.clone(), "one_rug");
2467            map.insert(key2.clone(), "two_point_five_rug");
2468
2469            assert_eq!(map.get(&key1), Some(&"one_rug"));
2470            assert_eq!(map.len(), 2);
2471
2472            // Overwrite an existing key
2473            let old_value = map.insert(key1.clone(), "new_one_rug");
2474            assert_eq!(old_value, Some("one_rug"));
2475            assert_eq!(map.get(&key1), Some(&"new_one_rug"));
2476        }
2477
2478        #[test]
2479        fn test_hash_signed_zero() {
2480            use crate::functions::Sign;
2481            use std::collections::hash_map::DefaultHasher;
2482            use std::hash::{Hash, Hasher};
2483
2484            let val1 = RealRugValidated::try_new(Float::with_val(PRECISION, 0.0)).unwrap();
2485            assert!(val1.kernel_is_sign_positive());
2486            let val2 = RealRugValidated::try_new(Float::with_val(PRECISION, -0.0)).unwrap();
2487            assert!(val2.kernel_is_sign_negative());
2488
2489            // Equal values should have equal hashes
2490            let mut hasher1 = DefaultHasher::new();
2491            let mut hasher2 = DefaultHasher::new();
2492
2493            val1.hash(&mut hasher1);
2494            val2.hash(&mut hasher2);
2495
2496            assert_eq!(hasher1.finish(), hasher2.finish());
2497            assert_eq!(val1, val2); // Verify they're actually equal
2498        }
2499
2500        #[test]
2501        fn test_complex_as_hashmap_key() {
2502            use crate::ComplexRugStrictFinite;
2503            type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2504
2505            let mut map = HashMap::new();
2506            let key1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
2507                .unwrap();
2508            let key2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (3.0, 4.0)))
2509                .unwrap();
2510
2511            map.insert(key1.clone(), "one_plus_two_i_rug");
2512            map.insert(key2.clone(), "three_plus_four_i_rug");
2513
2514            assert_eq!(map.get(&key1), Some(&"one_plus_two_i_rug"));
2515            assert_eq!(map.len(), 2);
2516
2517            // Overwrite an existing key
2518            let old_value = map.insert(key1.clone(), "updated_complex_rug");
2519            assert_eq!(old_value, Some("one_plus_two_i_rug"));
2520            assert_eq!(map.get(&key1), Some(&"updated_complex_rug"));
2521        }
2522
2523        #[test]
2524        fn test_complex_hash_consistency() {
2525            use crate::ComplexRugStrictFinite;
2526            use std::collections::hash_map::DefaultHasher;
2527            use std::hash::{Hash, Hasher};
2528            type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2529
2530            let val1 =
2531                ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.234, 5.678)))
2532                    .unwrap();
2533            let val2 =
2534                ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.234, 5.678)))
2535                    .unwrap();
2536
2537            // Equal values should have equal hashes
2538            let mut hasher1 = DefaultHasher::new();
2539            let mut hasher2 = DefaultHasher::new();
2540
2541            val1.hash(&mut hasher1);
2542            val2.hash(&mut hasher2);
2543
2544            assert_eq!(hasher1.finish(), hasher2.finish());
2545            assert_eq!(val1, val2);
2546        }
2547
2548        #[test]
2549        fn test_complex_hash_signed_zero() {
2550            use crate::ComplexRugStrictFinite;
2551            use std::collections::hash_map::DefaultHasher;
2552            use std::hash::{Hash, Hasher};
2553            type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2554
2555            // Test all combinations of signed zeros
2556            let val1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (0.0, 0.0)))
2557                .unwrap();
2558            let val2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (-0.0, 0.0)))
2559                .unwrap();
2560            let val3 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (0.0, -0.0)))
2561                .unwrap();
2562            let val4 =
2563                ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (-0.0, -0.0)))
2564                    .unwrap();
2565
2566            // All should be equal
2567            assert_eq!(val1, val2);
2568            assert_eq!(val1, val3);
2569            assert_eq!(val1, val4);
2570
2571            // All should have the same hash
2572            let mut hasher1 = DefaultHasher::new();
2573            let mut hasher2 = DefaultHasher::new();
2574            let mut hasher3 = DefaultHasher::new();
2575            let mut hasher4 = DefaultHasher::new();
2576
2577            val1.hash(&mut hasher1);
2578            val2.hash(&mut hasher2);
2579            val3.hash(&mut hasher3);
2580            val4.hash(&mut hasher4);
2581
2582            let hash1 = hasher1.finish();
2583            let hash2 = hasher2.finish();
2584            let hash3 = hasher3.finish();
2585            let hash4 = hasher4.finish();
2586
2587            assert_eq!(hash1, hash2);
2588            assert_eq!(hash1, hash3);
2589            assert_eq!(hash1, hash4);
2590        }
2591
2592        #[test]
2593        fn test_complex_hashset_operations() {
2594            use crate::ComplexRugStrictFinite;
2595            use std::collections::HashSet;
2596            type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2597
2598            let mut set = HashSet::new();
2599
2600            let val1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
2601                .unwrap();
2602            let val2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (3.0, 4.0)))
2603                .unwrap();
2604            let val1_duplicate =
2605                ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
2606                    .unwrap();
2607
2608            assert!(set.insert(val1.clone()));
2609            assert!(set.insert(val2.clone()));
2610            assert!(!set.insert(val1_duplicate)); // Should return false (already exists)
2611
2612            assert_eq!(set.len(), 2);
2613            assert!(set.contains(&val1));
2614        }
2615
2616        #[test]
2617        fn test_complex_different_precision_different_hash() {
2618            use crate::ComplexRugStrictFinite;
2619            use std::collections::hash_map::DefaultHasher;
2620            use std::hash::{Hash, Hasher};
2621
2622            const PRECISION_A: u32 = 64;
2623            const PRECISION_B: u32 = 128;
2624
2625            let val1 = ComplexRugStrictFinite::<PRECISION_A>::try_new(rug::Complex::with_val(
2626                PRECISION_A,
2627                (1.0, 2.0),
2628            ))
2629            .unwrap();
2630            let val2 = ComplexRugStrictFinite::<PRECISION_B>::try_new(rug::Complex::with_val(
2631                PRECISION_B,
2632                (1.0, 2.0),
2633            ))
2634            .unwrap();
2635
2636            // Values with different precision should have different hashes
2637            let mut hasher1 = DefaultHasher::new();
2638            let mut hasher2 = DefaultHasher::new();
2639
2640            val1.hash(&mut hasher1);
2641            val2.hash(&mut hasher2);
2642
2643            let hash1 = hasher1.finish();
2644            let hash2 = hasher2.finish();
2645
2646            // Different precisions should produce different hashes
2647            assert_ne!(hash1, hash2);
2648        }
2649    }
2650
2651    mod rug_float {
2652        use super::*;
2653
2654        mod from_f64 {
2655            use super::*;
2656            use crate::{RealRugStrictFinite, RealScalar};
2657
2658            const PRECISION: u32 = 100;
2659
2660            #[test]
2661            fn test_from_f64_valid_constants() {
2662                // Test with mathematical constants (known valid values)
2663                let pi = RealRugStrictFinite::<PRECISION>::from_f64(std::f64::consts::PI);
2664                let pi_f64 = pi.as_raw_scalar_ref().to_f64();
2665                assert!((pi_f64 - std::f64::consts::PI).abs() < 1e-15);
2666
2667                let e = RealRugStrictFinite::<PRECISION>::from_f64(std::f64::consts::E);
2668                let e_f64 = e.as_raw_scalar_ref().to_f64();
2669                assert!((e_f64 - std::f64::consts::E).abs() < 1e-15);
2670            }
2671
2672            #[test]
2673            fn test_from_f64_valid_simple_values() {
2674                // Test with simple values that are exactly representable
2675                let x = RealRugStrictFinite::<PRECISION>::from_f64(42.0);
2676                assert_eq!(x.as_raw_scalar_ref().to_f64(), 42.0);
2677
2678                let y = RealRugStrictFinite::<PRECISION>::from_f64(-3.0);
2679                assert_eq!(y.as_raw_scalar_ref().to_f64(), -3.0);
2680
2681                let z = RealRugStrictFinite::<PRECISION>::from_f64(0.0);
2682                assert_eq!(z.as_raw_scalar_ref().to_f64(), 0.0);
2683            }
2684
2685            #[test]
2686            #[should_panic(
2687                expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
2688            )]
2689            fn test_from_f64_nan_panics() {
2690                let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::NAN);
2691            }
2692
2693            #[test]
2694            #[should_panic(
2695                expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
2696            )]
2697            fn test_from_f64_infinity_panics() {
2698                let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::INFINITY);
2699            }
2700
2701            #[test]
2702            #[should_panic(
2703                expected = "RealScalar::try_from_f64() failed: invalid conversion from f64 value"
2704            )]
2705            fn test_from_f64_neg_infinity_panics() {
2706                let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::NEG_INFINITY);
2707            }
2708
2709            #[test]
2710            fn test_try_from_f64_exact_representation() {
2711                // PRECISION = 100 bits (> 53, so all f64 values are exactly representable)
2712
2713                // All finite f64 values should be accepted
2714                assert!(
2715                    RealRugStrictFinite::<PRECISION>::try_from_f64(0.1).is_ok(),
2716                    "0.1 (as f64 approximation) should be accepted at 100-bit precision"
2717                );
2718                assert!(
2719                    RealRugStrictFinite::<PRECISION>::try_from_f64(0.3).is_ok(),
2720                    "0.3 (as f64 approximation) should be accepted at 100-bit precision"
2721                );
2722                assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).is_ok());
2723                assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(2.5).is_ok());
2724                assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).is_ok());
2725
2726                // Invalid values (NaN, infinity) should be rejected
2727                assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(f64::NAN).is_err());
2728                assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(f64::INFINITY).is_err());
2729
2730                // `1.0 + f64::EPSILON` uses the least significant f64 mantissa bit,
2731                // so it requires the full 53-bit f64 precision and must fail at 52 bits.
2732                match RealRugStrictFinite::<52>::try_from_f64(1.0 + f64::EPSILON) {
2733                    Err(RawRealConversionError::NonRepresentableExactly {
2734                        precision_out, ..
2735                    }) => {
2736                        assert_eq!(precision_out, 52, "Error should report precision 52");
2737                    }
2738                    _ => panic!("Should reject precision < 53"),
2739                }
2740            }
2741        }
2742
2743        mod truncate_to_usize {
2744            use super::*;
2745            use rug::Float;
2746
2747            const PRECISION: u32 = 128;
2748
2749            #[test]
2750            fn test_rug_truncate_to_usize_valid() {
2751                assert_eq!(
2752                    Float::with_val(PRECISION, 42.0)
2753                        .truncate_to_usize()
2754                        .unwrap(),
2755                    42
2756                );
2757                assert_eq!(
2758                    Float::with_val(PRECISION, 42.9)
2759                        .truncate_to_usize()
2760                        .unwrap(),
2761                    42
2762                );
2763                assert_eq!(
2764                    Float::with_val(PRECISION, 0.0).truncate_to_usize().unwrap(),
2765                    0
2766                );
2767                assert_eq!(
2768                    Float::with_val(PRECISION, usize::MAX)
2769                        .truncate_to_usize()
2770                        .unwrap(),
2771                    usize::MAX
2772                );
2773            }
2774
2775            #[test]
2776            fn test_rug_truncate_to_usize_not_finite() {
2777                assert!(matches!(
2778                    Float::with_val(PRECISION, f64::NAN).truncate_to_usize(),
2779                    Err(ErrorsRawRealToInteger::NotFinite { .. })
2780                ));
2781                assert!(matches!(
2782                    Float::with_val(PRECISION, f64::INFINITY).truncate_to_usize(),
2783                    Err(ErrorsRawRealToInteger::NotFinite { .. })
2784                ));
2785                assert!(matches!(
2786                    Float::with_val(PRECISION, f64::NEG_INFINITY).truncate_to_usize(),
2787                    Err(ErrorsRawRealToInteger::NotFinite { .. })
2788                ));
2789            }
2790
2791            #[test]
2792            fn test_rug_truncate_to_usize_out_of_range() {
2793                // Negative value
2794                assert!(matches!(
2795                    Float::with_val(PRECISION, -1.0).truncate_to_usize(),
2796                    Err(ErrorsRawRealToInteger::OutOfRange { .. })
2797                ));
2798
2799                // Value too large
2800                let mut too_large = Float::with_val(PRECISION, usize::MAX);
2801                too_large += 1;
2802                assert!(matches!(
2803                    too_large.truncate_to_usize(),
2804                    Err(ErrorsRawRealToInteger::OutOfRange { .. })
2805                ));
2806            }
2807        }
2808    }
2809
2810    mod truncate_to_usize {
2811        use super::*;
2812        use rug::Float;
2813        use try_create::TryNew;
2814
2815        const PRECISION: u32 = 1000;
2816
2817        #[test]
2818        fn test_positive_integers() {
2819            let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 42.0))
2820                .unwrap();
2821            assert_eq!(value.truncate_to_usize().unwrap(), 42);
2822
2823            let value =
2824                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
2825            assert_eq!(value.truncate_to_usize().unwrap(), 1);
2826        }
2827
2828        #[test]
2829        fn test_positive_fractionals_truncate() {
2830            let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 42.9))
2831                .unwrap();
2832            assert_eq!(value.truncate_to_usize().unwrap(), 42);
2833
2834            let value =
2835                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.9)).unwrap();
2836            assert_eq!(value.truncate_to_usize().unwrap(), 0);
2837        }
2838
2839        #[test]
2840        fn test_zero_cases() {
2841            let value =
2842                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.0)).unwrap();
2843            assert_eq!(value.truncate_to_usize().unwrap(), 0);
2844        }
2845
2846        #[test]
2847        fn test_negative_values_error() {
2848            let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
2849                .unwrap();
2850            let result = value.truncate_to_usize();
2851            assert!(matches!(
2852                result,
2853                Err(ErrorsRawRealToInteger::OutOfRange { .. })
2854            ));
2855
2856            let value =
2857                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -10.5))
2858                    .unwrap();
2859            let result = value.truncate_to_usize();
2860            assert!(matches!(
2861                result,
2862                Err(ErrorsRawRealToInteger::OutOfRange { .. })
2863            ));
2864        }
2865
2866        #[test]
2867        fn test_large_values() {
2868            // Test with large but valid values
2869            let value =
2870                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1_000_000.0))
2871                    .unwrap();
2872            assert_eq!(value.truncate_to_usize().unwrap(), 1_000_000);
2873
2874            // Test with values too large for usize
2875            let value = RealRugStrictFinite::<PRECISION>::try_new(
2876                Float::with_val(PRECISION, 1e50), // Much larger than any usize
2877            )
2878            .unwrap();
2879            let result = value.truncate_to_usize();
2880            assert!(matches!(
2881                result,
2882                Err(ErrorsRawRealToInteger::OutOfRange { .. })
2883            ));
2884        }
2885
2886        #[test]
2887        fn test_high_precision_truncation() {
2888            // Test truncation with high precision values
2889            let value = RealRugStrictFinite::<PRECISION>::try_new(
2890                Float::parse("42.99999999999999999999999999999")
2891                    .unwrap()
2892                    .complete(PRECISION),
2893            )
2894            .unwrap();
2895            assert_eq!(value.truncate_to_usize().unwrap(), 42);
2896
2897            // Very small positive value should truncate to 0
2898            let value = RealRugStrictFinite::<PRECISION>::try_new(
2899                Float::parse("0.99999999999999999999999999999")
2900                    .unwrap()
2901                    .complete(PRECISION),
2902            )
2903            .unwrap();
2904            assert_eq!(value.truncate_to_usize().unwrap(), 0);
2905        }
2906
2907        #[test]
2908        fn test_conversion_from_f64() {
2909            // Test truncation after conversion from f64
2910            let value = RealRugStrictFinite::<PRECISION>::try_from_f64(42.7).unwrap();
2911            assert_eq!(value.truncate_to_usize().unwrap(), 42);
2912
2913            let value = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
2914            assert_eq!(value.truncate_to_usize().unwrap(), 0);
2915        }
2916    }
2917}