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