num_valid/kernels/
rug.rs

1#![deny(rustdoc::broken_intra_doc_links)]
2
3use crate::{
4    RealScalar,
5    functions::{Conjugate, NegAssign, Rounding, Sign},
6    kernels::{
7        ComplexValidated, NumKernelStrictFinite, RawComplexTrait, RawRealTrait, RawScalarTrait,
8        RealValidated,
9    },
10    validation::{
11        ErrorsTryFromf64, ErrorsValidationRawComplex, ErrorsValidationRawReal, FpChecks,
12        ValidationPolicyReal,
13    },
14};
15use derive_more::with_trait::Neg;
16use duplicate::duplicate_item;
17use num::Complex;
18use rug::ops::{CompleteRound, Pow as RugPow};
19use std::{backtrace::Backtrace, cmp::Ordering, marker::PhantomData, num::FpCategory};
20use try_create::IntoInner;
21
22impl RawScalarTrait for rug::Float {
23    type ValidationErrors = ErrorsValidationRawReal<rug::Float>;
24
25    fn raw_zero(precision: u32) -> Self {
26        rug::Float::with_val(precision, 0.)
27    }
28
29    fn is_zero(&self) -> bool {
30        rug::Float::is_zero(self)
31    }
32
33    fn raw_one(precision: u32) -> Self {
34        rug::Float::with_val(precision, 1.)
35    }
36
37    #[duplicate_item(
38        unchecked_method       method;
39        [unchecked_reciprocal] [recip];
40        [unchecked_exp]        [exp];
41        [unchecked_sqrt]       [sqrt];
42        [unchecked_sin]        [sin];
43        [unchecked_asin]       [asin];
44        [unchecked_cos]        [cos];
45        [unchecked_acos]       [acos];
46        [unchecked_tan]        [tan];
47        [unchecked_atan]       [atan];
48        [unchecked_sinh]       [sinh];
49        [unchecked_asinh]      [asinh];
50        [unchecked_cosh]       [cosh];
51        [unchecked_acosh]      [acosh];
52        [unchecked_tanh]       [tanh];
53        [unchecked_atanh]      [atanh];
54        [unchecked_ln]         [ln];
55        [unchecked_log2]       [log2];
56        [unchecked_log10]      [log10];
57    )]
58    #[inline(always)]
59    fn unchecked_method(self) -> Self {
60        rug::Float::method(self)
61    }
62
63    #[duplicate_item(
64        unchecked_method               exponent_type;
65        [unchecked_pow_exponent_i8]    [i8];
66        [unchecked_pow_exponent_i16]   [i16];
67        [unchecked_pow_exponent_i32]   [i32];
68        [unchecked_pow_exponent_i64]   [i64];
69        [unchecked_pow_exponent_i128]  [i128];
70        [unchecked_pow_exponent_isize] [isize];
71        [unchecked_pow_exponent_u8]    [u8];
72        [unchecked_pow_exponent_u16]   [u16];
73        [unchecked_pow_exponent_u32]   [u32];
74        [unchecked_pow_exponent_u64]   [u64];
75        [unchecked_pow_exponent_u128]  [u128];
76        [unchecked_pow_exponent_usize] [usize];
77    )]
78    #[inline(always)]
79    fn unchecked_method(self, exponent: &exponent_type) -> Self {
80        rug::Float::pow(self, exponent)
81    }
82
83    /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
84    ///
85    /// `a.mul_add(b, c)` produces a result like `a * &b + &c`.
86    #[inline(always)]
87    fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
88        rug::Float::mul_add(self, b, c)
89    }
90}
91
92impl RawRealTrait for rug::Float {
93    type RawComplex = rug::Complex;
94
95    #[inline(always)]
96    fn unchecked_abs(self) -> rug::Float {
97        rug::Float::abs(self)
98    }
99
100    #[inline(always)]
101    fn unchecked_atan2(self, denominator: &Self) -> Self {
102        rug::Float::atan2(self, denominator)
103    }
104
105    #[inline(always)]
106    fn unchecked_pow_exponent_real(self, exponent: &Self) -> Self {
107        rug::Float::pow(self, exponent)
108    }
109
110    fn unchecked_hypot(self, other: &Self) -> Self {
111        rug::Float::hypot(self, other)
112    }
113
114    fn unchecked_ln_1p(self) -> Self {
115        rug::Float::ln_1p(self)
116    }
117
118    fn unchecked_exp_m1(self) -> Self {
119        rug::Float::exp_m1(self)
120    }
121
122    /// Multiplies two pairs and adds them in one fused operation, rounding to the nearest with only one rounding error.
123    /// `a.unchecked_mul_add_mul_mut(&b, &c, &d)` produces a result like `&a * &b + &c * &d`, but stores the result in `a` using its precision.
124    #[inline(always)]
125    fn unchecked_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self) {
126        self.mul_add_mul_mut(mul, add_mul1, add_mul2);
127    }
128
129    /// Multiplies two pairs and subtracts them in one fused operation, rounding to the nearest with only one rounding error.
130    /// `a.unchecked_mul_sub_mul_mut(&b, &c, &d)` produces a result like `&a * &b - &c * &d`, but stores the result in `a` using its precision.
131    #[inline(always)]
132    fn unchecked_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self) {
133        self.mul_sub_mul_mut(mul, sub_mul1, sub_mul2);
134    }
135
136    fn raw_total_cmp(&self, other: &Self) -> Ordering {
137        rug::Float::total_cmp(self, other)
138    }
139
140    /// Clamps the value within the specified bounds.
141    fn raw_clamp(self, min: &Self, max: &Self) -> Self {
142        rug::Float::clamp(self, min, max)
143    }
144
145    fn raw_classify(&self) -> FpCategory {
146        rug::Float::classify(self)
147    }
148
149    #[inline(always)]
150    fn raw_two(precision: u32) -> Self {
151        rug::Float::with_val(precision, 2.)
152    }
153
154    #[inline(always)]
155    fn raw_one_div_2(precision: u32) -> Self {
156        rug::Float::with_val(precision, 0.5)
157    }
158
159    fn raw_pi(precision: u32) -> Self {
160        rug::Float::with_val(precision, -1.).acos()
161    }
162
163    fn raw_two_pi(precision: u32) -> Self {
164        Self::raw_pi(precision) * rug::Float::with_val(precision, 2.)
165    }
166
167    fn raw_pi_div_2(precision: u32) -> Self {
168        rug::Float::with_val(precision, 1.).asin()
169    }
170
171    fn raw_max_finite(precision: u32) -> Self {
172        // Create a Float with the desired precision
173        // let f = rug::Float::new(PRECISION);
174
175        // Fill the significand with all 1s: 1 - 2^(-precision)
176        // This gives you the largest significand before it rolls over
177        let one = rug::Float::with_val(precision, 1);
178        let eps = rug::Float::with_val(precision, rug::Float::u_pow_u(2, precision)).recip();
179        let significand = one - &eps;
180
181        // Scale it to the maximum exponent (subtract 1 to avoid overflow to infinity)
182        let max_exp = rug::float::exp_max() - 1;
183        //        println!("max_exp = {max_exp}");
184        significand * rug::Float::with_val(precision, rug::Float::u_pow_u(2, max_exp as u32))
185    }
186
187    fn raw_min_finite(precision: u32) -> Self {
188        Self::raw_max_finite(precision).neg()
189    }
190
191    fn raw_epsilon(precision: u32) -> Self {
192        rug::Float::u_pow_u(2, precision - 1)
193            .complete(precision)
194            .recip()
195    }
196
197    fn raw_ln_2(precision: u32) -> Self {
198        rug::Float::with_val(precision, 2.).ln()
199    }
200
201    fn raw_ln_10(precision: u32) -> Self {
202        rug::Float::with_val(precision, 10.).ln()
203    }
204
205    fn raw_log10_2(precision: u32) -> Self {
206        rug::Float::with_val(precision, 2.).log10()
207    }
208
209    fn raw_log2_10(precision: u32) -> Self {
210        rug::Float::with_val(precision, 10.).log2()
211    }
212
213    fn raw_log2_e(precision: u32) -> Self {
214        Self::raw_e(precision).log2()
215    }
216
217    fn raw_log10_e(precision: u32) -> Self {
218        Self::raw_e(precision).log10()
219    }
220
221    fn raw_e(precision: u32) -> Self {
222        rug::Float::with_val(precision, 1.).exp()
223    }
224
225    #[inline(always)]
226    fn try_new_raw_real_from_f64<RealPolicy: ValidationPolicyReal<Value = Self>>(
227        value: f64,
228    ) -> Result<Self, ErrorsTryFromf64<Self>> {
229        let precision = RealPolicy::PRECISION;
230        let value_rug = RealPolicy::validate(rug::Float::with_val(precision, value))
231            .map_err(|e| ErrorsTryFromf64::Output { source: e })?;
232        if value_rug == value {
233            Ok(value_rug)
234        } else {
235            Err(ErrorsTryFromf64::NonRepresentableExactly {
236                value_in: value,
237                value_converted_from_f64: value_rug,
238                precision,
239                backtrace: Backtrace::force_capture(),
240            })
241        }
242    }
243
244    fn precision(&self) -> u32 {
245        rug::Float::prec(self)
246    }
247}
248
249impl RawScalarTrait for rug::Complex {
250    type ValidationErrors = ErrorsValidationRawComplex<ErrorsValidationRawReal<rug::Float>>;
251
252    fn raw_zero(precision: u32) -> Self {
253        rug::Complex::with_val(precision, (0., 0.))
254    }
255
256    fn is_zero(&self) -> bool {
257        rug::Complex::is_zero(self)
258    }
259
260    fn raw_one(precision: u32) -> Self {
261        rug::Complex::with_val(precision, (1., 0.))
262    }
263
264    #[duplicate_item(
265        unchecked_method       method;
266        [unchecked_reciprocal] [recip];
267        [unchecked_exp]        [exp];
268        [unchecked_sqrt]       [sqrt];
269        [unchecked_sin]        [sin];
270        [unchecked_asin]       [asin];
271        [unchecked_cos]        [cos];
272        [unchecked_acos]       [acos];
273        [unchecked_tan]        [tan];
274        [unchecked_atan]       [atan];
275        [unchecked_sinh]       [sinh];
276        [unchecked_asinh]      [asinh];
277        [unchecked_cosh]       [cosh];
278        [unchecked_acosh]      [acosh];
279        [unchecked_tanh]       [tanh];
280        [unchecked_atanh]      [atanh];
281        [unchecked_ln]         [ln];
282        [unchecked_log10]      [log10];
283    )]
284    #[inline(always)]
285    fn unchecked_method(self) -> Self {
286        rug::Complex::method(self)
287    }
288
289    #[inline(always)]
290    fn unchecked_log2(self) -> Self {
291        let ln_2 = rug::Float::with_val(self.real().prec(), 2.).ln();
292        rug::Complex::ln(self) / ln_2
293    }
294
295    #[duplicate_item(
296        unchecked_method               exponent_type;
297        [unchecked_pow_exponent_i8]    [i8];
298        [unchecked_pow_exponent_i16]   [i16];
299        [unchecked_pow_exponent_i32]   [i32];
300        [unchecked_pow_exponent_i64]   [i64];
301        [unchecked_pow_exponent_i128]  [i128];
302        [unchecked_pow_exponent_isize] [isize];
303        [unchecked_pow_exponent_u8]    [u8];
304        [unchecked_pow_exponent_u16]   [u16];
305        [unchecked_pow_exponent_u32]   [u32];
306        [unchecked_pow_exponent_u64]   [u64];
307        [unchecked_pow_exponent_u128]  [u128];
308        [unchecked_pow_exponent_usize] [usize];
309    )]
310    #[inline(always)]
311    fn unchecked_method(self, exponent: &exponent_type) -> Self {
312        rug::Complex::pow(self, exponent)
313    }
314
315    /// Multiplies and adds in one fused operation, rounding to the nearest with only one rounding error.
316    ///
317    /// `a.mul_add(b, c)` produces a result like `a * &b + &c`.
318    #[inline(always)]
319    fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
320        rug::Complex::mul_add(self, b, c)
321    }
322}
323
324impl Conjugate for rug::Complex {
325    #[inline(always)]
326    fn conjugate(self) -> Self {
327        rug::Complex::conj(self)
328    }
329}
330
331impl RawComplexTrait for rug::Complex {
332    type RawReal = rug::Float;
333
334    fn new_unchecked_raw_complex(real: rug::Float, imag: rug::Float) -> Self {
335        debug_assert_eq!(
336            real.prec(),
337            imag.prec(),
338            "Different precision between real and imaginary part!"
339        );
340        rug::Complex::with_val(real.prec(), (real, imag))
341    }
342
343    /// Returns a mutable reference to the real part of the complex number.
344    fn mut_raw_real_part(&mut self) -> &mut rug::Float {
345        self.mut_real()
346    }
347
348    /// Returns a mutable reference to the imaginary part of the complex number.
349    fn mut_raw_imag_part(&mut self) -> &mut rug::Float {
350        self.mut_imag()
351    }
352
353    #[inline(always)]
354    fn unchecked_abs(self) -> rug::Float {
355        rug::Complex::abs(self).into_real_imag().0
356    }
357
358    #[inline(always)]
359    fn raw_real_part(&self) -> &rug::Float {
360        self.real()
361    }
362
363    #[inline(always)]
364    fn raw_imag_part(&self) -> &rug::Float {
365        self.imag()
366    }
367
368    #[inline(always)]
369    fn unchecked_arg(self) -> rug::Float {
370        rug::Complex::arg(self).into_real_imag().0
371    }
372
373    #[inline(always)]
374    fn unchecked_pow_exponent_real(self, exponent: &rug::Float) -> Self {
375        rug::Complex::pow(self, exponent)
376    }
377}
378
379impl FpChecks for rug::Float {
380    fn is_finite(&self) -> bool {
381        rug::Float::is_finite(self)
382    }
383
384    fn is_infinite(&self) -> bool {
385        rug::Float::is_infinite(self)
386    }
387
388    fn is_nan(&self) -> bool {
389        rug::Float::is_nan(self)
390    }
391    fn is_normal(&self) -> bool {
392        rug::Float::is_normal(self)
393    }
394}
395
396impl FpChecks for rug::Complex {
397    /// Returns `true` if the real and imaginary parts of `self` are neither infinite nor NaN.
398    #[inline(always)]
399    fn is_finite(&self) -> bool {
400        self.real().is_finite() && self.imag().is_finite()
401    }
402
403    /// Returns `true` if the real or the imaginary part of `self` are positive infinity or negative infinity.
404    #[inline(always)]
405    fn is_infinite(&self) -> bool {
406        !self.is_nan() && (self.real().is_infinite() || self.imag().is_infinite())
407    }
408
409    /// Returns `true` if the real or the imaginary part of `self` are NaN.
410    #[inline(always)]
411    fn is_nan(&self) -> bool {
412        self.real().is_nan() || self.imag().is_nan()
413    }
414
415    /// Returns `true` if the real and the imaginary part of `self` are *normal* (i.e. neither zero, infinite, subnormal, or NaN).
416    #[inline(always)]
417    fn is_normal(&self) -> bool {
418        self.real().is_normal() && self.imag().is_normal()
419    }
420}
421
422//------------------------------------------------------------------------------------------------------------
423/// A type alias for a numerical kernel that uses `rug` for arbitrary-precision arithmetic with strict finiteness checks.
424///
425/// This policy is a specialization of [`NumKernelStrictFinite`] for the `rug` backend.
426/// It bundles the raw `rug` types ([`rug::Float`] and [`rug::Complex`]) with their corresponding
427/// validation logic, [`StrictFinitePolicy`](crate::validation::StrictFinitePolicy).
428///
429/// The primary role of this policy is to serve as the generic parameter for the main validated
430/// types, [`RealRugStrictFinite<PRECISION>`] and [`ComplexRugStrictFinite<PRECISION>`], thereby
431/// defining their behavior and ensuring their correctness.
432///
433/// # Validation
434///
435/// This policy enforces the following rules on the underlying [`rug::Float`] values, for both
436/// real numbers and the components of complex numbers:
437///
438/// 1.  **Finiteness**: The value must not be `NaN` or `Infinity`.
439/// 2.  **Precision**: The precision of the [`rug::Float`] must exactly match the `PRECISION`
440///     constant specified in the type. This is a critical check for `rug` types.
441///
442/// # Example
443///
444/// While you typically won't use `RugStrictFinite` directly, it's the engine that
445/// powers the validated `rug` types.
446///
447/// ```rust
448/// use num_valid::{RealRugStrictFinite, ComplexRugStrictFinite};
449/// use rug::{Float, Complex};
450/// use try_create::TryNew;
451///
452/// const PRECISION: u32 = 100;
453///
454/// // This works because the value is finite and has the correct precision.
455/// let valid_real = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.14)).unwrap();
456///
457/// // This fails because the precision is wrong.
458/// let wrong_precision_real = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION + 1, 3.14));
459/// assert!(wrong_precision_real.is_err());
460///
461/// // This fails because the value is NaN.
462/// let nan_real = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, f64::NAN));
463/// assert!(nan_real.is_err());
464///
465/// // The same rules apply to complex numbers.
466/// let valid_complex = ComplexRugStrictFinite::<PRECISION>::try_new(
467///     Complex::with_val(PRECISION, (1.0, 2.0))
468/// ).unwrap();
469///
470/// let invalid_complex = ComplexRugStrictFinite::<PRECISION>::try_new(
471///     Complex::with_val(PRECISION, (1.0, f64::INFINITY))
472/// );
473/// assert!(invalid_complex.is_err());
474/// ```
475pub type RugStrictFinite<const PRECISION: u32> = NumKernelStrictFinite<rug::Float, PRECISION>;
476//------------------------------------------------------------------------------------------------------------
477
478//------------------------------------------------------------------------------------------------------------
479/// A type alias for a validated real scalar using the `Rug` kernel with a specified precision and the `NumKernelStrictFinite` validation policy.
480pub type RealRugStrictFinite<const PRECISION: u32> = RealValidated<RugStrictFinite<PRECISION>>;
481
482/// A type alias for a validated complex scalar using the `Rug` kernel with a specified precision and the `NumKernelStrictFinite` validation policy.
483pub type ComplexRugStrictFinite<const PRECISION: u32> =
484    ComplexValidated<RugStrictFinite<PRECISION>>;
485
486impl Sign for rug::Float {
487    /// Returns a number with the magnitude of `self` and the sign of `sign`.
488    #[inline(always)]
489    fn kernel_copysign(self, sign: &Self) -> Self {
490        self.copysign(sign)
491    }
492
493    /// Returns `true` if the value is negative, −0 or NaN with a negative sign.
494    #[inline(always)]
495    fn kernel_is_sign_negative(&self) -> bool {
496        self.is_sign_negative()
497    }
498
499    /// Returns `true` if the value is positive, +0 or NaN with a positive sign.
500    #[inline(always)]
501    fn kernel_is_sign_positive(&self) -> bool {
502        self.is_sign_positive()
503    }
504
505    /// Returns the signum of the number.
506    ///
507    /// This method relies on `rug::Float::signum()`.
508    /// The behavior for special values is as follows:
509    /// - If the number is positive and not zero, returns `1.0`.
510    /// - If the number is negative and not zero, returns `-1.0`.
511    /// - If the number is zero, `rug::Float::signum()` returns `1.0` (representing positive zero).
512    #[inline(always)]
513    fn kernel_signum(self) -> Self {
514        self.signum()
515    }
516}
517
518impl Rounding for rug::Float {
519    /// Returns the smallest integer greater than or equal to `self`.
520    #[inline(always)]
521    fn kernel_ceil(self) -> Self {
522        self.ceil()
523    }
524
525    /// Returns the largest integer smaller than or equal to `self`.
526    #[inline(always)]
527    fn kernel_floor(self) -> Self {
528        self.floor()
529    }
530
531    /// Returns the fractional part of `self`.
532    #[inline(always)]
533    fn kernel_fract(self) -> Self {
534        self.fract()
535    }
536
537    /// Rounds `self` to the nearest integer, rounding half-way cases away from zero.
538    #[inline(always)]
539    fn kernel_round(self) -> Self {
540        self.round()
541    }
542
543    /// Returns the nearest integer to a number. Rounds half-way cases to the number with an even least significant digit.
544    ///
545    /// This function always returns the precise result.
546    ///
547    /// # Examples
548    /// ```
549    /// use num_valid::{RealScalar, RealRugStrictFinite, functions::Rounding};
550    ///
551    /// const PRECISION: u32 = 100;
552    ///
553    /// let f = RealRugStrictFinite::<PRECISION>::try_from_f64(3.3).unwrap();
554    /// let g = RealRugStrictFinite::<PRECISION>::try_from_f64(-3.3).unwrap();
555    /// let h = RealRugStrictFinite::<PRECISION>::try_from_f64(3.5).unwrap();
556    /// let i = RealRugStrictFinite::<PRECISION>::try_from_f64(-4.5).unwrap();
557    ///
558    /// assert_eq!(f.kernel_round_ties_even(), RealRugStrictFinite::<PRECISION>::try_from_f64(3.).unwrap());
559    /// assert_eq!(g.kernel_round_ties_even(), RealRugStrictFinite::<PRECISION>::try_from_f64(-3.).unwrap());
560    /// assert_eq!(h.kernel_round_ties_even(), RealRugStrictFinite::<PRECISION>::try_from_f64(4.).unwrap());
561    /// assert_eq!(i.kernel_round_ties_even(), RealRugStrictFinite::<PRECISION>::try_from_f64(-4.).unwrap());
562    /// ```
563    #[inline(always)]
564    fn kernel_round_ties_even(self) -> Self {
565        self.round_even()
566    }
567
568    /// Returns the integer part of `self`. This means that non-integer numbers are always truncated towards zero.
569    ///    
570    /// # Examples
571    /// ```
572    /// use num_valid::{RealScalar, RealRugStrictFinite, functions::Rounding};
573    ///
574    /// const PRECISION: u32 = 100;
575    ///
576    /// let f = RealRugStrictFinite::<PRECISION>::try_from_f64(3.7).unwrap();
577    /// let g = RealRugStrictFinite::<PRECISION>::try_from_f64(3.).unwrap();
578    /// let h = RealRugStrictFinite::<PRECISION>::try_from_f64(-3.7).unwrap();
579    ///
580    /// assert_eq!(f.kernel_trunc(), RealRugStrictFinite::<PRECISION>::try_from_f64(3.).unwrap());
581    /// assert_eq!(g.kernel_trunc(), RealRugStrictFinite::<PRECISION>::try_from_f64(3.).unwrap());
582    /// assert_eq!(h.kernel_trunc(), RealRugStrictFinite::<PRECISION>::try_from_f64(-3.).unwrap());
583    /// ```
584    #[inline(always)]
585    fn kernel_trunc(self) -> Self {
586        self.trunc()
587    }
588}
589
590//------------------------------------------------------------------------------------------------------------
591
592//-------------------------------------------------------------
593impl<const PRECISION: u32> TryFrom<Complex<f64>> for ComplexRugStrictFinite<PRECISION> {
594    type Error = ErrorsValidationRawComplex<ErrorsTryFromf64<rug::Float>>;
595
596    fn try_from(value: Complex<f64>) -> Result<Self, Self::Error> {
597        let real_part = RealRugStrictFinite::<PRECISION>::try_from_f64(value.re);
598        let imag_part = RealRugStrictFinite::<PRECISION>::try_from_f64(value.im);
599
600        match (real_part, imag_part) {
601            (Ok(real_part), Ok(imag_part)) => Ok(Self {
602                value: rug::Complex::with_val(
603                    PRECISION,
604                    (real_part.into_inner(), imag_part.into_inner()),
605                ),
606                _phantom: PhantomData,
607            }),
608            (Err(error_real_part), Ok(_)) => Err(ErrorsValidationRawComplex::InvalidRealPart {
609                source: error_real_part,
610            }),
611            (Ok(_), Err(error_imaginary_part)) => {
612                Err(ErrorsValidationRawComplex::InvalidImaginaryPart {
613                    source: error_imaginary_part,
614                })
615            }
616            (Err(error_real_part), Err(error_imaginary_part)) => {
617                Err(ErrorsValidationRawComplex::InvalidBothParts {
618                    real_error: error_real_part,
619                    imag_error: error_imaginary_part,
620                })
621            }
622        }
623    }
624}
625//------------------------------------------------------------------------------------------------
626
627//------------------------------------------------------------------------------------------------
628
629#[duplicate::duplicate_item(
630    T;
631    [rug::Float];
632    [rug::Complex];
633)]
634/// Compound negation and assignment.
635impl NegAssign for T {
636    /// Performs the negation of `self`.
637    fn neg_assign(&mut self) {
638        <T as rug::ops::NegAssign>::neg_assign(self);
639    }
640}
641//------------------------------------------------------------------------------------------------
642
643//------------------------------------------------------------------------------------------------
644
645#[cfg(test)]
646mod tests {
647    use super::*;
648    use crate::{
649        ACosH, ComplexRugStrictFinite, ComplexScalarConstructors, ComplexScalarGetParts,
650        ComplexScalarMutateParts, ComplexScalarSetParts, Constants, Max, Min,
651        functions::{
652            ACos, ACosHErrors, ACosHInputErrors, ACosRealErrors, ACosRealInputErrors, ASin,
653            ASinRealErrors, ASinRealInputErrors, ATan, ATan2, ATan2Errors, ATanComplexErrors,
654            ATanComplexInputErrors, ATanH, ATanHErrors, ATanHInputErrors, Abs, Clamp, Exp,
655            ExpErrors, Hypot, Ln, Log2, LogarithmComplexErrors, LogarithmComplexInputErrors,
656            NegAssign, Pow, PowComplexBaseRealExponentErrors, PowIntExponentErrors,
657            PowIntExponentInputErrors, PowRealBaseRealExponentErrors, Reciprocal, ReciprocalErrors,
658            Sqrt, SqrtRealErrors, TotalCmp,
659        },
660        validation::ErrorsValidationRawReal,
661    };
662    use num::{One, Zero};
663    use rug::Float;
664    use try_create::{TryNew, TryNewValidated};
665
666    const PRECISION: u32 = 53;
667
668    mod fp_checks {
669        use super::*;
670        use crate::kernels::rug::{ComplexRugStrictFinite, RealRugStrictFinite};
671        use rug::Float;
672
673        #[test]
674        fn is_finite() {
675            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
676            assert!(real.is_finite());
677
678            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::INFINITY));
679            assert!(real.is_err());
680
681            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
682                53,
683                (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
684            ))
685            .unwrap();
686            assert!(complex.is_finite());
687
688            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
689                53,
690                (Float::with_val(53, f64::INFINITY), Float::with_val(53, 1.0)),
691            ));
692            assert!(complex.is_err());
693        }
694
695        #[test]
696        fn is_infinite() {
697            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
698            assert!(!real.is_infinite());
699
700            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::INFINITY));
701            assert!(real.is_err());
702
703            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
704                53,
705                (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
706            ))
707            .unwrap();
708            assert!(!complex.is_infinite());
709
710            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
711                53,
712                (Float::with_val(53, f64::INFINITY), Float::with_val(53, 1.0)),
713            ));
714            assert!(complex.is_err());
715        }
716
717        #[test]
718        fn is_nan() {
719            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
720            assert!(!real.is_nan());
721
722            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::NAN));
723            assert!(matches!(real, Err(ErrorsValidationRawReal::IsNaN { .. })));
724
725            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
726                53,
727                (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
728            ))
729            .unwrap();
730            assert!(!complex.is_nan());
731
732            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
733                53,
734                (Float::with_val(53, f64::NAN), Float::with_val(53, 1.0)),
735            ));
736            assert!(matches!(
737                complex,
738                Err(ErrorsValidationRawComplex::InvalidRealPart {
739                    source: ErrorsValidationRawReal::IsNaN { .. }
740                })
741            ));
742        }
743
744        #[test]
745        fn is_normal() {
746            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
747            assert!(real.is_normal());
748
749            let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
750            assert!(!real.is_normal());
751
752            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
753                53,
754                (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
755            ))
756            .unwrap();
757            assert!(complex.is_normal());
758
759            let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
760                53,
761                (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
762            ))
763            .unwrap();
764            assert!(!complex.is_normal());
765        }
766    }
767
768    mod abs {
769        use super::*;
770
771        mod real {
772            use super::*;
773
774            #[test]
775            fn abs_valid() {
776                let value =
777                    RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, -4.0)).unwrap();
778
779                let expected_result =
780                    RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 4.0)).unwrap();
781                assert_eq!(value.clone().try_abs().unwrap(), expected_result);
782                assert_eq!(value.abs(), expected_result);
783            }
784
785            #[test]
786            fn abs_zero() {
787                let value =
788                    RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
789
790                let expected_result =
791                    RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
792                assert_eq!(value.clone().try_abs().unwrap(), expected_result);
793                assert_eq!(value.abs(), expected_result);
794            }
795
796            /*
797            #[cfg(feature = "rug")]
798            #[test]
799            fn abs_nan() {
800                let value =
801                    RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, rug::float::Special::Nan))
802                        .unwrap();
803                let result = value.try_abs();
804                assert!(matches!(result, Err(AbsRealErrors::Input { .. })));
805            }
806
807            #[cfg(feature = "rug")]
808            #[test]
809            fn abs_infinite() {
810                let value = RealRugStrictFinite::<53>::try_new(rug::Float::with_val(
811                    53,
812                    rug::float::Special::Infinity,
813                ))
814                .unwrap();
815                let result = value.try_abs();
816                assert!(matches!(result, Err(AbsRealErrors::Input { .. })));
817            }
818            */
819        }
820
821        mod complex {
822            use super::*;
823
824            #[test]
825            fn abs_valid() {
826                let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
827                    53,
828                    (rug::Float::with_val(53, 3.0), rug::Float::with_val(53, 4.0)),
829                ))
830                .unwrap();
831
832                let expected_result =
833                    RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 5.0)).unwrap();
834                assert_eq!(value.clone().try_abs().unwrap(), expected_result);
835                assert_eq!(value.abs(), expected_result);
836            }
837
838            #[test]
839            fn abs_zero() {
840                let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
841                    53,
842                    (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
843                ))
844                .unwrap();
845
846                let expected_result =
847                    RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
848                assert_eq!(value.clone().try_abs().unwrap(), expected_result);
849                assert_eq!(value.abs(), expected_result);
850            }
851            /*
852            #[test]
853            fn abs_nan() {
854                let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
855                    53,
856                    (
857                        rug::Float::with_val(53, rug::float::Special::Nan),
858                        rug::Float::with_val(53, 0.0),
859                    ),
860                ))
861                .unwrap();
862                assert!(matches!(
863                    value.try_abs(),
864                    Err(AbsComplexErrors::Input { .. })
865                ));
866            }
867
868            #[test]
869            fn abs_infinite() {
870                let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
871                    53,
872                    (
873                        rug::Float::with_val(53, rug::float::Special::Infinity),
874                        rug::Float::with_val(53, 0.0),
875                    ),
876                ))
877                .unwrap();
878                assert!(matches!(
879                    value.try_abs(),
880                    Err(AbsComplexErrors::Input { .. })
881                ));
882            }
883            */
884        }
885    }
886
887    mod max_min {
888        use super::*;
889
890        #[test]
891        fn test_realrug_max() {
892            let value =
893                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
894            let other =
895                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
896            let expected =
897                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
898            assert_eq!(Max::max(&value, &other), &expected);
899
900            let neg_value =
901                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
902                    .unwrap();
903            let neg_other =
904                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
905                    .unwrap();
906            let neg_expected =
907                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
908                    .unwrap();
909            assert_eq!(Max::max(&neg_value, &neg_other), &neg_expected);
910        }
911
912        #[test]
913        fn test_realrug_min() {
914            let value =
915                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
916            let other =
917                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
918            let expected =
919                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
920            assert_eq!(Min::min(&value, &other), &expected);
921
922            let neg_value =
923                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
924                    .unwrap();
925            let neg_other =
926                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
927                    .unwrap();
928            let neg_expected =
929                RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
930                    .unwrap();
931            assert_eq!(Min::min(&neg_value, &neg_other), &neg_expected);
932        }
933    }
934
935    mod builders {
936        use super::*;
937
938        mod real {
939            use super::*;
940
941            #[test]
942            fn try_new_nan() {
943                let nan = rug::Float::with_val(PRECISION, f64::NAN);
944                let err = RealRugStrictFinite::<PRECISION>::try_new(nan).unwrap_err();
945                assert!(matches!(err, ErrorsValidationRawReal::IsNaN { .. }));
946            }
947
948            #[test]
949            fn try_new_pos_infinity() {
950                let pos_infinity = rug::Float::with_val(PRECISION, f64::INFINITY);
951                let err = RealRugStrictFinite::<PRECISION>::try_new(pos_infinity).unwrap_err();
952                assert!(matches!(err, ErrorsValidationRawReal::IsPosInfinity { .. }));
953            }
954
955            #[test]
956            fn try_new_neg_infinity() {
957                let neg_infinity = rug::Float::with_val(PRECISION, f64::NEG_INFINITY);
958                let err = RealRugStrictFinite::<PRECISION>::try_new(neg_infinity).unwrap_err();
959                assert!(matches!(err, ErrorsValidationRawReal::IsNegInfinity { .. }));
960            }
961        }
962
963        mod complex {
964            use super::*;
965
966            #[test]
967            fn real_part() {
968                let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
969                    rug::Complex::with_val(PRECISION, (1.23, 4.56)),
970                )
971                .unwrap();
972                assert_eq!(c1.real_part(), 1.23);
973
974                let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
975                    rug::Complex::with_val(PRECISION, (-7.89, 0.12)),
976                )
977                .unwrap();
978                assert_eq!(c2.real_part(), -7.89);
979
980                let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
981                    rug::Complex::with_val(PRECISION, (0.0, 10.0)),
982                )
983                .unwrap();
984                assert_eq!(c3.real_part(), 0.0);
985
986                let c_nan_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
987                    rug::Complex::with_val(PRECISION, (f64::NAN, 5.0)),
988                )
989                .unwrap_err();
990                assert!(matches!(
991                    c_nan_re,
992                    ErrorsValidationRawComplex::InvalidRealPart {
993                        source: ErrorsValidationRawReal::IsNaN { .. }
994                    }
995                ));
996
997                let c_inf_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
998                    rug::Complex::with_val(PRECISION, (f64::INFINITY, 5.0)),
999                )
1000                .unwrap_err();
1001                assert!(matches!(
1002                    c_inf_re,
1003                    ErrorsValidationRawComplex::InvalidRealPart {
1004                        source: ErrorsValidationRawReal::IsPosInfinity { .. }
1005                    }
1006                ));
1007
1008                let c_neg_inf_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1009                    rug::Complex::with_val(PRECISION, (f64::NEG_INFINITY, 5.0)),
1010                )
1011                .unwrap_err();
1012                assert!(matches!(
1013                    c_neg_inf_re,
1014                    ErrorsValidationRawComplex::InvalidRealPart {
1015                        source: ErrorsValidationRawReal::IsNegInfinity { .. }
1016                    }
1017                ));
1018            }
1019
1020            #[test]
1021            fn imag_part() {
1022                let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1023                    rug::Complex::with_val(PRECISION, (1.23, 4.56)),
1024                )
1025                .unwrap();
1026                assert_eq!(c1.imag_part(), 4.56);
1027
1028                let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1029                    rug::Complex::with_val(PRECISION, (-7.89, 0.12)),
1030                )
1031                .unwrap();
1032                assert_eq!(c2.imag_part(), 0.12);
1033
1034                let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1035                    rug::Complex::with_val(PRECISION, (10.0, 0.0)),
1036                )
1037                .unwrap();
1038                assert_eq!(c3.imag_part(), 0.0);
1039
1040                let c_nan_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1041                    rug::Complex::with_val(PRECISION, (5.0, f64::NAN)),
1042                )
1043                .unwrap_err();
1044                assert!(matches!(
1045                    c_nan_im,
1046                    ErrorsValidationRawComplex::InvalidImaginaryPart {
1047                        source: ErrorsValidationRawReal::IsNaN { .. }
1048                    }
1049                ));
1050
1051                let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1052                    rug::Complex::with_val(PRECISION, (5.0, f64::INFINITY)),
1053                )
1054                .unwrap_err();
1055                assert!(matches!(
1056                    c_inf_im,
1057                    ErrorsValidationRawComplex::InvalidImaginaryPart {
1058                        source: ErrorsValidationRawReal::IsPosInfinity { .. }
1059                    }
1060                ));
1061
1062                let c_neg_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1063                    rug::Complex::with_val(PRECISION, (5.0, f64::NEG_INFINITY)),
1064                )
1065                .unwrap_err();
1066                assert!(matches!(
1067                    c_neg_inf_im,
1068                    ErrorsValidationRawComplex::InvalidImaginaryPart {
1069                        source: ErrorsValidationRawReal::IsNegInfinity { .. }
1070                    }
1071                ));
1072            }
1073
1074            #[test]
1075            fn try_new_complex() {
1076                let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
1077                let i1 = RealRugStrictFinite::<PRECISION>::try_from_f64(4.56).unwrap();
1078                let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
1079                    r1.as_ref().clone(),
1080                    i1.as_ref().clone(),
1081                )
1082                .unwrap();
1083                assert_eq!(c1.real_part(), r1);
1084                assert_eq!(c1.imag_part(), i1);
1085
1086                let r2 = RealRugStrictFinite::<PRECISION>::try_from_f64(-7.89).unwrap();
1087                let i2 = RealRugStrictFinite::<PRECISION>::try_from_f64(-0.12).unwrap();
1088                let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
1089                    r2.as_ref().clone(),
1090                    i2.as_ref().clone(),
1091                )
1092                .unwrap();
1093                assert_eq!(c2.real_part(), r2);
1094                assert_eq!(c2.imag_part(), i2);
1095
1096                let r3 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
1097                let i3 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
1098                let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
1099                    r3.as_ref().clone(),
1100                    i3.as_ref().clone(),
1101                )
1102                .unwrap();
1103                assert_eq!(c3.real_part(), r3);
1104                assert_eq!(c3.real_part(), i3);
1105                assert!(c3.is_zero());
1106
1107                let c_nan_re = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
1108                    Float::with_val(PRECISION, f64::NAN),
1109                    Float::with_val(PRECISION, 5.0),
1110                )
1111                .unwrap_err();
1112                assert!(matches!(
1113                    c_nan_re,
1114                    ErrorsValidationRawComplex::InvalidRealPart { .. }
1115                ));
1116
1117                let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
1118                    Float::with_val(PRECISION, 10.0),
1119                    Float::with_val(PRECISION, f64::INFINITY),
1120                )
1121                .unwrap_err();
1122                assert!(matches!(
1123                    c_inf_im,
1124                    ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
1125                ));
1126
1127                let c_nan_re_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
1128                    Float::with_val(PRECISION, f64::NAN),
1129                    Float::with_val(PRECISION, f64::INFINITY),
1130                )
1131                .unwrap_err();
1132                assert!(matches!(
1133                    c_nan_re_inf_im,
1134                    ErrorsValidationRawComplex::InvalidBothParts { .. }
1135                ));
1136            }
1137
1138            #[test]
1139            fn try_from_complexf64() {
1140                let c1_in = num::Complex::new(1.23, 4.56);
1141                let c1 = ComplexRugStrictFinite::<PRECISION>::try_from(c1_in).unwrap();
1142                assert_eq!(c1.real_part(), c1_in.re);
1143                assert_eq!(c1.imag_part(), c1_in.im);
1144
1145                let c2_in = num::Complex::new(-7.89, -0.12);
1146                let c2 = ComplexRugStrictFinite::<PRECISION>::try_from(c2_in).unwrap();
1147                assert_eq!(c2.real_part(), c2_in.re);
1148                assert_eq!(c2.imag_part(), c2_in.im);
1149
1150                let c3_in = num::Complex::new(0., 0.);
1151                let c3 = ComplexRugStrictFinite::<PRECISION>::try_from(c3_in).unwrap();
1152                assert_eq!(c3.real_part(), c3_in.re);
1153                assert_eq!(c3.imag_part(), c3_in.im);
1154
1155                let c_nan_re =
1156                    ComplexRugStrictFinite::<PRECISION>::try_from(num::Complex::new(f64::NAN, 5.0))
1157                        .unwrap_err();
1158                assert!(matches!(
1159                    c_nan_re,
1160                    ErrorsValidationRawComplex::InvalidRealPart { .. }
1161                ));
1162
1163                let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_from(num::Complex::new(
1164                    10.0,
1165                    f64::INFINITY,
1166                ))
1167                .unwrap_err();
1168                assert!(matches!(
1169                    c_inf_im,
1170                    ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
1171                ));
1172
1173                let c_nan_re_inf_im = ComplexRugStrictFinite::<PRECISION>::try_from(
1174                    num::Complex::new(f64::NAN, f64::INFINITY),
1175                )
1176                .unwrap_err();
1177                assert!(matches!(
1178                    c_nan_re_inf_im,
1179                    ErrorsValidationRawComplex::InvalidBothParts { .. }
1180                ));
1181            }
1182
1183            #[test]
1184            fn try_new_pure_real() {
1185                let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
1186                let c1 =
1187                    ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(r1.as_ref().clone())
1188                        .unwrap();
1189                assert_eq!(c1.real_part(), r1);
1190                assert!(c1.imag_part().is_zero());
1191
1192                let c_nan = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
1193                    Float::with_val(PRECISION, f64::NAN),
1194                )
1195                .unwrap_err();
1196                assert!(matches!(
1197                    c_nan,
1198                    ErrorsValidationRawComplex::InvalidRealPart {
1199                        source: ErrorsValidationRawReal::IsNaN { .. }
1200                    }
1201                ));
1202            }
1203
1204            #[test]
1205            fn try_new_pure_imaginary() {
1206                let i1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
1207                let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
1208                    i1.as_ref().clone(),
1209                )
1210                .unwrap();
1211                assert!(c1.real_part().is_zero());
1212                assert_eq!(c1.imag_part(), i1);
1213
1214                let c_nan = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
1215                    Float::with_val(PRECISION, f64::NAN),
1216                )
1217                .unwrap_err();
1218                assert!(matches!(
1219                    c_nan,
1220                    ErrorsValidationRawComplex::InvalidImaginaryPart {
1221                        source: ErrorsValidationRawReal::IsNaN { .. }
1222                    }
1223                ));
1224            }
1225
1226            #[test]
1227            fn add_to_real_part() {
1228                let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1229                    rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1230                )
1231                .unwrap();
1232                c.add_to_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1233                assert_eq!(c.real_part(), 4.0);
1234                assert_eq!(c.imag_part(), 2.0);
1235
1236                c.add_to_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0).unwrap());
1237                assert_eq!(c.real_part(), -1.0);
1238                assert_eq!(c.imag_part(), 2.0);
1239            }
1240
1241            #[test]
1242            fn add_to_imaginary_part() {
1243                let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1244                    rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1245                )
1246                .unwrap();
1247                c.add_to_imaginary_part(
1248                    &RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(),
1249                );
1250                assert_eq!(c.real_part(), 1.0);
1251                assert_eq!(c.imag_part(), 5.0);
1252
1253                c.add_to_imaginary_part(
1254                    &RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap(),
1255                );
1256                assert_eq!(c.real_part(), 1.0);
1257                assert_eq!(c.imag_part(), 1.0);
1258            }
1259
1260            #[test]
1261            fn multiply_real_part() {
1262                let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1263                    rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1264                )
1265                .unwrap();
1266                c.multiply_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1267                assert_eq!(c.real_part(), 3.0);
1268                assert_eq!(c.imag_part(), 2.0);
1269
1270                c.multiply_real_part(
1271                    &RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap(),
1272                );
1273                assert_eq!(c.real_part(), -6.0);
1274                assert_eq!(c.imag_part(), 2.0);
1275            }
1276
1277            #[test]
1278            fn multiply_imaginary_part() {
1279                let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1280                    rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1281                )
1282                .unwrap();
1283                c.multiply_imaginary_part(
1284                    &RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(),
1285                );
1286                assert_eq!(c.real_part(), 1.0);
1287                assert_eq!(c.imag_part(), 6.0);
1288
1289                c.multiply_imaginary_part(
1290                    &RealRugStrictFinite::<PRECISION>::try_from_f64(-0.5).unwrap(),
1291                );
1292                assert_eq!(c.real_part(), 1.0);
1293                assert_eq!(c.imag_part(), -3.0);
1294            }
1295
1296            #[test]
1297            fn set_real_part() {
1298                let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1299                    rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1300                )
1301                .unwrap();
1302                c.set_real_part(RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1303                assert_eq!(c.real_part(), 3.0);
1304                assert_eq!(c.imag_part(), 2.0);
1305
1306                c.set_real_part(RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap());
1307                assert_eq!(c.real_part(), -4.0);
1308                assert_eq!(c.imag_part(), 2.0);
1309            }
1310
1311            #[test]
1312            fn set_imaginary_part() {
1313                let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1314                    rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1315                )
1316                .unwrap();
1317                c.set_imaginary_part(RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1318                assert_eq!(c.real_part(), 1.0);
1319                assert_eq!(c.imag_part(), 3.0);
1320
1321                c.set_imaginary_part(RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap());
1322                assert_eq!(c.real_part(), 1.0);
1323                assert_eq!(c.imag_part(), -4.0);
1324            }
1325        }
1326    }
1327
1328    mod mul {
1329        use super::*;
1330
1331        mod real {
1332            use super::*;
1333
1334            #[test]
1335            fn multiply_ref() {
1336                let r1 = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1337                    PRECISION, 3.0,
1338                ))
1339                .unwrap();
1340                let r2 = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1341                    PRECISION, 4.0,
1342                ))
1343                .unwrap();
1344                let result = r1 * &r2;
1345                assert_eq!(
1346                    result,
1347                    RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1348                        PRECISION, 12.0
1349                    ))
1350                    .unwrap()
1351                );
1352            }
1353        }
1354
1355        mod complex {
1356            use super::*;
1357
1358            #[test]
1359            fn multiply_ref() {
1360                let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1361                    rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1362                )
1363                .unwrap();
1364                let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1365                    rug::Complex::with_val(PRECISION, (3.0, 4.0)),
1366                )
1367                .unwrap();
1368                let result = c1 * &c2;
1369                assert_eq!(
1370                    result,
1371                    ComplexRugStrictFinite::<PRECISION>::try_new_validated(rug::Complex::with_val(
1372                        PRECISION,
1373                        (-5.0, 10.0),
1374                    ))
1375                    .unwrap()
1376                ); // (1*3 - 2*4) + (1*4 + 2*3)i
1377            }
1378
1379            #[test]
1380            fn complex_times_real() {
1381                let r = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1382                    PRECISION, 2.0,
1383                ))
1384                .unwrap();
1385                let c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1386                    rug::Complex::with_val(PRECISION, (3.0, 4.0)),
1387                )
1388                .unwrap();
1389
1390                let result_expected = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1391                    rug::Complex::with_val(PRECISION, (6.0, 8.0)),
1392                )
1393                .unwrap(); // 2 * (3 + 4i) = 6 + 8i
1394
1395                let result = c.clone() * &r;
1396                assert_eq!(&result, &result_expected);
1397
1398                let result = c.clone() * r.clone();
1399                assert_eq!(&result, &result_expected);
1400
1401                let mut result = c.clone();
1402                result *= &r;
1403                assert_eq!(&result, &result_expected);
1404
1405                let mut result = c.clone();
1406                result *= r;
1407                assert_eq!(&result, &result_expected);
1408            }
1409
1410            #[test]
1411            fn real_times_complex() {
1412                let r = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1413                    PRECISION, 2.0,
1414                ))
1415                .unwrap();
1416                let c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1417                    rug::Complex::with_val(PRECISION, (3.0, 4.0)),
1418                )
1419                .unwrap();
1420
1421                let result_expected = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1422                    rug::Complex::with_val(PRECISION, (6.0, 8.0)),
1423                )
1424                .unwrap(); // 2 * (3 + 4i) = 6 + 8i
1425
1426                let result = &r * c.clone();
1427                assert_eq!(&result, &result_expected);
1428
1429                let result = r * c.clone();
1430                assert_eq!(&result, &result_expected);
1431            }
1432        }
1433    }
1434
1435    mod arithmetic {
1436        use super::*;
1437
1438        mod real {
1439            use super::*;
1440
1441            #[test]
1442            fn neg_assign() {
1443                let mut a = rug::Float::with_val(PRECISION, 1.);
1444                a.neg_assign();
1445                let a_expected = rug::Float::with_val(PRECISION, -1.);
1446                assert_eq!(a, a_expected);
1447
1448                let mut b = RealRugStrictFinite::<PRECISION>::one();
1449                b.neg_assign();
1450                let b_expected = RealRugStrictFinite::<PRECISION>::try_new_validated(
1451                    rug::Float::with_val(PRECISION, -1.),
1452                )
1453                .unwrap();
1454                assert_eq!(&b, &b_expected);
1455            }
1456
1457            #[test]
1458            #[should_panic(expected = "Division failed validation")]
1459            fn div_by_zero() {
1460                let one = RealRugStrictFinite::<PRECISION>::one();
1461                let zero = RealRugStrictFinite::<PRECISION>::zero();
1462                let _ = &one / &zero;
1463            }
1464
1465            #[test]
1466            #[should_panic(expected = "Division failed validation")]
1467            fn div_assign_by_zero() {
1468                let mut num = RealRugStrictFinite::<PRECISION>::one();
1469                let zero_ref = &RealRugStrictFinite::<PRECISION>::zero();
1470                num /= zero_ref;
1471            }
1472        }
1473
1474        mod complex {
1475            use super::*;
1476
1477            #[test]
1478            fn neg_assign() {
1479                let re = rug::Float::with_val(PRECISION, 1.);
1480                let im = rug::Float::with_val(PRECISION, 2.);
1481                let mut num = rug::Complex::with_val(PRECISION, (re, im));
1482                num.neg_assign();
1483                let expected = rug::Complex::with_val(
1484                    PRECISION,
1485                    (
1486                        rug::Float::with_val(PRECISION, -1.),
1487                        rug::Float::with_val(PRECISION, -2.),
1488                    ),
1489                );
1490                assert_eq!(&num, &expected);
1491
1492                let mut num = ComplexRugStrictFinite::<PRECISION>::try_new_validated(num).unwrap();
1493                let expected = num.clone().neg();
1494                num.neg_assign();
1495                assert_eq!(&num, &expected);
1496            }
1497
1498            #[test]
1499            #[should_panic(expected = "Division failed validation")]
1500            fn div_by_zero() {
1501                let one = ComplexRugStrictFinite::<PRECISION>::one();
1502                let zero = ComplexRugStrictFinite::<PRECISION>::zero();
1503                let _ = &one / &zero;
1504            }
1505
1506            #[test]
1507            #[should_panic(expected = "Division failed validation")]
1508            fn div_assign_by_zero() {
1509                let mut num = ComplexRugStrictFinite::<PRECISION>::one();
1510                let zero_ref = &ComplexRugStrictFinite::<PRECISION>::zero();
1511                num /= zero_ref;
1512            }
1513        }
1514    }
1515
1516    mod real_scalar_methods {
1517        use super::*;
1518
1519        #[test]
1520        fn epsilon() {
1521            let eps = RealRugStrictFinite::<PRECISION>::epsilon();
1522            assert!(eps.is_finite() && eps > RealRugStrictFinite::<PRECISION>::zero());
1523            let expected_eps_val =
1524                rug::Float::with_val(PRECISION, 2.0).pow(1i32 - PRECISION as i32);
1525            let expected_eps = RealRugStrictFinite::<PRECISION>::try_new(expected_eps_val).unwrap();
1526            assert_eq!(eps, expected_eps, "Epsilon value mismatch");
1527        }
1528
1529        #[test]
1530        fn clamp() {
1531            let val = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap();
1532            let min_val = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
1533            let max_val = RealRugStrictFinite::<PRECISION>::try_from_f64(10.0).unwrap();
1534
1535            assert_eq!(val.clone().kernel_clamp(&min_val, &max_val), val);
1536            assert_eq!(
1537                RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0)
1538                    .unwrap()
1539                    .kernel_clamp(&min_val, &max_val),
1540                min_val
1541            );
1542            assert_eq!(
1543                RealRugStrictFinite::<PRECISION>::try_from_f64(15.0)
1544                    .unwrap()
1545                    .kernel_clamp(&min_val, &max_val),
1546                max_val
1547            );
1548        }
1549
1550        #[test]
1551        fn hypot() {
1552            let a = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap();
1553            let b = RealRugStrictFinite::<PRECISION>::try_from_f64(4.0).unwrap();
1554            let expected = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap();
1555            assert_eq!(a.kernel_hypot(&b), expected);
1556        }
1557
1558        #[test]
1559        fn signum() {
1560            assert_eq!(
1561                RealRugStrictFinite::<PRECISION>::try_from_f64(5.0)
1562                    .unwrap()
1563                    .kernel_signum(),
1564                RealRugStrictFinite::<PRECISION>::one()
1565            );
1566            assert_eq!(
1567                RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0)
1568                    .unwrap()
1569                    .kernel_signum(),
1570                RealRugStrictFinite::<PRECISION>::negative_one()
1571            );
1572            // rug::Float::signum of 0.0 is 1.0
1573            assert_eq!(
1574                RealRugStrictFinite::<PRECISION>::zero().kernel_signum(),
1575                RealRugStrictFinite::<PRECISION>::one()
1576            );
1577        }
1578
1579        #[test]
1580        fn total_cmp() {
1581            let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0).unwrap();
1582            let r2 = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1583            assert_eq!(r1.total_cmp(&r1), Ordering::Equal);
1584            assert_eq!(r1.total_cmp(&r2), Ordering::Less);
1585            assert_eq!(r2.total_cmp(&r1), Ordering::Greater);
1586        }
1587
1588        #[test]
1589        fn mul_add_mul_mut() {
1590            let mut a = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1591            let b = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(); // mul
1592            let c = RealRugStrictFinite::<PRECISION>::try_from_f64(4.0).unwrap(); // add_mul1
1593            let d = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap(); // add_mul2
1594            // Expected: a = a*b + c*d = 2*3 + 4*5 = 6 + 20 = 26
1595            a.kernel_mul_add_mul_mut(&b, &c, &d);
1596            assert_eq!(
1597                a,
1598                RealRugStrictFinite::<PRECISION>::try_from_f64(26.0).unwrap()
1599            );
1600        }
1601
1602        #[test]
1603        fn mul_sub_mul_mut() {
1604            let mut a = RealRugStrictFinite::<PRECISION>::try_from_f64(10.0).unwrap();
1605            let b = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap(); // mul
1606            let c = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(); // sub_mul1
1607            let d = RealRugStrictFinite::<PRECISION>::try_from_f64(4.0).unwrap(); // sub_mul2
1608            // Expected: a = a*b - c*d = 10*2 - 3*4 = 20 - 12 = 8
1609            a.kernel_mul_sub_mul_mut(&b, &c, &d);
1610            assert_eq!(
1611                a,
1612                RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1613            );
1614        }
1615
1616        #[test]
1617        fn test_real_rug_constants() {
1618            // Helper to create a raw rug::Float for comparison
1619            let raw_float = |f: f64| Float::with_val(PRECISION, f);
1620
1621            // PI
1622            let pi = RealRugStrictFinite::<PRECISION>::pi();
1623            let expected_pi = raw_float(-1.0).acos();
1624            assert_eq!(pi.as_ref(), &expected_pi);
1625
1626            // TWO_PI
1627            let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
1628            let expected_two_pi = &expected_pi * raw_float(2.0);
1629            assert_eq!(two_pi.as_ref(), &expected_two_pi);
1630
1631            // PI_DIV_2
1632            let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1633            let expected_pi_div_2 = raw_float(1.0).asin();
1634            assert_eq!(pi_div_2.as_ref(), &expected_pi_div_2);
1635
1636            // E
1637            let e = RealRugStrictFinite::<PRECISION>::e();
1638            let expected_e = raw_float(1.0).exp();
1639            assert_eq!(e.as_ref(), &expected_e);
1640
1641            // LOG2_E
1642            let log2_e = RealRugStrictFinite::<PRECISION>::log2_e();
1643            let expected_log2_e = expected_e.clone().log2();
1644            assert_eq!(log2_e.as_ref(), &expected_log2_e);
1645
1646            // LOG10_E
1647            let log10_e = RealRugStrictFinite::<PRECISION>::log10_e();
1648            let expected_log10_e = expected_e.log10();
1649            assert_eq!(log10_e.as_ref(), &expected_log10_e);
1650
1651            // LN_2
1652            let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1653            let expected_ln_2 = raw_float(2.0).ln();
1654            assert_eq!(ln_2.as_ref(), &expected_ln_2);
1655
1656            // LN_10
1657            let ln_10 = RealRugStrictFinite::<PRECISION>::ln_10();
1658            let expected_ln_10 = raw_float(10.0).ln();
1659            assert_eq!(ln_10.as_ref(), &expected_ln_10);
1660
1661            // LOG2_10
1662            let log2_10 = RealRugStrictFinite::<PRECISION>::log2_10();
1663            let expected_log2_10 = raw_float(10.0).log2();
1664            assert_eq!(log2_10.as_ref(), &expected_log2_10);
1665
1666            // LOG10_2
1667            let log10_2 = RealRugStrictFinite::<PRECISION>::log10_2();
1668            let expected_log10_2 = raw_float(2.0).log10();
1669            assert_eq!(log10_2.as_ref(), &expected_log10_2);
1670
1671            // MAX_FINITE
1672            let max_finite = RealRugStrictFinite::<PRECISION>::max_finite();
1673            let expected_max_finite = <rug::Float as RawRealTrait>::raw_max_finite(PRECISION);
1674            assert_eq!(max_finite.as_ref(), &expected_max_finite);
1675
1676            // MIN_FINITE
1677            let min_finite = RealRugStrictFinite::<PRECISION>::min_finite();
1678            let expected_min_finite = <rug::Float as RawRealTrait>::raw_min_finite(PRECISION);
1679            assert_eq!(min_finite.as_ref(), &expected_min_finite);
1680
1681            // EPSILON
1682            let epsilon = RealRugStrictFinite::<PRECISION>::epsilon();
1683            let expected_epsilon = <rug::Float as RawRealTrait>::raw_epsilon(PRECISION);
1684            assert_eq!(epsilon.as_ref(), &expected_epsilon);
1685
1686            // NEGATIVE_ONE
1687            assert_eq!(
1688                RealRugStrictFinite::<PRECISION>::negative_one().as_ref(),
1689                &raw_float(-1.0)
1690            );
1691
1692            // TWO
1693            assert_eq!(
1694                RealRugStrictFinite::<PRECISION>::two().as_ref(),
1695                &raw_float(2.0)
1696            );
1697
1698            // ONE_DIV_2
1699            assert_eq!(
1700                RealRugStrictFinite::<PRECISION>::one_div_2().as_ref(),
1701                &raw_float(0.5)
1702            );
1703        }
1704    }
1705
1706    mod function_traits {
1707        use super::*;
1708        use crate::{
1709            functions::{
1710                ATan2InputErrors, LogarithmRealErrors, LogarithmRealInputErrors,
1711                PowComplexBaseRealExponentInputErrors, PowRealBaseRealExponentInputErrors,
1712                ReciprocalInputErrors, SqrtRealInputErrors,
1713            },
1714            validation::ErrorsValidationRawReal,
1715        };
1716
1717        mod real {
1718            use super::*;
1719
1720            #[test]
1721            fn exp_overflow() {
1722                let large_val = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0e60).unwrap(); // exp(1.0e60) is very large
1723                let res_large = large_val.try_exp();
1724                assert!(matches!(
1725                    res_large,
1726                    Err(ExpErrors::Output {
1727                        source: ErrorsValidationRawReal::IsPosInfinity { .. }
1728                    })
1729                ),);
1730            }
1731
1732            #[test]
1733            fn ln_domain_errors() {
1734                let neg_val = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.0).unwrap();
1735                assert!(matches!(
1736                    neg_val.try_ln(),
1737                    Err(LogarithmRealErrors::Input {
1738                        source: LogarithmRealInputErrors::NegativeArgument { .. }
1739                    })
1740                ));
1741
1742                let zero_val = RealRugStrictFinite::<PRECISION>::zero();
1743                assert!(matches!(
1744                    zero_val.try_ln(),
1745                    Err(LogarithmRealErrors::Input {
1746                        source: LogarithmRealInputErrors::ZeroArgument { .. }
1747                    })
1748                ));
1749            }
1750        } // end mod real
1751
1752        mod complex {
1753            use super::*;
1754
1755            #[test]
1756            fn log2_zero() {
1757                let zero_val = ComplexRugStrictFinite::<PRECISION>::zero();
1758                assert!(matches!(
1759                    zero_val.try_log2(),
1760                    Err(LogarithmComplexErrors::Input {
1761                        source: LogarithmComplexInputErrors::ZeroArgument { .. }
1762                    })
1763                ));
1764            }
1765        } // end mod complex
1766
1767        mod pow {
1768            use super::*;
1769
1770            mod real_base {
1771                use super::*;
1772
1773                #[test]
1774                fn negative_base_real_exponent_error() {
1775                    let base = RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap();
1776                    let exponent = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
1777                    let res = base.try_pow(&exponent);
1778                    assert!(matches!(
1779                        res,
1780                        Err(PowRealBaseRealExponentErrors::Input {
1781                            source: PowRealBaseRealExponentInputErrors::NegativeBase { .. }
1782                        })
1783                    ));
1784                }
1785
1786                #[test]
1787                fn real_base_uint_exponent() {
1788                    let base = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1789                    assert_eq!(
1790                        base.clone().try_pow(3u8).unwrap(),
1791                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1792                    );
1793                    assert_eq!(
1794                        base.clone().try_pow(3u16).unwrap(),
1795                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1796                    );
1797                    assert_eq!(
1798                        base.clone().try_pow(3u32).unwrap(),
1799                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1800                    );
1801                    assert_eq!(
1802                        base.clone().try_pow(3u64).unwrap(),
1803                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1804                    );
1805                    assert_eq!(
1806                        base.clone().try_pow(3u128).unwrap(),
1807                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1808                    );
1809                    assert_eq!(
1810                        base.clone().try_pow(3usize).unwrap(),
1811                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1812                    );
1813
1814                    assert_eq!(
1815                        base.clone().pow(3u8),
1816                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1817                    );
1818                    assert_eq!(
1819                        base.clone().pow(3u16),
1820                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1821                    );
1822                    assert_eq!(
1823                        base.clone().pow(3u32),
1824                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1825                    );
1826                    assert_eq!(
1827                        base.clone().pow(3u64),
1828                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1829                    );
1830                    assert_eq!(
1831                        base.clone().pow(3u128),
1832                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1833                    );
1834                    assert_eq!(
1835                        base.clone().pow(3usize),
1836                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1837                    );
1838                }
1839
1840                #[test]
1841                fn real_base_int_exponent() {
1842                    let base = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1843                    assert_eq!(
1844                        base.clone().try_pow(3i8).unwrap(),
1845                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1846                    );
1847                    assert_eq!(
1848                        base.clone().try_pow(3i16).unwrap(),
1849                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1850                    );
1851                    assert_eq!(
1852                        base.clone().try_pow(3i32).unwrap(),
1853                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1854                    );
1855                    assert_eq!(
1856                        base.clone().try_pow(3i64).unwrap(),
1857                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1858                    );
1859                    assert_eq!(
1860                        base.clone().try_pow(3i128).unwrap(),
1861                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1862                    );
1863                    assert_eq!(
1864                        base.clone().try_pow(3isize).unwrap(),
1865                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1866                    );
1867
1868                    assert_eq!(
1869                        base.clone().pow(3i8),
1870                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1871                    );
1872                    assert_eq!(
1873                        base.clone().pow(3i16),
1874                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1875                    );
1876                    assert_eq!(
1877                        base.clone().pow(3i32),
1878                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1879                    );
1880                    assert_eq!(
1881                        base.clone().pow(3i64),
1882                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1883                    );
1884                    assert_eq!(
1885                        base.clone().pow(3i128),
1886                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1887                    );
1888                    assert_eq!(
1889                        base.clone().pow(3isize),
1890                        RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1891                    );
1892                }
1893
1894                #[test]
1895                fn real_base_int_exponent_zero_neg_exp_error() {
1896                    let base = RealRugStrictFinite::<PRECISION>::zero();
1897                    let exponent: i32 = -2;
1898                    let res = base.try_pow(exponent);
1899                    assert!(matches!(
1900                        res,
1901                        Err(PowIntExponentErrors::Input {
1902                            source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
1903                        })
1904                    ));
1905                }
1906            }
1907
1908            mod complex_base {
1909                use super::*;
1910
1911                #[test]
1912                fn complex_base_uint_exponent() {
1913                    let base = ComplexRugStrictFinite::<PRECISION>::try_new(
1914                        rug::Complex::with_val(PRECISION, (2.0, 3.0)),
1915                    )
1916                    .unwrap();
1917                    let expected_res = ComplexRugStrictFinite::<PRECISION>::try_new(
1918                        rug::Complex::with_val(PRECISION, (-46.0, 9.0)),
1919                    )
1920                    .unwrap();
1921
1922                    assert_eq!(&base.clone().try_pow(3u8).unwrap(), &expected_res);
1923                    assert_eq!(&base.clone().try_pow(3u16).unwrap(), &expected_res);
1924                    assert_eq!(&base.clone().try_pow(3u32).unwrap(), &expected_res);
1925                    assert_eq!(&base.clone().try_pow(3u64).unwrap(), &expected_res);
1926                    assert_eq!(&base.clone().try_pow(3u128).unwrap(), &expected_res);
1927                    assert_eq!(&base.clone().try_pow(3usize).unwrap(), &expected_res);
1928
1929                    assert_eq!(&base.clone().pow(3u8), &expected_res);
1930                    assert_eq!(&base.clone().pow(3u16), &expected_res);
1931                    assert_eq!(&base.clone().pow(3u32), &expected_res);
1932                    assert_eq!(&base.clone().pow(3u64), &expected_res);
1933                    assert_eq!(&base.clone().pow(3u128), &expected_res);
1934                    assert_eq!(&base.clone().pow(3usize), &expected_res);
1935                }
1936
1937                #[test]
1938                fn complex_base_int_exponent() {
1939                    let base = ComplexRugStrictFinite::<PRECISION>::try_new(
1940                        rug::Complex::with_val(PRECISION, (2.0, 3.0)),
1941                    )
1942                    .unwrap();
1943                    let expected_res = ComplexRugStrictFinite::<PRECISION>::try_new(
1944                        rug::Complex::with_val(PRECISION, (-46.0, 9.0)),
1945                    )
1946                    .unwrap();
1947
1948                    assert_eq!(&base.clone().try_pow(3i8).unwrap(), &expected_res);
1949                    assert_eq!(&base.clone().try_pow(3i16).unwrap(), &expected_res);
1950                    assert_eq!(&base.clone().try_pow(3i32).unwrap(), &expected_res);
1951                    assert_eq!(&base.clone().try_pow(3i64).unwrap(), &expected_res);
1952                    assert_eq!(&base.clone().try_pow(3i128).unwrap(), &expected_res);
1953                    assert_eq!(&base.clone().try_pow(3isize).unwrap(), &expected_res);
1954
1955                    assert_eq!(&base.clone().pow(3i8), &expected_res);
1956                    assert_eq!(&base.clone().pow(3i16), &expected_res);
1957                    assert_eq!(&base.clone().pow(3i32), &expected_res);
1958                    assert_eq!(&base.clone().pow(3i64), &expected_res);
1959                    assert_eq!(&base.clone().pow(3i128), &expected_res);
1960                    assert_eq!(&base.clone().pow(3isize), &expected_res);
1961                }
1962
1963                #[test]
1964                fn complex_zero_base_negative_real_exponent_error() {
1965                    let base = ComplexRugStrictFinite::<PRECISION>::zero();
1966                    let exponent = RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap();
1967                    let res = base.try_pow(&exponent);
1968                    assert!(matches!(
1969                        res,
1970                        Err(PowComplexBaseRealExponentErrors::Input {
1971                            source:
1972                                PowComplexBaseRealExponentInputErrors::ZeroBaseNegativeExponent { .. }
1973                        })
1974                    ));
1975                }
1976
1977                #[test]
1978                fn complex_zero_base_zero_real_exponent() {
1979                    let base = ComplexRugStrictFinite::<PRECISION>::zero();
1980                    let exponent = RealRugStrictFinite::<PRECISION>::zero();
1981                    let res = base.try_pow(&exponent).unwrap();
1982                    assert_eq!(res, ComplexRugStrictFinite::<PRECISION>::one());
1983                }
1984
1985                #[test]
1986                fn complex_base_int_exponent_zero_neg_exp_error() {
1987                    let base = ComplexRugStrictFinite::<PRECISION>::zero();
1988                    let exponent: i32 = -2;
1989                    let res = base.try_pow(exponent);
1990                    assert!(matches!(
1991                        res,
1992                        Err(PowIntExponentErrors::Input {
1993                            source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
1994                        })
1995                    ));
1996                }
1997            }
1998        }
1999
2000        #[test]
2001        fn reciprocal_real_rug_zero() {
2002            let zero_val = RealRugStrictFinite::<PRECISION>::zero();
2003            let res = zero_val.try_reciprocal();
2004            assert!(matches!(
2005                res,
2006                Err(ReciprocalErrors::Input {
2007                    source: ReciprocalInputErrors::DivisionByZero { .. }
2008                })
2009            ));
2010        }
2011
2012        #[test]
2013        fn reciprocal_complex_rug_zero() {
2014            let zero_val = ComplexRugStrictFinite::<PRECISION>::zero();
2015            let res = zero_val.try_reciprocal();
2016            assert!(matches!(
2017                res,
2018                Err(ReciprocalErrors::Input {
2019                    source: ReciprocalInputErrors::DivisionByZero { .. }
2020                })
2021            ));
2022        }
2023
2024        #[test]
2025        fn sqrt_real_rug_negative_input() {
2026            let neg_val = RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap();
2027            let res = neg_val.try_sqrt();
2028            assert!(matches!(
2029                res,
2030                Err(SqrtRealErrors::Input {
2031                    source: SqrtRealInputErrors::NegativeValue { .. }
2032                })
2033            ));
2034        }
2035
2036        mod trigonometric {
2037            use super::*;
2038
2039            #[test]
2040            fn atan2_real_rug_zero_over_zero() {
2041                let zero_val = RealRugStrictFinite::<PRECISION>::zero();
2042                let res = zero_val.try_atan2(&RealRugStrictFinite::<PRECISION>::zero());
2043                assert!(matches!(
2044                    res,
2045                    Err(ATan2Errors::Input {
2046                        source: ATan2InputErrors::ZeroOverZero { .. }
2047                    })
2048                ));
2049            }
2050
2051            /*
2052            #[test]
2053            #[ignore = "at the moment we cannot create a pole for the Tan function"]
2054            fn tan_real_rug_pole() {
2055                // tan(PI/2) is a pole
2056                let pi_half = RealRugStrictFinite::<PRECISION>::pi_div_2();
2057                let res = pi_half.try_tan();
2058                println!("Result: {:?}", res);
2059                assert!(matches!(
2060                    res,
2061                    Err(TanRealErrors::Input {
2062                        source: TanRealInputErrors::ArgumentIsPole { .. }
2063                    })
2064                ));
2065            }
2066            */
2067
2068            #[test]
2069            fn asin_real_rug_out_of_domain() {
2070                let val_gt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.5).unwrap();
2071                assert!(matches!(
2072                    val_gt_1.try_asin(),
2073                    Err(ASinRealErrors::Input {
2074                        source: ASinRealInputErrors::OutOfDomain { .. }
2075                    })
2076                ));
2077                let val_lt_neg1 = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.5).unwrap();
2078                assert!(matches!(
2079                    val_lt_neg1.try_asin(),
2080                    Err(ASinRealErrors::Input {
2081                        source: ASinRealInputErrors::OutOfDomain { .. }
2082                    })
2083                ));
2084            }
2085
2086            #[test]
2087            fn acos_real_rug_out_of_domain() {
2088                let val_gt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.5).unwrap();
2089                assert!(matches!(
2090                    val_gt_1.try_acos(),
2091                    Err(ACosRealErrors::Input {
2092                        source: ACosRealInputErrors::OutOfDomain { .. }
2093                    })
2094                ));
2095                let val_lt_neg1 = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.5).unwrap();
2096                assert!(matches!(
2097                    val_lt_neg1.try_acos(),
2098                    Err(ACosRealErrors::Input {
2099                        source: ACosRealInputErrors::OutOfDomain { .. }
2100                    })
2101                ));
2102            }
2103
2104            #[test]
2105            fn atan_complex_rug_pole() {
2106                // atan(i) and atan(-i) are poles
2107                let i_val = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
2108                    Float::with_val(PRECISION, 1.0),
2109                )
2110                .unwrap();
2111                assert!(matches!(
2112                    i_val.try_atan(),
2113                    Err(ATanComplexErrors::Input {
2114                        source: ATanComplexInputErrors::ArgumentIsPole { .. }
2115                    })
2116                ));
2117
2118                let neg_i_val = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
2119                    Float::with_val(PRECISION, -1.0),
2120                )
2121                .unwrap();
2122                assert!(matches!(
2123                    neg_i_val.try_atan(),
2124                    Err(ATanComplexErrors::Input {
2125                        source: ATanComplexInputErrors::ArgumentIsPole { .. }
2126                    })
2127                ));
2128            }
2129        } // endmod trigonometric
2130
2131        mod hyperbolic {
2132            use super::*;
2133
2134            mod real {
2135                use super::*;
2136
2137                #[test]
2138                fn atanh_real_rug_out_of_domain() {
2139                    let val_ge_1 = RealRugStrictFinite::<PRECISION>::one(); // atanh(1) is Inf
2140                    assert!(matches!(
2141                        val_ge_1.try_atanh(),
2142                        Err(ATanHErrors::Input {
2143                            source: ATanHInputErrors::OutOfDomain { .. }
2144                        })
2145                    ));
2146
2147                    let val_le_neg1 = RealRugStrictFinite::<PRECISION>::negative_one(); // atanh(-1) is -Inf
2148                    assert!(matches!(
2149                        val_le_neg1.try_atanh(),
2150                        Err(ATanHErrors::Input {
2151                            source: ATanHInputErrors::OutOfDomain { .. }
2152                        })
2153                    ));
2154                }
2155
2156                #[test]
2157                fn acosh_real_rug_out_of_domain() {
2158                    let val_lt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
2159                    assert!(matches!(
2160                        val_lt_1.try_acosh(),
2161                        Err(ACosHErrors::Input {
2162                            source: ACosHInputErrors::OutOfDomain { .. }
2163                        })
2164                    ));
2165                }
2166            }
2167
2168            mod complex {
2169                use super::*;
2170
2171                /*
2172                #[test]
2173                #[ignore = "at the moment we cannot create a pole for the ATanH function"]
2174                fn tanh_complex_rug_pole() {
2175                    // tanh(z) has poles where cosh(z) = 0. e.g. z = i * (PI/2 + k*PI)
2176                    let pi_half = RealRugStrictFinite::<PRECISION>::pi_div_2().into_inner();
2177                    let pole_val =
2178                        ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(pi_half).unwrap();
2179                    println!("Atanh(Pole value): {:?}", pole_val.clone().try_tanh());
2180                    assert!(matches!(
2181                        pole_val.try_tanh(),
2182                        Err(TanHComplexErrors::Input {
2183                            source: TanHComplexInputErrors::OutOfDomain { .. }
2184                        })
2185                    ));
2186                }
2187                */
2188
2189                #[test]
2190                fn acosh_out_of_domain() {
2191                    // acosh(z) domain is C \ (-inf, 1) on real axis
2192                    let val_on_branch_cut = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2193                        Float::with_val(PRECISION, 0.5),
2194                    )
2195                    .unwrap();
2196                    assert!(matches!(
2197                        val_on_branch_cut.try_acosh(),
2198                        Err(ACosHErrors::Input {
2199                            source: ACosHInputErrors::OutOfDomain { .. }
2200                        })
2201                    ));
2202
2203                    let val_on_branch_cut_neg =
2204                        ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(Float::with_val(
2205                            PRECISION, -5.0,
2206                        ))
2207                        .unwrap();
2208                    assert!(matches!(
2209                        val_on_branch_cut_neg.try_acosh(),
2210                        Err(ACosHErrors::Input {
2211                            source: ACosHInputErrors::OutOfDomain { .. }
2212                        })
2213                    ));
2214                }
2215
2216                #[test]
2217                fn atanh_out_of_domain() {
2218                    let val_ge_1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2219                        Float::with_val(PRECISION, 1.0),
2220                    )
2221                    .unwrap();
2222                    assert!(matches!(
2223                        val_ge_1.try_atanh(),
2224                        Err(ATanHErrors::Input {
2225                            source: ATanHInputErrors::OutOfDomain { .. }
2226                        })
2227                    ));
2228
2229                    let val_le_neg1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2230                        Float::with_val(PRECISION, -1.0),
2231                    )
2232                    .unwrap();
2233                    assert!(matches!(
2234                        val_le_neg1.try_atanh(),
2235                        Err(ATanHErrors::Input {
2236                            source: ATanHInputErrors::OutOfDomain { .. }
2237                        })
2238                    ));
2239                }
2240            }
2241
2242            /*
2243            #[test]
2244            #[ignore = "at the moment we cannot create a pole for the TanH function"]
2245            fn tanh_out_of_domain() {
2246                // tanh(z) has poles where cosh(z) = 0. e.g. z = i * (PI/2 + k*PI)
2247                let pi_half = RealRugStrictFinite::<PRECISION>::pi_div_2().into_inner();
2248                let pole_val = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(pi_half).unwrap();
2249                println!("TanH(Pole value): {:?}", pole_val.clone().try_tanh());
2250                assert!(matches!(
2251                    pole_val.try_tanh(),
2252                    Err(TanHComplexErrors::Input {
2253                        source: TanHComplexInputErrors::OutOfDomain { .. }
2254                    })
2255                ));
2256            }
2257            */
2258        } // end mod hyperbolic
2259    }
2260
2261    mod summation {
2262        use super::*;
2263
2264        const PRECISION: u32 = 53;
2265
2266        type RealValidated = RealRugStrictFinite<PRECISION>;
2267        type ComplexValidated = ComplexRugStrictFinite<PRECISION>;
2268
2269        #[test]
2270        fn sum_real() {
2271            let values = vec![
2272                RealValidated::try_from_f64(1.0).unwrap(),
2273                RealValidated::try_from_f64(2.0).unwrap(),
2274                RealValidated::try_from_f64(3.0).unwrap(),
2275                RealValidated::try_from_f64(4.0).unwrap(),
2276                RealValidated::try_from_f64(5.0).unwrap(),
2277            ];
2278            let sum: RealValidated = values.into_iter().sum();
2279            assert_eq!(sum, RealValidated::try_from_f64(15.0).unwrap());
2280        }
2281
2282        #[test]
2283        fn sum_real_compensated() {
2284            // Test case where simple summation might lose precision
2285            let values = vec![
2286                RealValidated::try_from_f64(1.0e100).unwrap(),
2287                RealValidated::try_from_f64(1.0).unwrap(),
2288                RealValidated::try_from_f64(-1.0e100).unwrap(),
2289            ];
2290            let sum: RealValidated = values.into_iter().sum();
2291            // The Neumaier sum should correctly result in 1.0
2292            assert_eq!(sum, RealValidated::try_from_f64(1.0).unwrap());
2293        }
2294
2295        #[test]
2296        fn sum_complex() {
2297            let values = vec![
2298                ComplexValidated::try_new_complex(
2299                    rug::Float::with_val(PRECISION, 1.),
2300                    rug::Float::with_val(PRECISION, 2.),
2301                )
2302                .unwrap(),
2303                ComplexValidated::try_new_complex(
2304                    rug::Float::with_val(PRECISION, 3.),
2305                    rug::Float::with_val(PRECISION, 4.),
2306                )
2307                .unwrap(),
2308                ComplexValidated::try_new_complex(
2309                    rug::Float::with_val(PRECISION, 5.),
2310                    rug::Float::with_val(PRECISION, 6.),
2311                )
2312                .unwrap(),
2313            ];
2314            let sum: ComplexValidated = values.into_iter().sum();
2315            assert_eq!(
2316                sum,
2317                ComplexValidated::try_new_complex(
2318                    rug::Float::with_val(PRECISION, 9.),
2319                    rug::Float::with_val(PRECISION, 12.)
2320                )
2321                .unwrap()
2322            );
2323        }
2324
2325        #[test]
2326        fn sum_complex_compensated() {
2327            let values = [
2328                ComplexValidated::try_new_complex(
2329                    rug::Float::with_val(PRECISION, 1.0e100),
2330                    rug::Float::with_val(PRECISION, -1.0e100),
2331                )
2332                .unwrap(),
2333                ComplexValidated::try_new_complex(
2334                    rug::Float::with_val(PRECISION, 1.),
2335                    rug::Float::with_val(PRECISION, 2.),
2336                )
2337                .unwrap(),
2338                ComplexValidated::try_new_complex(
2339                    rug::Float::with_val(PRECISION, -1.0e100),
2340                    rug::Float::with_val(PRECISION, 1.0e100),
2341                )
2342                .unwrap(),
2343            ];
2344            let sum: ComplexValidated = values.iter().cloned().sum();
2345            assert_eq!(
2346                sum,
2347                ComplexValidated::try_new_complex(
2348                    rug::Float::with_val(PRECISION, 1.),
2349                    rug::Float::with_val(PRECISION, 2.)
2350                )
2351                .unwrap()
2352            );
2353        }
2354    } // end mod summation
2355
2356    mod random {
2357        use super::*;
2358        use crate::{RandomSampleFromF64, new_random_vec};
2359        use rand::{Rng, SeedableRng, distr::Uniform, rngs::StdRng};
2360
2361        const PRECISION: u32 = 53;
2362
2363        type RealValidated = RealRugStrictFinite<PRECISION>;
2364        type ComplexValidated = ComplexRugStrictFinite<PRECISION>;
2365
2366        /// Tests the random generation of a `RealValidated` value.
2367        /// It uses a seeded RNG to ensure deterministic results and checks
2368        /// if the generated value falls within the expected [0, 1) range.
2369        #[test]
2370        fn test_random_real_validated() {
2371            let seed = [42; 32];
2372            let mut rng = StdRng::from_seed(seed);
2373
2374            let random_real: RealValidated = rng.random();
2375
2376            // rng.random::<f64>() produces a value in [0, 1), so the converted value should be in the same range.
2377            assert_eq!(random_real, 0.23713468825474326);
2378
2379            // Check for determinism
2380            let mut rng2 = StdRng::from_seed(seed);
2381            let random_real2: RealValidated = rng2.random();
2382            assert_eq!(random_real, random_real2);
2383        }
2384
2385        /// Tests the random generation of a `ComplexValidated` value.
2386        /// It uses a seeded RNG for determinism and verifies that both the real
2387        /// and imaginary parts of the generated complex number are within the
2388        /// expected [0, 1) range.
2389        #[test]
2390        fn test_random_complex_validated() {
2391            let seed = [99; 32];
2392            let mut rng = StdRng::from_seed(seed);
2393
2394            let random_complex: ComplexValidated = rng.random();
2395
2396            // The real and imaginary parts are generated independently,
2397            // so both should be in the [0, 1) range.
2398            let real_part = random_complex.real_part();
2399            let imag_part = random_complex.imag_part();
2400
2401            assert_eq!(real_part, 0.9995546882627792);
2402            assert_eq!(imag_part, 0.08932180682540247);
2403
2404            // Check for determinism
2405            let mut rng2 = StdRng::from_seed(seed);
2406            let random_complex2: ComplexValidated = rng2.random();
2407            assert_eq!(random_complex, random_complex2);
2408        }
2409
2410        const SEED: [u8; 32] = [42; 32];
2411
2412        #[test]
2413        fn test_sample_real_validated() {
2414            let mut rng = StdRng::from_seed(SEED);
2415            let dist = Uniform::new(-10.0, 10.0).unwrap();
2416
2417            let val = RealValidated::sample_from(&dist, &mut rng);
2418            assert_eq!(val, -5.257306234905137);
2419
2420            // Check determinism
2421            let mut rng2 = StdRng::from_seed(SEED);
2422            let val2 = RealValidated::sample_from(&dist, &mut rng2);
2423            assert_eq!(val, val2);
2424        }
2425
2426        #[test]
2427        fn test_sample_complex_validated() {
2428            let mut rng = StdRng::from_seed(SEED);
2429            let dist = Uniform::new(-10.0, 10.0).unwrap();
2430
2431            let val = ComplexValidated::sample_from(&dist, &mut rng);
2432            assert_eq!(val.real_part(), -5.257306234905137);
2433            assert_eq!(val.imag_part(), 7.212119776268775);
2434
2435            // Check determinism
2436            let mut rng2 = StdRng::from_seed(SEED);
2437            let val2 = ComplexValidated::sample_from(&dist, &mut rng2);
2438            assert_eq!(val, val2);
2439        }
2440
2441        #[test]
2442        fn new_random_vec_real() {
2443            let mut rng = StdRng::from_seed(SEED);
2444            let dist = Uniform::new(-10.0, 10.0).unwrap();
2445            let vec: Vec<RealValidated> = new_random_vec(3, &dist, &mut rng);
2446            assert_eq!(vec.len(), 3);
2447            assert_eq!(vec[0], -5.257306234905137);
2448            assert_eq!(vec[1], 7.212119776268775);
2449            assert_eq!(vec[2], -4.666248990558111);
2450
2451            // Check determinism
2452            let mut rng2 = StdRng::from_seed(SEED);
2453            let vec2: Vec<RealValidated> = new_random_vec(3, &dist, &mut rng2);
2454            assert_eq!(vec, vec2);
2455        }
2456
2457        #[test]
2458        fn new_random_vec_complex() {
2459            let mut rng = StdRng::from_seed(SEED);
2460            let dist = Uniform::new(-10.0, 10.0).unwrap();
2461            let vec: Vec<ComplexValidated> = new_random_vec(3, &dist, &mut rng);
2462            assert_eq!(vec.len(), 3);
2463            assert_eq!(vec[0].real_part(), -5.257306234905137);
2464            assert_eq!(vec[0].imag_part(), 7.212119776268775);
2465            assert_eq!(vec[1].real_part(), -4.666248990558111);
2466            assert_eq!(vec[1].imag_part(), 9.66047141517383);
2467            assert_eq!(vec[2].real_part(), -9.04279551029691);
2468            assert_eq!(vec[2].imag_part(), -1.026624649331671);
2469
2470            // Check determinism
2471            let mut rng2 = StdRng::from_seed(SEED);
2472            let vec2: Vec<ComplexValidated> = new_random_vec(3, &dist, &mut rng2);
2473            assert_eq!(vec, vec2);
2474        }
2475    }
2476}