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, capture_backtrace,
13 },
14};
15use derive_more::with_trait::Neg;
16use duplicate::duplicate_item;
17use num::Complex;
18use rug::float::Constant as MpfrConstant;
19use rug::ops::{CompleteRound, Pow as RugPow};
20use std::{
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 #[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 self.prec().hash(state);
105
106 if self.is_zero() {
108 rug::Float::with_val(self.prec(), 0.0)
110 .to_string_radix(10, None)
111 .hash(state);
112 } else {
113 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 #[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 #[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 #[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, MpfrConstant::Pi)
197 }
198
199 #[inline(always)]
200 fn raw_two_pi(precision: u32) -> Self {
201 rug::Float::with_val(precision, MpfrConstant::Pi) * 2
202 }
203
204 #[inline(always)]
205 fn raw_pi_div_2(precision: u32) -> Self {
206 rug::Float::with_val(precision, MpfrConstant::Pi) / 2
207 }
208
209 #[inline(always)]
210 fn raw_max_finite(precision: u32) -> Self {
211 let one = rug::Float::with_val(precision, 1);
217 let eps = rug::Float::with_val(precision, rug::Float::u_pow_u(2, precision)).recip();
218 let significand = one - &eps;
219
220 let max_exp = rug::float::exp_max() - 1;
222 significand * rug::Float::with_val(precision, rug::Float::u_pow_u(2, max_exp as u32))
224 }
225
226 #[inline(always)]
227 fn raw_min_finite(precision: u32) -> Self {
228 Self::raw_max_finite(precision).neg()
229 }
230
231 #[inline(always)]
232 fn raw_epsilon(precision: u32) -> Self {
233 rug::Float::u_pow_u(2, precision - 1)
234 .complete(precision)
235 .recip()
236 }
237
238 #[inline(always)]
239 fn raw_ln_2(precision: u32) -> Self {
240 rug::Float::with_val(precision, MpfrConstant::Log2)
242 }
243
244 #[inline(always)]
245 fn raw_ln_10(precision: u32) -> Self {
246 let ln2 = rug::Float::with_val(precision, MpfrConstant::Log2);
249 let log2_10 = rug::Float::with_val(precision, 10).log2();
250 ln2 * log2_10
251 }
252
253 #[inline(always)]
254 fn raw_log10_2(precision: u32) -> Self {
255 rug::Float::with_val(precision, 2.).log10()
256 }
257
258 #[inline(always)]
259 fn raw_log2_10(precision: u32) -> Self {
260 rug::Float::with_val(precision, 10.).log2()
261 }
262
263 #[inline(always)]
264 fn raw_log2_e(precision: u32) -> Self {
265 rug::Float::with_val(precision, MpfrConstant::Log2).recip()
268 }
269
270 #[inline(always)]
271 fn raw_log10_e(precision: u32) -> Self {
272 let ln2 = rug::Float::with_val(precision, MpfrConstant::Log2);
274 let log2_10 = rug::Float::with_val(precision, 10).log2();
275 (ln2 * log2_10).recip()
276 }
277
278 #[inline(always)]
279 fn raw_e(precision: u32) -> Self {
280 rug::Float::with_val(precision, 1.).exp()
281 }
282
283 #[inline(always)]
284 fn try_new_raw_real_from_f64<RealPolicy: ValidationPolicyReal<Value = Self>>(
285 value: f64,
286 ) -> Result<Self, ErrorsTryFromf64<Self>> {
287 let precision = RealPolicy::PRECISION;
288 let value_rug = RealPolicy::validate(rug::Float::with_val(precision, value))
289 .map_err(|e| ErrorsTryFromf64::Output { source: e })?;
290 if value_rug == value {
291 Ok(value_rug)
292 } else {
293 Err(ErrorsTryFromf64::NonRepresentableExactly {
294 value_in: value,
295 value_converted_from_f64: value_rug,
296 precision,
297 backtrace: capture_backtrace(),
298 })
299 }
300 }
301
302 #[inline(always)]
303 fn precision(&self) -> u32 {
304 rug::Float::prec(self)
305 }
306
307 #[inline(always)]
308 fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<rug::Float, usize>> {
309 if !self.is_finite() {
310 return Err(ErrorsRawRealToInteger::NotFinite {
311 value: self,
312 backtrace: capture_backtrace(),
313 });
314 }
315
316 let truncation = self.clone().trunc();
317
318 let out_of_range = || ErrorsRawRealToInteger::OutOfRange {
319 value: self,
320 min: usize::MIN,
321 max: usize::MAX,
322 backtrace: capture_backtrace(),
323 };
324
325 let truncation_as_rug_integer = truncation.to_integer().ok_or_else(out_of_range.clone())?;
326
327 truncation_as_rug_integer
328 .to_usize()
329 .ok_or_else(out_of_range)
330 }
331}
332
333impl RawScalarTrait for rug::Complex {
334 type ValidationErrors = ErrorsValidationRawComplex<ErrorsValidationRawReal<rug::Float>>;
335
336 fn raw_zero(precision: u32) -> Self {
337 rug::Complex::with_val(precision, (0., 0.))
338 }
339
340 fn is_zero(&self) -> bool {
341 rug::Complex::is_zero(self)
342 }
343
344 fn raw_one(precision: u32) -> Self {
345 rug::Complex::with_val(precision, (1., 0.))
346 }
347
348 #[duplicate_item(
349 unchecked_method method;
350 [unchecked_reciprocal] [recip];
351 [unchecked_exp] [exp];
352 [unchecked_sqrt] [sqrt];
353 [unchecked_sin] [sin];
354 [unchecked_asin] [asin];
355 [unchecked_cos] [cos];
356 [unchecked_acos] [acos];
357 [unchecked_tan] [tan];
358 [unchecked_atan] [atan];
359 [unchecked_sinh] [sinh];
360 [unchecked_asinh] [asinh];
361 [unchecked_cosh] [cosh];
362 [unchecked_acosh] [acosh];
363 [unchecked_tanh] [tanh];
364 [unchecked_atanh] [atanh];
365 [unchecked_ln] [ln];
366 [unchecked_log10] [log10];
367 )]
368 #[inline(always)]
369 fn unchecked_method(self) -> Self {
370 rug::Complex::method(self)
371 }
372
373 #[inline(always)]
374 fn unchecked_log2(self) -> Self {
375 let ln_2 = rug::Float::with_val(self.real().prec(), 2.).ln();
376 rug::Complex::ln(self) / ln_2
377 }
378
379 #[duplicate_item(
380 unchecked_method exponent_type;
381 [unchecked_pow_exponent_i8] [i8];
382 [unchecked_pow_exponent_i16] [i16];
383 [unchecked_pow_exponent_i32] [i32];
384 [unchecked_pow_exponent_i64] [i64];
385 [unchecked_pow_exponent_i128] [i128];
386 [unchecked_pow_exponent_isize] [isize];
387 [unchecked_pow_exponent_u8] [u8];
388 [unchecked_pow_exponent_u16] [u16];
389 [unchecked_pow_exponent_u32] [u32];
390 [unchecked_pow_exponent_u64] [u64];
391 [unchecked_pow_exponent_u128] [u128];
392 [unchecked_pow_exponent_usize] [usize];
393 )]
394 #[inline(always)]
395 fn unchecked_method(self, exponent: &exponent_type) -> Self {
396 rug::Complex::pow(self, exponent)
397 }
398
399 #[inline(always)]
403 fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
404 rug::Complex::mul_add(self, b, c)
405 }
406
407 fn compute_hash<H: Hasher>(&self, state: &mut H) {
408 self.raw_real_part().compute_hash(state);
409 self.raw_imag_part().compute_hash(state);
410 }
411}
412
413impl Conjugate for rug::Complex {
414 #[inline(always)]
415 fn conjugate(self) -> Self {
416 rug::Complex::conj(self)
417 }
418}
419
420impl RawComplexTrait for rug::Complex {
421 type RawReal = rug::Float;
422
423 fn new_unchecked_raw_complex(real: rug::Float, imag: rug::Float) -> Self {
424 debug_assert_eq!(
425 real.prec(),
426 imag.prec(),
427 "Different precision between real and imaginary part!"
428 );
429 rug::Complex::with_val(real.prec(), (real, imag))
430 }
431
432 fn mut_raw_real_part(&mut self) -> &mut rug::Float {
434 self.mut_real()
435 }
436
437 fn mut_raw_imag_part(&mut self) -> &mut rug::Float {
439 self.mut_imag()
440 }
441
442 #[inline(always)]
443 fn unchecked_abs(self) -> rug::Float {
444 rug::Complex::abs(self).into_real_imag().0
445 }
446
447 #[inline(always)]
448 fn raw_real_part(&self) -> &rug::Float {
449 self.real()
450 }
451
452 #[inline(always)]
453 fn raw_imag_part(&self) -> &rug::Float {
454 self.imag()
455 }
456
457 #[inline(always)]
458 fn unchecked_arg(self) -> rug::Float {
459 rug::Complex::arg(self).into_real_imag().0
460 }
461
462 #[inline(always)]
463 fn unchecked_pow_exponent_real(self, exponent: &rug::Float) -> Self {
464 rug::Complex::pow(self, exponent)
465 }
466}
467
468impl FpChecks for rug::Float {
469 fn is_finite(&self) -> bool {
470 rug::Float::is_finite(self)
471 }
472
473 fn is_infinite(&self) -> bool {
474 rug::Float::is_infinite(self)
475 }
476
477 fn is_nan(&self) -> bool {
478 rug::Float::is_nan(self)
479 }
480 fn is_normal(&self) -> bool {
481 rug::Float::is_normal(self)
482 }
483}
484
485impl FpChecks for rug::Complex {
486 #[inline(always)]
488 fn is_finite(&self) -> bool {
489 self.real().is_finite() && self.imag().is_finite()
490 }
491
492 #[inline(always)]
494 fn is_infinite(&self) -> bool {
495 !self.is_nan() && (self.real().is_infinite() || self.imag().is_infinite())
496 }
497
498 #[inline(always)]
500 fn is_nan(&self) -> bool {
501 self.real().is_nan() || self.imag().is_nan()
502 }
503
504 #[inline(always)]
506 fn is_normal(&self) -> bool {
507 self.real().is_normal() && self.imag().is_normal()
508 }
509}
510
511pub type RugStrictFinite<const PRECISION: u32> = NumKernelStrictFinite<rug::Float, PRECISION>;
565pub type RealRugStrictFinite<const PRECISION: u32> = RealValidated<RugStrictFinite<PRECISION>>;
570
571pub type ComplexRugStrictFinite<const PRECISION: u32> =
573 ComplexValidated<RugStrictFinite<PRECISION>>;
574
575impl Sign for rug::Float {
576 #[inline(always)]
578 fn kernel_copysign(self, sign: &Self) -> Self {
579 self.copysign(sign)
580 }
581
582 #[inline(always)]
584 fn kernel_is_sign_negative(&self) -> bool {
585 self.is_sign_negative()
586 }
587
588 #[inline(always)]
590 fn kernel_is_sign_positive(&self) -> bool {
591 self.is_sign_positive()
592 }
593
594 #[inline(always)]
602 fn kernel_signum(self) -> Self {
603 self.signum()
604 }
605}
606
607impl Rounding for rug::Float {
608 #[inline(always)]
610 fn kernel_ceil(self) -> Self {
611 self.ceil()
612 }
613
614 #[inline(always)]
616 fn kernel_floor(self) -> Self {
617 self.floor()
618 }
619
620 #[inline(always)]
622 fn kernel_fract(self) -> Self {
623 self.fract()
624 }
625
626 #[inline(always)]
628 fn kernel_round(self) -> Self {
629 self.round()
630 }
631
632 #[inline(always)]
653 fn kernel_round_ties_even(self) -> Self {
654 self.round_even()
655 }
656
657 #[inline(always)]
674 fn kernel_trunc(self) -> Self {
675 self.trunc()
676 }
677}
678
679impl<const PRECISION: u32> TryFrom<Complex<f64>> for ComplexRugStrictFinite<PRECISION> {
683 type Error = ErrorsValidationRawComplex<ErrorsTryFromf64<rug::Float>>;
684
685 fn try_from(value: Complex<f64>) -> Result<Self, Self::Error> {
686 let real_part = RealRugStrictFinite::<PRECISION>::try_from_f64(value.re);
687 let imag_part = RealRugStrictFinite::<PRECISION>::try_from_f64(value.im);
688
689 match (real_part, imag_part) {
690 (Ok(real_part), Ok(imag_part)) => Ok(Self {
691 value: rug::Complex::with_val(
692 PRECISION,
693 (real_part.into_inner(), imag_part.into_inner()),
694 ),
695 _phantom: PhantomData,
696 }),
697 (Err(error_real_part), Ok(_)) => Err(ErrorsValidationRawComplex::InvalidRealPart {
698 source: error_real_part,
699 }),
700 (Ok(_), Err(error_imaginary_part)) => {
701 Err(ErrorsValidationRawComplex::InvalidImaginaryPart {
702 source: error_imaginary_part,
703 })
704 }
705 (Err(error_real_part), Err(error_imaginary_part)) => {
706 Err(ErrorsValidationRawComplex::InvalidBothParts {
707 real_error: error_real_part,
708 imag_error: error_imaginary_part,
709 })
710 }
711 }
712 }
713}
714#[duplicate_item(
719 T;
720 [rug::Float];
721 [rug::Complex];
722)]
723impl NegAssign for T {
725 fn neg_assign(&mut self) {
727 <T as rug::ops::NegAssign>::neg_assign(self);
728 }
729}
730#[cfg(test)]
733mod tests {
734 use super::*;
735 use crate::{
736 ACosH, ComplexRugStrictFinite, ComplexScalarConstructors, ComplexScalarGetParts,
737 ComplexScalarMutateParts, ComplexScalarSetParts, Constants, Max, Min,
738 functions::{
739 ACos, ACosHErrors, ACosHInputErrors, ACosRealErrors, ACosRealInputErrors, ASin,
740 ASinRealErrors, ASinRealInputErrors, ATan, ATan2, ATan2Errors, ATanComplexErrors,
741 ATanComplexInputErrors, ATanH, ATanHErrors, ATanHInputErrors, Abs, Clamp, Exp,
742 ExpErrors, Hypot, Ln, Log2, LogarithmComplexErrors, LogarithmComplexInputErrors,
743 NegAssign, Pow, PowComplexBaseRealExponentErrors, PowIntExponentErrors,
744 PowIntExponentInputErrors, PowRealBaseRealExponentErrors, Reciprocal, ReciprocalErrors,
745 Sqrt, SqrtRealErrors, TotalCmp,
746 },
747 validation::ErrorsValidationRawReal,
748 };
749 use num::{One, Zero};
750 use rug::Float;
751 use try_create::{TryNew, TryNewValidated};
752
753 const PRECISION: u32 = 53;
754
755 mod fp_checks {
756 use super::*;
757 use crate::kernels::rug::{ComplexRugStrictFinite, RealRugStrictFinite};
758 use rug::Float;
759
760 #[test]
761 fn is_finite() {
762 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
763 assert!(real.is_finite());
764
765 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::INFINITY));
766 assert!(real.is_err());
767
768 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
769 53,
770 (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
771 ))
772 .unwrap();
773 assert!(complex.is_finite());
774
775 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
776 53,
777 (Float::with_val(53, f64::INFINITY), Float::with_val(53, 1.0)),
778 ));
779 assert!(complex.is_err());
780 }
781
782 #[test]
783 fn is_infinite() {
784 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
785 assert!(!real.is_infinite());
786
787 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::INFINITY));
788 assert!(real.is_err());
789
790 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
791 53,
792 (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
793 ))
794 .unwrap();
795 assert!(!complex.is_infinite());
796
797 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
798 53,
799 (Float::with_val(53, f64::INFINITY), Float::with_val(53, 1.0)),
800 ));
801 assert!(complex.is_err());
802 }
803
804 #[test]
805 fn is_nan() {
806 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
807 assert!(!real.is_nan());
808
809 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::NAN));
810 assert!(matches!(real, Err(ErrorsValidationRawReal::IsNaN { .. })));
811
812 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
813 53,
814 (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
815 ))
816 .unwrap();
817 assert!(!complex.is_nan());
818
819 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
820 53,
821 (Float::with_val(53, f64::NAN), Float::with_val(53, 1.0)),
822 ));
823 assert!(matches!(
824 complex,
825 Err(ErrorsValidationRawComplex::InvalidRealPart {
826 source: ErrorsValidationRawReal::IsNaN { .. }
827 })
828 ));
829 }
830
831 #[test]
832 fn is_normal() {
833 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
834 assert!(real.is_normal());
835
836 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
837 assert!(!real.is_normal());
838
839 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
840 53,
841 (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
842 ))
843 .unwrap();
844 assert!(complex.is_normal());
845
846 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
847 53,
848 (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
849 ))
850 .unwrap();
851 assert!(!complex.is_normal());
852 }
853 }
854
855 mod abs {
856 use super::*;
857
858 mod real {
859 use super::*;
860
861 #[test]
862 fn abs_valid() {
863 let value =
864 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, -4.0)).unwrap();
865
866 let expected_result =
867 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 4.0)).unwrap();
868 assert_eq!(value.clone().try_abs().unwrap(), expected_result);
869 assert_eq!(value.abs(), expected_result);
870 }
871
872 #[test]
873 fn abs_zero() {
874 let value =
875 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
876
877 let expected_result =
878 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
879 assert_eq!(value.clone().try_abs().unwrap(), expected_result);
880 assert_eq!(value.abs(), expected_result);
881 }
882
883 }
907
908 mod complex {
909 use super::*;
910
911 #[test]
912 fn abs_valid() {
913 let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
914 53,
915 (rug::Float::with_val(53, 3.0), rug::Float::with_val(53, 4.0)),
916 ))
917 .unwrap();
918
919 let expected_result =
920 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 5.0)).unwrap();
921 assert_eq!(value.clone().try_abs().unwrap(), expected_result);
922 assert_eq!(value.abs(), expected_result);
923 }
924
925 #[test]
926 fn abs_zero() {
927 let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
928 53,
929 (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
930 ))
931 .unwrap();
932
933 let expected_result =
934 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
935 assert_eq!(value.clone().try_abs().unwrap(), expected_result);
936 assert_eq!(value.abs(), expected_result);
937 }
938 }
972 }
973
974 mod max_min {
975 use super::*;
976
977 #[test]
978 fn test_realrug_max() {
979 let value =
980 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
981 let other =
982 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
983 let expected =
984 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
985 assert_eq!(Max::max(&value, &other), &expected);
986
987 let neg_value =
988 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
989 .unwrap();
990 let neg_other =
991 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
992 .unwrap();
993 let neg_expected =
994 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
995 .unwrap();
996 assert_eq!(Max::max(&neg_value, &neg_other), &neg_expected);
997 }
998
999 #[test]
1000 fn test_realrug_min() {
1001 let value =
1002 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
1003 let other =
1004 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
1005 let expected =
1006 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
1007 assert_eq!(Min::min(&value, &other), &expected);
1008
1009 let neg_value =
1010 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
1011 .unwrap();
1012 let neg_other =
1013 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
1014 .unwrap();
1015 let neg_expected =
1016 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
1017 .unwrap();
1018 assert_eq!(Min::min(&neg_value, &neg_other), &neg_expected);
1019 }
1020 }
1021
1022 mod builders {
1023 use super::*;
1024
1025 mod real {
1026 use super::*;
1027
1028 #[test]
1029 fn try_new_nan() {
1030 let nan = rug::Float::with_val(PRECISION, f64::NAN);
1031 let err = RealRugStrictFinite::<PRECISION>::try_new(nan).unwrap_err();
1032 assert!(matches!(err, ErrorsValidationRawReal::IsNaN { .. }));
1033 }
1034
1035 #[test]
1036 fn try_new_pos_infinity() {
1037 let pos_infinity = rug::Float::with_val(PRECISION, f64::INFINITY);
1038 let err = RealRugStrictFinite::<PRECISION>::try_new(pos_infinity).unwrap_err();
1039 assert!(matches!(err, ErrorsValidationRawReal::IsPosInfinity { .. }));
1040 }
1041
1042 #[test]
1043 fn try_new_neg_infinity() {
1044 let neg_infinity = rug::Float::with_val(PRECISION, f64::NEG_INFINITY);
1045 let err = RealRugStrictFinite::<PRECISION>::try_new(neg_infinity).unwrap_err();
1046 assert!(matches!(err, ErrorsValidationRawReal::IsNegInfinity { .. }));
1047 }
1048 }
1049
1050 mod complex {
1051 use super::*;
1052
1053 #[test]
1054 fn real_part() {
1055 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1056 rug::Complex::with_val(PRECISION, (1.23, 4.56)),
1057 )
1058 .unwrap();
1059 assert_eq!(c1.real_part(), 1.23);
1060
1061 let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1062 rug::Complex::with_val(PRECISION, (-7.89, 0.12)),
1063 )
1064 .unwrap();
1065 assert_eq!(c2.real_part(), -7.89);
1066
1067 let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1068 rug::Complex::with_val(PRECISION, (0.0, 10.0)),
1069 )
1070 .unwrap();
1071 assert_eq!(c3.real_part(), 0.0);
1072
1073 let c_nan_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1074 rug::Complex::with_val(PRECISION, (f64::NAN, 5.0)),
1075 )
1076 .unwrap_err();
1077 assert!(matches!(
1078 c_nan_re,
1079 ErrorsValidationRawComplex::InvalidRealPart {
1080 source: ErrorsValidationRawReal::IsNaN { .. }
1081 }
1082 ));
1083
1084 let c_inf_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1085 rug::Complex::with_val(PRECISION, (f64::INFINITY, 5.0)),
1086 )
1087 .unwrap_err();
1088 assert!(matches!(
1089 c_inf_re,
1090 ErrorsValidationRawComplex::InvalidRealPart {
1091 source: ErrorsValidationRawReal::IsPosInfinity { .. }
1092 }
1093 ));
1094
1095 let c_neg_inf_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1096 rug::Complex::with_val(PRECISION, (f64::NEG_INFINITY, 5.0)),
1097 )
1098 .unwrap_err();
1099 assert!(matches!(
1100 c_neg_inf_re,
1101 ErrorsValidationRawComplex::InvalidRealPart {
1102 source: ErrorsValidationRawReal::IsNegInfinity { .. }
1103 }
1104 ));
1105 }
1106
1107 #[test]
1108 fn imag_part() {
1109 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1110 rug::Complex::with_val(PRECISION, (1.23, 4.56)),
1111 )
1112 .unwrap();
1113 assert_eq!(c1.imag_part(), 4.56);
1114
1115 let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1116 rug::Complex::with_val(PRECISION, (-7.89, 0.12)),
1117 )
1118 .unwrap();
1119 assert_eq!(c2.imag_part(), 0.12);
1120
1121 let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1122 rug::Complex::with_val(PRECISION, (10.0, 0.0)),
1123 )
1124 .unwrap();
1125 assert_eq!(c3.imag_part(), 0.0);
1126
1127 let c_nan_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1128 rug::Complex::with_val(PRECISION, (5.0, f64::NAN)),
1129 )
1130 .unwrap_err();
1131 assert!(matches!(
1132 c_nan_im,
1133 ErrorsValidationRawComplex::InvalidImaginaryPart {
1134 source: ErrorsValidationRawReal::IsNaN { .. }
1135 }
1136 ));
1137
1138 let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1139 rug::Complex::with_val(PRECISION, (5.0, f64::INFINITY)),
1140 )
1141 .unwrap_err();
1142 assert!(matches!(
1143 c_inf_im,
1144 ErrorsValidationRawComplex::InvalidImaginaryPart {
1145 source: ErrorsValidationRawReal::IsPosInfinity { .. }
1146 }
1147 ));
1148
1149 let c_neg_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1150 rug::Complex::with_val(PRECISION, (5.0, f64::NEG_INFINITY)),
1151 )
1152 .unwrap_err();
1153 assert!(matches!(
1154 c_neg_inf_im,
1155 ErrorsValidationRawComplex::InvalidImaginaryPart {
1156 source: ErrorsValidationRawReal::IsNegInfinity { .. }
1157 }
1158 ));
1159 }
1160
1161 #[test]
1162 fn try_new_complex() {
1163 let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
1164 let i1 = RealRugStrictFinite::<PRECISION>::try_from_f64(4.56).unwrap();
1165 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
1166 r1.as_ref().clone(),
1167 i1.as_ref().clone(),
1168 )
1169 .unwrap();
1170 assert_eq!(c1.real_part(), r1);
1171 assert_eq!(c1.imag_part(), i1);
1172
1173 let r2 = RealRugStrictFinite::<PRECISION>::try_from_f64(-7.89).unwrap();
1174 let i2 = RealRugStrictFinite::<PRECISION>::try_from_f64(-0.12).unwrap();
1175 let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
1176 r2.as_ref().clone(),
1177 i2.as_ref().clone(),
1178 )
1179 .unwrap();
1180 assert_eq!(c2.real_part(), r2);
1181 assert_eq!(c2.imag_part(), i2);
1182
1183 let r3 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
1184 let i3 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
1185 let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
1186 r3.as_ref().clone(),
1187 i3.as_ref().clone(),
1188 )
1189 .unwrap();
1190 assert_eq!(c3.real_part(), r3);
1191 assert_eq!(c3.real_part(), i3);
1192 assert!(c3.is_zero());
1193
1194 let c_nan_re = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
1195 Float::with_val(PRECISION, f64::NAN),
1196 Float::with_val(PRECISION, 5.0),
1197 )
1198 .unwrap_err();
1199 assert!(matches!(
1200 c_nan_re,
1201 ErrorsValidationRawComplex::InvalidRealPart { .. }
1202 ));
1203
1204 let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
1205 Float::with_val(PRECISION, 10.0),
1206 Float::with_val(PRECISION, f64::INFINITY),
1207 )
1208 .unwrap_err();
1209 assert!(matches!(
1210 c_inf_im,
1211 ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
1212 ));
1213
1214 let c_nan_re_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
1215 Float::with_val(PRECISION, f64::NAN),
1216 Float::with_val(PRECISION, f64::INFINITY),
1217 )
1218 .unwrap_err();
1219 assert!(matches!(
1220 c_nan_re_inf_im,
1221 ErrorsValidationRawComplex::InvalidBothParts { .. }
1222 ));
1223 }
1224
1225 #[test]
1226 fn try_from_complexf64() {
1227 let c1_in = num::Complex::new(1.23, 4.56);
1228 let c1 = ComplexRugStrictFinite::<PRECISION>::try_from(c1_in).unwrap();
1229 assert_eq!(c1.real_part(), c1_in.re);
1230 assert_eq!(c1.imag_part(), c1_in.im);
1231
1232 let c2_in = num::Complex::new(-7.89, -0.12);
1233 let c2 = ComplexRugStrictFinite::<PRECISION>::try_from(c2_in).unwrap();
1234 assert_eq!(c2.real_part(), c2_in.re);
1235 assert_eq!(c2.imag_part(), c2_in.im);
1236
1237 let c3_in = num::Complex::new(0., 0.);
1238 let c3 = ComplexRugStrictFinite::<PRECISION>::try_from(c3_in).unwrap();
1239 assert_eq!(c3.real_part(), c3_in.re);
1240 assert_eq!(c3.imag_part(), c3_in.im);
1241
1242 let c_nan_re =
1243 ComplexRugStrictFinite::<PRECISION>::try_from(num::Complex::new(f64::NAN, 5.0))
1244 .unwrap_err();
1245 assert!(matches!(
1246 c_nan_re,
1247 ErrorsValidationRawComplex::InvalidRealPart { .. }
1248 ));
1249
1250 let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_from(num::Complex::new(
1251 10.0,
1252 f64::INFINITY,
1253 ))
1254 .unwrap_err();
1255 assert!(matches!(
1256 c_inf_im,
1257 ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
1258 ));
1259
1260 let c_nan_re_inf_im = ComplexRugStrictFinite::<PRECISION>::try_from(
1261 num::Complex::new(f64::NAN, f64::INFINITY),
1262 )
1263 .unwrap_err();
1264 assert!(matches!(
1265 c_nan_re_inf_im,
1266 ErrorsValidationRawComplex::InvalidBothParts { .. }
1267 ));
1268 }
1269
1270 #[test]
1271 fn try_new_pure_real() {
1272 let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
1273 let c1 =
1274 ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(r1.as_ref().clone())
1275 .unwrap();
1276 assert_eq!(c1.real_part(), r1);
1277 assert!(c1.imag_part().is_zero());
1278
1279 let c_nan = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
1280 Float::with_val(PRECISION, f64::NAN),
1281 )
1282 .unwrap_err();
1283 assert!(matches!(
1284 c_nan,
1285 ErrorsValidationRawComplex::InvalidRealPart {
1286 source: ErrorsValidationRawReal::IsNaN { .. }
1287 }
1288 ));
1289 }
1290
1291 #[test]
1292 fn try_new_pure_imaginary() {
1293 let i1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
1294 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
1295 i1.as_ref().clone(),
1296 )
1297 .unwrap();
1298 assert!(c1.real_part().is_zero());
1299 assert_eq!(c1.imag_part(), i1);
1300
1301 let c_nan = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
1302 Float::with_val(PRECISION, f64::NAN),
1303 )
1304 .unwrap_err();
1305 assert!(matches!(
1306 c_nan,
1307 ErrorsValidationRawComplex::InvalidImaginaryPart {
1308 source: ErrorsValidationRawReal::IsNaN { .. }
1309 }
1310 ));
1311 }
1312
1313 #[test]
1314 fn add_to_real_part() {
1315 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1316 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1317 )
1318 .unwrap();
1319 c.add_to_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1320 assert_eq!(c.real_part(), 4.0);
1321 assert_eq!(c.imag_part(), 2.0);
1322
1323 c.add_to_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0).unwrap());
1324 assert_eq!(c.real_part(), -1.0);
1325 assert_eq!(c.imag_part(), 2.0);
1326 }
1327
1328 #[test]
1329 fn add_to_imaginary_part() {
1330 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1331 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1332 )
1333 .unwrap();
1334 c.add_to_imaginary_part(
1335 &RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(),
1336 );
1337 assert_eq!(c.real_part(), 1.0);
1338 assert_eq!(c.imag_part(), 5.0);
1339
1340 c.add_to_imaginary_part(
1341 &RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap(),
1342 );
1343 assert_eq!(c.real_part(), 1.0);
1344 assert_eq!(c.imag_part(), 1.0);
1345 }
1346
1347 #[test]
1348 fn multiply_real_part() {
1349 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1350 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1351 )
1352 .unwrap();
1353 c.multiply_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1354 assert_eq!(c.real_part(), 3.0);
1355 assert_eq!(c.imag_part(), 2.0);
1356
1357 c.multiply_real_part(
1358 &RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap(),
1359 );
1360 assert_eq!(c.real_part(), -6.0);
1361 assert_eq!(c.imag_part(), 2.0);
1362 }
1363
1364 #[test]
1365 fn multiply_imaginary_part() {
1366 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1367 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1368 )
1369 .unwrap();
1370 c.multiply_imaginary_part(
1371 &RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(),
1372 );
1373 assert_eq!(c.real_part(), 1.0);
1374 assert_eq!(c.imag_part(), 6.0);
1375
1376 c.multiply_imaginary_part(
1377 &RealRugStrictFinite::<PRECISION>::try_from_f64(-0.5).unwrap(),
1378 );
1379 assert_eq!(c.real_part(), 1.0);
1380 assert_eq!(c.imag_part(), -3.0);
1381 }
1382
1383 #[test]
1384 fn set_real_part() {
1385 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1386 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1387 )
1388 .unwrap();
1389 c.set_real_part(RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1390 assert_eq!(c.real_part(), 3.0);
1391 assert_eq!(c.imag_part(), 2.0);
1392
1393 c.set_real_part(RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap());
1394 assert_eq!(c.real_part(), -4.0);
1395 assert_eq!(c.imag_part(), 2.0);
1396 }
1397
1398 #[test]
1399 fn set_imaginary_part() {
1400 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1401 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1402 )
1403 .unwrap();
1404 c.set_imaginary_part(RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1405 assert_eq!(c.real_part(), 1.0);
1406 assert_eq!(c.imag_part(), 3.0);
1407
1408 c.set_imaginary_part(RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap());
1409 assert_eq!(c.real_part(), 1.0);
1410 assert_eq!(c.imag_part(), -4.0);
1411 }
1412 }
1413 }
1414
1415 mod mul {
1416 use super::*;
1417
1418 mod real {
1419 use super::*;
1420
1421 #[test]
1422 fn multiply_ref() {
1423 let r1 = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1424 PRECISION, 3.0,
1425 ))
1426 .unwrap();
1427 let r2 = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1428 PRECISION, 4.0,
1429 ))
1430 .unwrap();
1431 let result = r1 * &r2;
1432 assert_eq!(
1433 result,
1434 RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1435 PRECISION, 12.0
1436 ))
1437 .unwrap()
1438 );
1439 }
1440 }
1441
1442 mod complex {
1443 use super::*;
1444
1445 #[test]
1446 fn multiply_ref() {
1447 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1448 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1449 )
1450 .unwrap();
1451 let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1452 rug::Complex::with_val(PRECISION, (3.0, 4.0)),
1453 )
1454 .unwrap();
1455 let result = c1 * &c2;
1456 assert_eq!(
1457 result,
1458 ComplexRugStrictFinite::<PRECISION>::try_new_validated(rug::Complex::with_val(
1459 PRECISION,
1460 (-5.0, 10.0),
1461 ))
1462 .unwrap()
1463 ); }
1465
1466 #[test]
1467 fn complex_times_real() {
1468 let r = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1469 PRECISION, 2.0,
1470 ))
1471 .unwrap();
1472 let c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1473 rug::Complex::with_val(PRECISION, (3.0, 4.0)),
1474 )
1475 .unwrap();
1476
1477 let result_expected = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1478 rug::Complex::with_val(PRECISION, (6.0, 8.0)),
1479 )
1480 .unwrap(); let result = c.clone() * &r;
1483 assert_eq!(&result, &result_expected);
1484
1485 let result = c.clone() * r.clone();
1486 assert_eq!(&result, &result_expected);
1487
1488 let mut result = c.clone();
1489 result *= &r;
1490 assert_eq!(&result, &result_expected);
1491
1492 let mut result = c.clone();
1493 result *= r;
1494 assert_eq!(&result, &result_expected);
1495 }
1496
1497 #[test]
1498 fn real_times_complex() {
1499 let r = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1500 PRECISION, 2.0,
1501 ))
1502 .unwrap();
1503 let c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1504 rug::Complex::with_val(PRECISION, (3.0, 4.0)),
1505 )
1506 .unwrap();
1507
1508 let result_expected = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1509 rug::Complex::with_val(PRECISION, (6.0, 8.0)),
1510 )
1511 .unwrap(); let result = &r * c.clone();
1514 assert_eq!(&result, &result_expected);
1515
1516 let result = r * c.clone();
1517 assert_eq!(&result, &result_expected);
1518 }
1519 }
1520 }
1521
1522 mod arithmetic {
1523 use super::*;
1524
1525 mod real {
1526 use super::*;
1527
1528 #[test]
1529 fn neg_assign() {
1530 let mut a = rug::Float::with_val(PRECISION, 1.);
1531 a.neg_assign();
1532 let a_expected = rug::Float::with_val(PRECISION, -1.);
1533 assert_eq!(a, a_expected);
1534
1535 let mut b = RealRugStrictFinite::<PRECISION>::one();
1536 b.neg_assign();
1537 let b_expected = RealRugStrictFinite::<PRECISION>::try_new_validated(
1538 rug::Float::with_val(PRECISION, -1.),
1539 )
1540 .unwrap();
1541 assert_eq!(&b, &b_expected);
1542 }
1543
1544 #[test]
1545 #[should_panic(expected = "Division failed validation")]
1546 fn div_by_zero() {
1547 let one = RealRugStrictFinite::<PRECISION>::one();
1548 let zero = RealRugStrictFinite::<PRECISION>::zero();
1549 let _ = &one / &zero;
1550 }
1551
1552 #[test]
1553 #[should_panic(expected = "Division failed validation")]
1554 fn div_assign_by_zero() {
1555 let mut num = RealRugStrictFinite::<PRECISION>::one();
1556 let zero_ref = &RealRugStrictFinite::<PRECISION>::zero();
1557 num /= zero_ref;
1558 }
1559 }
1560
1561 mod complex {
1562 use super::*;
1563
1564 #[test]
1565 fn neg_assign() {
1566 let re = rug::Float::with_val(PRECISION, 1.);
1567 let im = rug::Float::with_val(PRECISION, 2.);
1568 let mut num = rug::Complex::with_val(PRECISION, (re, im));
1569 num.neg_assign();
1570 let expected = rug::Complex::with_val(
1571 PRECISION,
1572 (
1573 rug::Float::with_val(PRECISION, -1.),
1574 rug::Float::with_val(PRECISION, -2.),
1575 ),
1576 );
1577 assert_eq!(&num, &expected);
1578
1579 let mut num = ComplexRugStrictFinite::<PRECISION>::try_new_validated(num).unwrap();
1580 let expected = num.clone().neg();
1581 num.neg_assign();
1582 assert_eq!(&num, &expected);
1583 }
1584
1585 #[test]
1586 #[should_panic(expected = "Division failed validation")]
1587 fn div_by_zero() {
1588 let one = ComplexRugStrictFinite::<PRECISION>::one();
1589 let zero = ComplexRugStrictFinite::<PRECISION>::zero();
1590 let _ = &one / &zero;
1591 }
1592
1593 #[test]
1594 #[should_panic(expected = "Division failed validation")]
1595 fn div_assign_by_zero() {
1596 let mut num = ComplexRugStrictFinite::<PRECISION>::one();
1597 let zero_ref = &ComplexRugStrictFinite::<PRECISION>::zero();
1598 num /= zero_ref;
1599 }
1600 }
1601 }
1602
1603 mod real_scalar_methods {
1604 use super::*;
1605
1606 #[test]
1607 fn epsilon() {
1608 let eps = RealRugStrictFinite::<PRECISION>::epsilon();
1609 assert!(eps.is_finite() && eps > RealRugStrictFinite::<PRECISION>::zero());
1610 let expected_eps_val =
1611 rug::Float::with_val(PRECISION, 2.0).pow(1i32 - PRECISION as i32);
1612 let expected_eps = RealRugStrictFinite::<PRECISION>::try_new(expected_eps_val).unwrap();
1613 assert_eq!(eps, expected_eps, "Epsilon value mismatch");
1614 }
1615
1616 #[test]
1617 fn clamp() {
1618 let val = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap();
1619 let min_val = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
1620 let max_val = RealRugStrictFinite::<PRECISION>::try_from_f64(10.0).unwrap();
1621
1622 assert_eq!(val.clone().clamp(&min_val, &max_val), val);
1623 assert_eq!(
1624 RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0)
1625 .unwrap()
1626 .clamp(&min_val, &max_val),
1627 min_val
1628 );
1629 assert_eq!(
1630 RealRugStrictFinite::<PRECISION>::try_from_f64(15.0)
1631 .unwrap()
1632 .clamp(&min_val, &max_val),
1633 max_val
1634 );
1635 }
1636
1637 #[test]
1638 fn hypot() {
1639 let a = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap();
1640 let b = RealRugStrictFinite::<PRECISION>::try_from_f64(4.0).unwrap();
1641 let expected = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap();
1642 assert_eq!(a.hypot(&b), expected);
1643 }
1644
1645 #[test]
1646 fn signum() {
1647 assert_eq!(
1648 RealRugStrictFinite::<PRECISION>::try_from_f64(5.0)
1649 .unwrap()
1650 .kernel_signum(),
1651 RealRugStrictFinite::<PRECISION>::one()
1652 );
1653 assert_eq!(
1654 RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0)
1655 .unwrap()
1656 .kernel_signum(),
1657 RealRugStrictFinite::<PRECISION>::negative_one()
1658 );
1659 assert_eq!(
1661 RealRugStrictFinite::<PRECISION>::zero().kernel_signum(),
1662 RealRugStrictFinite::<PRECISION>::one()
1663 );
1664 }
1665
1666 #[test]
1667 fn total_cmp() {
1668 let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0).unwrap();
1669 let r2 = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1670 assert_eq!(r1.total_cmp(&r1), Ordering::Equal);
1671 assert_eq!(r1.total_cmp(&r2), Ordering::Less);
1672 assert_eq!(r2.total_cmp(&r1), Ordering::Greater);
1673 }
1674
1675 #[test]
1676 fn mul_add_mul_mut() {
1677 let mut a = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1678 let b = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(); let c = RealRugStrictFinite::<PRECISION>::try_from_f64(4.0).unwrap(); let d = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap(); a.kernel_mul_add_mul_mut(&b, &c, &d);
1683 assert_eq!(
1684 a,
1685 RealRugStrictFinite::<PRECISION>::try_from_f64(26.0).unwrap()
1686 );
1687 }
1688
1689 #[test]
1690 fn mul_sub_mul_mut() {
1691 let mut a = RealRugStrictFinite::<PRECISION>::try_from_f64(10.0).unwrap();
1692 let b = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap(); let c = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(); let d = RealRugStrictFinite::<PRECISION>::try_from_f64(4.0).unwrap(); a.kernel_mul_sub_mul_mut(&b, &c, &d);
1697 assert_eq!(
1698 a,
1699 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1700 );
1701 }
1702
1703 #[test]
1704 fn test_real_rug_constants() {
1705 let raw_float = |f: f64| Float::with_val(PRECISION, f);
1707
1708 let pi = RealRugStrictFinite::<PRECISION>::pi();
1710 let expected_pi = Float::with_val(PRECISION, MpfrConstant::Pi);
1711 assert_eq!(pi.as_ref(), &expected_pi);
1712
1713 let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
1715 let expected_two_pi = Float::with_val(PRECISION, MpfrConstant::Pi) * 2;
1716 assert_eq!(two_pi.as_ref(), &expected_two_pi);
1717
1718 let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1720 let expected_pi_div_2 = Float::with_val(PRECISION, MpfrConstant::Pi) / 2;
1721 assert_eq!(pi_div_2.as_ref(), &expected_pi_div_2);
1722
1723 let e = RealRugStrictFinite::<PRECISION>::e();
1725 let expected_e = raw_float(1.0).exp();
1726 assert_eq!(e.as_ref(), &expected_e);
1727
1728 let log2_e = RealRugStrictFinite::<PRECISION>::log2_e();
1730 let expected_log2_e = Float::with_val(PRECISION, MpfrConstant::Log2).recip();
1731 assert_eq!(log2_e.as_ref(), &expected_log2_e);
1732
1733 let log10_e = RealRugStrictFinite::<PRECISION>::log10_e();
1735 let ln2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1736 let log2_10 = raw_float(10.0).log2();
1737 let expected_log10_e = (ln2 * log2_10).recip();
1738 assert_eq!(log10_e.as_ref(), &expected_log10_e);
1739
1740 let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1742 let expected_ln_2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1743 assert_eq!(ln_2.as_ref(), &expected_ln_2);
1744
1745 let ln_10 = RealRugStrictFinite::<PRECISION>::ln_10();
1747 let ln2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1748 let log2_10 = raw_float(10.0).log2();
1749 let expected_ln_10 = ln2 * log2_10;
1750 assert_eq!(ln_10.as_ref(), &expected_ln_10);
1751
1752 let log2_10 = RealRugStrictFinite::<PRECISION>::log2_10();
1754 let expected_log2_10 = raw_float(10.0).log2();
1755 assert_eq!(log2_10.as_ref(), &expected_log2_10);
1756
1757 let log10_2 = RealRugStrictFinite::<PRECISION>::log10_2();
1759 let expected_log10_2 = raw_float(2.0).log10();
1760 assert_eq!(log10_2.as_ref(), &expected_log10_2);
1761
1762 let max_finite = RealRugStrictFinite::<PRECISION>::max_finite();
1764 let expected_max_finite = <rug::Float as RawRealTrait>::raw_max_finite(PRECISION);
1765 assert_eq!(max_finite.as_ref(), &expected_max_finite);
1766
1767 let min_finite = RealRugStrictFinite::<PRECISION>::min_finite();
1769 let expected_min_finite = <rug::Float as RawRealTrait>::raw_min_finite(PRECISION);
1770 assert_eq!(min_finite.as_ref(), &expected_min_finite);
1771
1772 let epsilon = RealRugStrictFinite::<PRECISION>::epsilon();
1774 let expected_epsilon = <rug::Float as RawRealTrait>::raw_epsilon(PRECISION);
1775 assert_eq!(epsilon.as_ref(), &expected_epsilon);
1776
1777 assert_eq!(
1779 RealRugStrictFinite::<PRECISION>::negative_one().as_ref(),
1780 &raw_float(-1.0)
1781 );
1782
1783 assert_eq!(
1785 RealRugStrictFinite::<PRECISION>::two().as_ref(),
1786 &raw_float(2.0)
1787 );
1788
1789 assert_eq!(
1791 RealRugStrictFinite::<PRECISION>::one_div_2().as_ref(),
1792 &raw_float(0.5)
1793 );
1794 }
1795
1796 #[test]
1800 fn test_real_rug_constants_mpfr_optimization() {
1801 let pi = RealRugStrictFinite::<PRECISION>::pi();
1803 let expected_pi = Float::with_val(PRECISION, MpfrConstant::Pi);
1804 assert_eq!(pi.as_ref(), &expected_pi);
1805
1806 let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1808 let expected_ln_2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1809 assert_eq!(ln_2.as_ref(), &expected_ln_2);
1810
1811 let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
1813 let expected_two_pi = Float::with_val(PRECISION, MpfrConstant::Pi) * 2;
1814 assert_eq!(two_pi.as_ref(), &expected_two_pi);
1815
1816 let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1817 let expected_pi_div_2 = Float::with_val(PRECISION, MpfrConstant::Pi) / 2;
1818 assert_eq!(pi_div_2.as_ref(), &expected_pi_div_2);
1819 }
1820
1821 #[test]
1823 fn test_real_rug_constants_precision_independence() {
1824 type Real100 = RealRugStrictFinite<100>;
1825 type Real200 = RealRugStrictFinite<200>;
1826 type Real500 = RealRugStrictFinite<500>;
1827
1828 let pi_100 = Real100::pi();
1830 let pi_200 = Real200::pi();
1831 let pi_500 = Real500::pi();
1832
1833 let pi_100_f64 = pi_100.as_ref().to_f64();
1836 let pi_200_f64 = pi_200.as_ref().to_f64();
1837 let pi_500_f64 = pi_500.as_ref().to_f64();
1838
1839 let pi_expected = std::f64::consts::PI;
1840 assert!((pi_100_f64 - pi_expected).abs() < 1e-15);
1841 assert!((pi_200_f64 - pi_expected).abs() < 1e-15);
1842 assert!((pi_500_f64 - pi_expected).abs() < 1e-15);
1843
1844 let e_100 = Real100::e();
1846 let e_200 = Real200::e();
1847
1848 let e_100_f64 = e_100.as_ref().to_f64();
1849 let e_200_f64 = e_200.as_ref().to_f64();
1850
1851 let e_expected = std::f64::consts::E;
1852 assert!((e_100_f64 - e_expected).abs() < 1e-15);
1853 assert!((e_200_f64 - e_expected).abs() < 1e-15);
1854 }
1855
1856 #[test]
1858 fn test_real_rug_constants_mathematical_relationships() {
1859 let pi = RealRugStrictFinite::<PRECISION>::pi();
1860 let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
1861 let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1862
1863 let expected_two_pi = pi.as_ref() * Float::with_val(PRECISION, 2);
1865 assert_eq!(two_pi.as_ref(), &expected_two_pi);
1866
1867 let expected_pi_div_2 = pi.as_ref() / Float::with_val(PRECISION, 2);
1869 assert_eq!(pi_div_2.as_ref(), &expected_pi_div_2);
1870
1871 let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1872 let ln_10 = RealRugStrictFinite::<PRECISION>::ln_10();
1873 let log2_e = RealRugStrictFinite::<PRECISION>::log2_e();
1874 let log10_e = RealRugStrictFinite::<PRECISION>::log10_e();
1875
1876 let product = (log2_e.as_ref() * ln_2.as_ref()).complete(PRECISION);
1878 let one = Float::with_val(PRECISION, 1);
1879 let epsilon = Float::with_val(PRECISION, 1e-10);
1880 let diff = (product - &one).abs();
1881 assert!(diff < epsilon);
1882
1883 let product = (log10_e.as_ref() * ln_10.as_ref()).complete(PRECISION);
1885 let diff = (product - &one).abs();
1886 assert!(diff < epsilon);
1887 }
1888
1889 #[test]
1892 fn test_real_rug_constants_consistency() {
1893 let pi1 = RealRugStrictFinite::<PRECISION>::pi();
1895 let pi2 = RealRugStrictFinite::<PRECISION>::pi();
1896 assert_eq!(pi1.as_ref(), pi2.as_ref());
1897
1898 let e1 = RealRugStrictFinite::<PRECISION>::e();
1899 let e2 = RealRugStrictFinite::<PRECISION>::e();
1900 assert_eq!(e1.as_ref(), e2.as_ref());
1901
1902 let ln2_1 = RealRugStrictFinite::<PRECISION>::ln_2();
1903 let ln2_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1904 assert_eq!(ln2_1.as_ref(), ln2_2.as_ref());
1905
1906 let two_pi1 = RealRugStrictFinite::<PRECISION>::two_pi();
1907 let two_pi2 = RealRugStrictFinite::<PRECISION>::two_pi();
1908 assert_eq!(two_pi1.as_ref(), two_pi2.as_ref());
1909
1910 let pi_div_2_1 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1911 let pi_div_2_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1912 assert_eq!(pi_div_2_1.as_ref(), pi_div_2_2.as_ref());
1913 }
1914 }
1915
1916 mod scalar_constructors {
1917 use super::*;
1918 use crate::{
1919 functions::{
1920 ATan2InputErrors, LogarithmRealErrors, LogarithmRealInputErrors,
1921 PowComplexBaseRealExponentInputErrors, PowRealBaseRealExponentInputErrors,
1922 ReciprocalInputErrors, SqrtRealInputErrors,
1923 },
1924 validation::ErrorsValidationRawReal,
1925 };
1926
1927 mod real {
1928 use super::*;
1929
1930 #[test]
1931 fn exp_overflow() {
1932 let large_val = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0e60).unwrap(); let res_large = large_val.try_exp();
1934 assert!(matches!(
1935 res_large,
1936 Err(ExpErrors::Output {
1937 source: ErrorsValidationRawReal::IsPosInfinity { .. }
1938 })
1939 ),);
1940 }
1941
1942 #[test]
1943 fn ln_domain_errors() {
1944 let neg_val = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.0).unwrap();
1945 assert!(matches!(
1946 neg_val.try_ln(),
1947 Err(LogarithmRealErrors::Input {
1948 source: LogarithmRealInputErrors::NegativeArgument { .. }
1949 })
1950 ));
1951
1952 let zero_val = RealRugStrictFinite::<PRECISION>::zero();
1953 assert!(matches!(
1954 zero_val.try_ln(),
1955 Err(LogarithmRealErrors::Input {
1956 source: LogarithmRealInputErrors::ZeroArgument { .. }
1957 })
1958 ));
1959 }
1960 } mod complex {
1963 use super::*;
1964
1965 #[test]
1966 fn log2_zero() {
1967 let zero_val = ComplexRugStrictFinite::<PRECISION>::zero();
1968 assert!(matches!(
1969 zero_val.try_log2(),
1970 Err(LogarithmComplexErrors::Input {
1971 source: LogarithmComplexInputErrors::ZeroArgument { .. }
1972 })
1973 ));
1974 }
1975 } mod pow {
1978 use super::*;
1979
1980 mod real_base {
1981 use super::*;
1982
1983 #[test]
1984 fn negative_base_real_exponent_error() {
1985 let base = RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap();
1986 let exponent = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
1987 let res = base.try_pow(&exponent);
1988 assert!(matches!(
1989 res,
1990 Err(PowRealBaseRealExponentErrors::Input {
1991 source: PowRealBaseRealExponentInputErrors::NegativeBase { .. }
1992 })
1993 ));
1994 }
1995
1996 #[test]
1997 fn real_base_uint_exponent() {
1998 let base = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1999 assert_eq!(
2000 base.clone().try_pow(3u8).unwrap(),
2001 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2002 );
2003 assert_eq!(
2004 base.clone().try_pow(3u16).unwrap(),
2005 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2006 );
2007 assert_eq!(
2008 base.clone().try_pow(3u32).unwrap(),
2009 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2010 );
2011 assert_eq!(
2012 base.clone().try_pow(3u64).unwrap(),
2013 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2014 );
2015 assert_eq!(
2016 base.clone().try_pow(3u128).unwrap(),
2017 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2018 );
2019 assert_eq!(
2020 base.clone().try_pow(3usize).unwrap(),
2021 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2022 );
2023
2024 assert_eq!(
2025 base.clone().pow(3u8),
2026 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2027 );
2028 assert_eq!(
2029 base.clone().pow(3u16),
2030 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2031 );
2032 assert_eq!(
2033 base.clone().pow(3u32),
2034 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2035 );
2036 assert_eq!(
2037 base.clone().pow(3u64),
2038 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2039 );
2040 assert_eq!(
2041 base.clone().pow(3u128),
2042 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2043 );
2044 assert_eq!(
2045 base.clone().pow(3usize),
2046 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2047 );
2048 }
2049
2050 #[test]
2051 fn real_base_int_exponent() {
2052 let base = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
2053 assert_eq!(
2054 base.clone().try_pow(3i8).unwrap(),
2055 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2056 );
2057 assert_eq!(
2058 base.clone().try_pow(3i16).unwrap(),
2059 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2060 );
2061 assert_eq!(
2062 base.clone().try_pow(3i32).unwrap(),
2063 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2064 );
2065 assert_eq!(
2066 base.clone().try_pow(3i64).unwrap(),
2067 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2068 );
2069 assert_eq!(
2070 base.clone().try_pow(3i128).unwrap(),
2071 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2072 );
2073 assert_eq!(
2074 base.clone().try_pow(3isize).unwrap(),
2075 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2076 );
2077
2078 assert_eq!(
2079 base.clone().pow(3i8),
2080 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2081 );
2082 assert_eq!(
2083 base.clone().pow(3i16),
2084 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2085 );
2086 assert_eq!(
2087 base.clone().pow(3i32),
2088 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2089 );
2090 assert_eq!(
2091 base.clone().pow(3i64),
2092 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2093 );
2094 assert_eq!(
2095 base.clone().pow(3i128),
2096 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2097 );
2098 assert_eq!(
2099 base.clone().pow(3isize),
2100 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
2101 );
2102 }
2103
2104 #[test]
2105 fn real_base_int_exponent_zero_neg_exp_error() {
2106 let base = RealRugStrictFinite::<PRECISION>::zero();
2107 let exponent: i32 = -2;
2108 let res = base.try_pow(exponent);
2109 assert!(matches!(
2110 res,
2111 Err(PowIntExponentErrors::Input {
2112 source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
2113 })
2114 ));
2115 }
2116 }
2117
2118 mod complex_base {
2119 use super::*;
2120
2121 #[test]
2122 fn complex_base_uint_exponent() {
2123 let base = ComplexRugStrictFinite::<PRECISION>::try_new(
2124 rug::Complex::with_val(PRECISION, (2.0, 3.0)),
2125 )
2126 .unwrap();
2127 let expected_res = ComplexRugStrictFinite::<PRECISION>::try_new(
2128 rug::Complex::with_val(PRECISION, (-46.0, 9.0)),
2129 )
2130 .unwrap();
2131
2132 assert_eq!(&base.clone().try_pow(3u8).unwrap(), &expected_res);
2133 assert_eq!(&base.clone().try_pow(3u16).unwrap(), &expected_res);
2134 assert_eq!(&base.clone().try_pow(3u32).unwrap(), &expected_res);
2135 assert_eq!(&base.clone().try_pow(3u64).unwrap(), &expected_res);
2136 assert_eq!(&base.clone().try_pow(3u128).unwrap(), &expected_res);
2137 assert_eq!(&base.clone().try_pow(3usize).unwrap(), &expected_res);
2138
2139 assert_eq!(&base.clone().pow(3u8), &expected_res);
2140 assert_eq!(&base.clone().pow(3u16), &expected_res);
2141 assert_eq!(&base.clone().pow(3u32), &expected_res);
2142 assert_eq!(&base.clone().pow(3u64), &expected_res);
2143 assert_eq!(&base.clone().pow(3u128), &expected_res);
2144 assert_eq!(&base.clone().pow(3usize), &expected_res);
2145 }
2146
2147 #[test]
2148 fn complex_base_int_exponent() {
2149 let base = ComplexRugStrictFinite::<PRECISION>::try_new(
2150 rug::Complex::with_val(PRECISION, (2.0, 3.0)),
2151 )
2152 .unwrap();
2153 let expected_res = ComplexRugStrictFinite::<PRECISION>::try_new(
2154 rug::Complex::with_val(PRECISION, (-46.0, 9.0)),
2155 )
2156 .unwrap();
2157
2158 assert_eq!(&base.clone().try_pow(3i8).unwrap(), &expected_res);
2159 assert_eq!(&base.clone().try_pow(3i16).unwrap(), &expected_res);
2160 assert_eq!(&base.clone().try_pow(3i32).unwrap(), &expected_res);
2161 assert_eq!(&base.clone().try_pow(3i64).unwrap(), &expected_res);
2162 assert_eq!(&base.clone().try_pow(3i128).unwrap(), &expected_res);
2163 assert_eq!(&base.clone().try_pow(3isize).unwrap(), &expected_res);
2164
2165 assert_eq!(&base.clone().pow(3i8), &expected_res);
2166 assert_eq!(&base.clone().pow(3i16), &expected_res);
2167 assert_eq!(&base.clone().pow(3i32), &expected_res);
2168 assert_eq!(&base.clone().pow(3i64), &expected_res);
2169 assert_eq!(&base.clone().pow(3i128), &expected_res);
2170 assert_eq!(&base.clone().pow(3isize), &expected_res);
2171 }
2172
2173 #[test]
2174 fn complex_zero_base_negative_real_exponent_error() {
2175 let base = ComplexRugStrictFinite::<PRECISION>::zero();
2176 let exponent = RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap();
2177 let res = base.try_pow(&exponent);
2178 assert!(matches!(
2179 res,
2180 Err(PowComplexBaseRealExponentErrors::Input {
2181 source:
2182 PowComplexBaseRealExponentInputErrors::ZeroBaseNegativeExponent { .. }
2183 })
2184 ));
2185 }
2186
2187 #[test]
2188 fn complex_zero_base_zero_real_exponent() {
2189 let base = ComplexRugStrictFinite::<PRECISION>::zero();
2190 let exponent = RealRugStrictFinite::<PRECISION>::zero();
2191 let res = base.try_pow(&exponent).unwrap();
2192 assert_eq!(res, ComplexRugStrictFinite::<PRECISION>::one());
2193 }
2194
2195 #[test]
2196 fn complex_base_int_exponent_zero_neg_exp_error() {
2197 let base = ComplexRugStrictFinite::<PRECISION>::zero();
2198 let exponent: i32 = -2;
2199 let res = base.try_pow(exponent);
2200 assert!(matches!(
2201 res,
2202 Err(PowIntExponentErrors::Input {
2203 source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
2204 })
2205 ));
2206 }
2207 }
2208 }
2209
2210 #[test]
2211 fn reciprocal_real_rug_zero() {
2212 let zero_val = RealRugStrictFinite::<PRECISION>::zero();
2213 let res = zero_val.try_reciprocal();
2214 assert!(matches!(
2215 res,
2216 Err(ReciprocalErrors::Input {
2217 source: ReciprocalInputErrors::DivisionByZero { .. }
2218 })
2219 ));
2220 }
2221
2222 #[test]
2223 fn reciprocal_complex_rug_zero() {
2224 let zero_val = ComplexRugStrictFinite::<PRECISION>::zero();
2225 let res = zero_val.try_reciprocal();
2226 assert!(matches!(
2227 res,
2228 Err(ReciprocalErrors::Input {
2229 source: ReciprocalInputErrors::DivisionByZero { .. }
2230 })
2231 ));
2232 }
2233
2234 #[test]
2235 fn sqrt_real_rug_negative_input() {
2236 let neg_val = RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap();
2237 let res = neg_val.try_sqrt();
2238 assert!(matches!(
2239 res,
2240 Err(SqrtRealErrors::Input {
2241 source: SqrtRealInputErrors::NegativeValue { .. }
2242 })
2243 ));
2244 }
2245
2246 mod trigonometric {
2247 use super::*;
2248
2249 #[test]
2250 fn atan2_real_rug_zero_over_zero() {
2251 let zero_val = RealRugStrictFinite::<PRECISION>::zero();
2252 let res = zero_val.try_atan2(&RealRugStrictFinite::<PRECISION>::zero());
2253 assert!(matches!(
2254 res,
2255 Err(ATan2Errors::Input {
2256 source: ATan2InputErrors::ZeroOverZero { .. }
2257 })
2258 ));
2259 }
2260
2261 #[test]
2279 fn asin_real_rug_out_of_domain() {
2280 let val_gt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.5).unwrap();
2281 assert!(matches!(
2282 val_gt_1.try_asin(),
2283 Err(ASinRealErrors::Input {
2284 source: ASinRealInputErrors::OutOfDomain { .. }
2285 })
2286 ));
2287 let val_lt_neg1 = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.5).unwrap();
2288 assert!(matches!(
2289 val_lt_neg1.try_asin(),
2290 Err(ASinRealErrors::Input {
2291 source: ASinRealInputErrors::OutOfDomain { .. }
2292 })
2293 ));
2294 }
2295
2296 #[test]
2297 fn acos_real_rug_out_of_domain() {
2298 let val_gt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.5).unwrap();
2299 assert!(matches!(
2300 val_gt_1.try_acos(),
2301 Err(ACosRealErrors::Input {
2302 source: ACosRealInputErrors::OutOfDomain { .. }
2303 })
2304 ));
2305 let val_lt_neg1 = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.5).unwrap();
2306 assert!(matches!(
2307 val_lt_neg1.try_acos(),
2308 Err(ACosRealErrors::Input {
2309 source: ACosRealInputErrors::OutOfDomain { .. }
2310 })
2311 ));
2312 }
2313
2314 #[test]
2315 fn atan_complex_rug_pole() {
2316 let i_val = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
2318 Float::with_val(PRECISION, 1.0),
2319 )
2320 .unwrap();
2321 assert!(matches!(
2322 i_val.try_atan(),
2323 Err(ATanComplexErrors::Input {
2324 source: ATanComplexInputErrors::ArgumentIsPole { .. }
2325 })
2326 ));
2327
2328 let neg_i_val = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
2329 Float::with_val(PRECISION, -1.0),
2330 )
2331 .unwrap();
2332 assert!(matches!(
2333 neg_i_val.try_atan(),
2334 Err(ATanComplexErrors::Input {
2335 source: ATanComplexInputErrors::ArgumentIsPole { .. }
2336 })
2337 ));
2338 }
2339 } mod hyperbolic {
2342 use super::*;
2343
2344 mod real {
2345 use super::*;
2346
2347 #[test]
2348 fn atanh_real_rug_out_of_domain() {
2349 let val_ge_1 = RealRugStrictFinite::<PRECISION>::one(); assert!(matches!(
2351 val_ge_1.try_atanh(),
2352 Err(ATanHErrors::Input {
2353 source: ATanHInputErrors::OutOfDomain { .. }
2354 })
2355 ));
2356
2357 let val_le_neg1 = RealRugStrictFinite::<PRECISION>::negative_one(); assert!(matches!(
2359 val_le_neg1.try_atanh(),
2360 Err(ATanHErrors::Input {
2361 source: ATanHInputErrors::OutOfDomain { .. }
2362 })
2363 ));
2364 }
2365
2366 #[test]
2367 fn acosh_real_rug_out_of_domain() {
2368 let val_lt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
2369 assert!(matches!(
2370 val_lt_1.try_acosh(),
2371 Err(ACosHErrors::Input {
2372 source: ACosHInputErrors::OutOfDomain { .. }
2373 })
2374 ));
2375 }
2376 }
2377
2378 mod complex {
2379 use super::*;
2380
2381 #[test]
2400 fn acosh_out_of_domain() {
2401 let val_on_branch_cut = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2403 Float::with_val(PRECISION, 0.5),
2404 )
2405 .unwrap();
2406 assert!(matches!(
2407 val_on_branch_cut.try_acosh(),
2408 Err(ACosHErrors::Input {
2409 source: ACosHInputErrors::OutOfDomain { .. }
2410 })
2411 ));
2412
2413 let val_on_branch_cut_neg =
2414 ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(Float::with_val(
2415 PRECISION, -5.0,
2416 ))
2417 .unwrap();
2418 assert!(matches!(
2419 val_on_branch_cut_neg.try_acosh(),
2420 Err(ACosHErrors::Input {
2421 source: ACosHInputErrors::OutOfDomain { .. }
2422 })
2423 ));
2424 }
2425
2426 #[test]
2427 fn atanh_out_of_domain() {
2428 let val_ge_1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2429 Float::with_val(PRECISION, 1.0),
2430 )
2431 .unwrap();
2432 assert!(matches!(
2433 val_ge_1.try_atanh(),
2434 Err(ATanHErrors::Input {
2435 source: ATanHInputErrors::OutOfDomain { .. }
2436 })
2437 ));
2438
2439 let val_le_neg1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2440 Float::with_val(PRECISION, -1.0),
2441 )
2442 .unwrap();
2443 assert!(matches!(
2444 val_le_neg1.try_atanh(),
2445 Err(ATanHErrors::Input {
2446 source: ATanHInputErrors::OutOfDomain { .. }
2447 })
2448 ));
2449 }
2450 }
2451
2452 } }
2470
2471 mod summation {
2472 use super::*;
2473
2474 const PRECISION: u32 = 53;
2475
2476 type RealValidated = RealRugStrictFinite<PRECISION>;
2477 type ComplexValidated = ComplexRugStrictFinite<PRECISION>;
2478
2479 #[test]
2480 fn sum_real() {
2481 let values = vec![
2482 RealValidated::try_from_f64(1.0).unwrap(),
2483 RealValidated::try_from_f64(2.0).unwrap(),
2484 RealValidated::try_from_f64(3.0).unwrap(),
2485 RealValidated::try_from_f64(4.0).unwrap(),
2486 RealValidated::try_from_f64(5.0).unwrap(),
2487 ];
2488 let sum: RealValidated = values.into_iter().sum();
2489 assert_eq!(sum, RealValidated::try_from_f64(15.0).unwrap());
2490 }
2491
2492 #[test]
2493 fn sum_real_compensated() {
2494 let values = vec![
2496 RealValidated::try_from_f64(1.0e100).unwrap(),
2497 RealValidated::try_from_f64(1.0).unwrap(),
2498 RealValidated::try_from_f64(-1.0e100).unwrap(),
2499 ];
2500 let sum: RealValidated = values.into_iter().sum();
2501 assert_eq!(sum, RealValidated::try_from_f64(1.0).unwrap());
2503 }
2504
2505 #[test]
2506 fn sum_complex() {
2507 let values = vec![
2508 ComplexValidated::try_new_complex(
2509 rug::Float::with_val(PRECISION, 1.),
2510 rug::Float::with_val(PRECISION, 2.),
2511 )
2512 .unwrap(),
2513 ComplexValidated::try_new_complex(
2514 rug::Float::with_val(PRECISION, 3.),
2515 rug::Float::with_val(PRECISION, 4.),
2516 )
2517 .unwrap(),
2518 ComplexValidated::try_new_complex(
2519 rug::Float::with_val(PRECISION, 5.),
2520 rug::Float::with_val(PRECISION, 6.),
2521 )
2522 .unwrap(),
2523 ];
2524 let sum: ComplexValidated = values.into_iter().sum();
2525 assert_eq!(
2526 sum,
2527 ComplexValidated::try_new_complex(
2528 rug::Float::with_val(PRECISION, 9.),
2529 rug::Float::with_val(PRECISION, 12.)
2530 )
2531 .unwrap()
2532 );
2533 }
2534
2535 #[test]
2536 fn sum_complex_compensated() {
2537 let values = [
2538 ComplexValidated::try_new_complex(
2539 rug::Float::with_val(PRECISION, 1.0e100),
2540 rug::Float::with_val(PRECISION, -1.0e100),
2541 )
2542 .unwrap(),
2543 ComplexValidated::try_new_complex(
2544 rug::Float::with_val(PRECISION, 1.),
2545 rug::Float::with_val(PRECISION, 2.),
2546 )
2547 .unwrap(),
2548 ComplexValidated::try_new_complex(
2549 rug::Float::with_val(PRECISION, -1.0e100),
2550 rug::Float::with_val(PRECISION, 1.0e100),
2551 )
2552 .unwrap(),
2553 ];
2554 let sum: ComplexValidated = values.iter().cloned().sum();
2555 assert_eq!(
2556 sum,
2557 ComplexValidated::try_new_complex(
2558 rug::Float::with_val(PRECISION, 1.),
2559 rug::Float::with_val(PRECISION, 2.)
2560 )
2561 .unwrap()
2562 );
2563 }
2564 } mod random {
2567 use super::*;
2568 use crate::{RandomSampleFromF64, new_random_vec};
2569 use rand::{Rng, SeedableRng, distr::Uniform, rngs::StdRng};
2570
2571 const PRECISION: u32 = 53;
2572
2573 type RealValidated = RealRugStrictFinite<PRECISION>;
2574 type ComplexValidated = ComplexRugStrictFinite<PRECISION>;
2575
2576 #[test]
2580 fn test_random_real_validated() {
2581 let seed = [42; 32];
2582 let mut rng = StdRng::from_seed(seed);
2583
2584 let random_real: RealValidated = rng.random();
2585
2586 assert_eq!(random_real, 0.23713468825474326);
2588
2589 let mut rng2 = StdRng::from_seed(seed);
2591 let random_real2: RealValidated = rng2.random();
2592 assert_eq!(random_real, random_real2);
2593 }
2594
2595 #[test]
2600 fn test_random_complex_validated() {
2601 let seed = [99; 32];
2602 let mut rng = StdRng::from_seed(seed);
2603
2604 let random_complex: ComplexValidated = rng.random();
2605
2606 let real_part = random_complex.real_part();
2609 let imag_part = random_complex.imag_part();
2610
2611 assert_eq!(real_part, 0.9995546882627792);
2612 assert_eq!(imag_part, 0.08932180682540247);
2613
2614 let mut rng2 = StdRng::from_seed(seed);
2616 let random_complex2: ComplexValidated = rng2.random();
2617 assert_eq!(random_complex, random_complex2);
2618 }
2619
2620 const SEED: [u8; 32] = [42; 32];
2621
2622 #[test]
2623 fn test_sample_real_validated() {
2624 let mut rng = StdRng::from_seed(SEED);
2625 let dist = Uniform::new(-10.0, 10.0).unwrap();
2626
2627 let val = RealValidated::sample_from(&dist, &mut rng);
2628 assert_eq!(val, -5.257306234905137);
2629
2630 let mut rng2 = StdRng::from_seed(SEED);
2632 let val2 = RealValidated::sample_from(&dist, &mut rng2);
2633 assert_eq!(val, val2);
2634 }
2635
2636 #[test]
2637 fn test_sample_complex_validated() {
2638 let mut rng = StdRng::from_seed(SEED);
2639 let dist = Uniform::new(-10.0, 10.0).unwrap();
2640
2641 let val = ComplexValidated::sample_from(&dist, &mut rng);
2642 assert_eq!(val.real_part(), -5.257306234905137);
2643 assert_eq!(val.imag_part(), 7.212119776268775);
2644
2645 let mut rng2 = StdRng::from_seed(SEED);
2647 let val2 = ComplexValidated::sample_from(&dist, &mut rng2);
2648 assert_eq!(val, val2);
2649 }
2650
2651 #[test]
2652 fn new_random_vec_real() {
2653 let mut rng = StdRng::from_seed(SEED);
2654 let dist = Uniform::new(-10.0, 10.0).unwrap();
2655 let vec: Vec<RealValidated> = new_random_vec(3, &dist, &mut rng);
2656 assert_eq!(vec.len(), 3);
2657 assert_eq!(vec[0], -5.257306234905137);
2658 assert_eq!(vec[1], 7.212119776268775);
2659 assert_eq!(vec[2], -4.666248990558111);
2660
2661 let mut rng2 = StdRng::from_seed(SEED);
2663 let vec2: Vec<RealValidated> = new_random_vec(3, &dist, &mut rng2);
2664 assert_eq!(vec, vec2);
2665 }
2666
2667 #[test]
2668 fn new_random_vec_complex() {
2669 let mut rng = StdRng::from_seed(SEED);
2670 let dist = Uniform::new(-10.0, 10.0).unwrap();
2671 let vec: Vec<ComplexValidated> = new_random_vec(3, &dist, &mut rng);
2672 assert_eq!(vec.len(), 3);
2673 assert_eq!(vec[0].real_part(), -5.257306234905137);
2674 assert_eq!(vec[0].imag_part(), 7.212119776268775);
2675 assert_eq!(vec[1].real_part(), -4.666248990558111);
2676 assert_eq!(vec[1].imag_part(), 9.66047141517383);
2677 assert_eq!(vec[2].real_part(), -9.04279551029691);
2678 assert_eq!(vec[2].imag_part(), -1.026624649331671);
2679
2680 let mut rng2 = StdRng::from_seed(SEED);
2682 let vec2: Vec<ComplexValidated> = new_random_vec(3, &dist, &mut rng2);
2683 assert_eq!(vec, vec2);
2684 }
2685 }
2686
2687 mod hash_map_key_usage {
2688 use crate::kernels::rug::RealRugStrictFinite;
2689 use rug::Float;
2690 use std::collections::HashMap;
2691 use try_create::TryNew;
2692
2693 const PRECISION: u32 = 128;
2694 type RealRugValidated = RealRugStrictFinite<PRECISION>;
2695
2696 #[test]
2697 fn test_rug_as_hashmap_key() {
2698 let mut map = HashMap::new();
2699 let key1 = RealRugValidated::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
2700 let key2 = RealRugValidated::try_new(Float::with_val(PRECISION, 2.5)).unwrap();
2701
2702 map.insert(key1.clone(), "one_rug");
2703 map.insert(key2.clone(), "two_point_five_rug");
2704
2705 assert_eq!(map.get(&key1), Some(&"one_rug"));
2706 assert_eq!(map.len(), 2);
2707
2708 let old_value = map.insert(key1.clone(), "new_one_rug");
2710 assert_eq!(old_value, Some("one_rug"));
2711 assert_eq!(map.get(&key1), Some(&"new_one_rug"));
2712 }
2713
2714 #[test]
2715 fn test_hash_signed_zero() {
2716 use crate::functions::Sign;
2717 use std::collections::hash_map::DefaultHasher;
2718 use std::hash::{Hash, Hasher};
2719
2720 let val1 = RealRugValidated::try_new(Float::with_val(PRECISION, 0.0)).unwrap();
2721 assert!(val1.kernel_is_sign_positive());
2722 let val2 = RealRugValidated::try_new(Float::with_val(PRECISION, -0.0)).unwrap();
2723 assert!(val2.kernel_is_sign_negative());
2724
2725 let mut hasher1 = DefaultHasher::new();
2727 let mut hasher2 = DefaultHasher::new();
2728
2729 val1.hash(&mut hasher1);
2730 val2.hash(&mut hasher2);
2731
2732 assert_eq!(hasher1.finish(), hasher2.finish());
2733 assert_eq!(val1, val2); }
2735
2736 #[test]
2737 fn test_complex_as_hashmap_key() {
2738 use crate::ComplexRugStrictFinite;
2739 type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2740
2741 let mut map = HashMap::new();
2742 let key1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
2743 .unwrap();
2744 let key2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (3.0, 4.0)))
2745 .unwrap();
2746
2747 map.insert(key1.clone(), "one_plus_two_i_rug");
2748 map.insert(key2.clone(), "three_plus_four_i_rug");
2749
2750 assert_eq!(map.get(&key1), Some(&"one_plus_two_i_rug"));
2751 assert_eq!(map.len(), 2);
2752
2753 let old_value = map.insert(key1.clone(), "updated_complex_rug");
2755 assert_eq!(old_value, Some("one_plus_two_i_rug"));
2756 assert_eq!(map.get(&key1), Some(&"updated_complex_rug"));
2757 }
2758
2759 #[test]
2760 fn test_complex_hash_consistency() {
2761 use crate::ComplexRugStrictFinite;
2762 use std::collections::hash_map::DefaultHasher;
2763 use std::hash::{Hash, Hasher};
2764 type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2765
2766 let val1 =
2767 ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.234, 5.678)))
2768 .unwrap();
2769 let val2 =
2770 ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.234, 5.678)))
2771 .unwrap();
2772
2773 let mut hasher1 = DefaultHasher::new();
2775 let mut hasher2 = DefaultHasher::new();
2776
2777 val1.hash(&mut hasher1);
2778 val2.hash(&mut hasher2);
2779
2780 assert_eq!(hasher1.finish(), hasher2.finish());
2781 assert_eq!(val1, val2);
2782 }
2783
2784 #[test]
2785 fn test_complex_hash_signed_zero() {
2786 use crate::ComplexRugStrictFinite;
2787 use std::collections::hash_map::DefaultHasher;
2788 use std::hash::{Hash, Hasher};
2789 type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2790
2791 let val1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (0.0, 0.0)))
2793 .unwrap();
2794 let val2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (-0.0, 0.0)))
2795 .unwrap();
2796 let val3 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (0.0, -0.0)))
2797 .unwrap();
2798 let val4 =
2799 ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (-0.0, -0.0)))
2800 .unwrap();
2801
2802 assert_eq!(val1, val2);
2804 assert_eq!(val1, val3);
2805 assert_eq!(val1, val4);
2806
2807 let mut hasher1 = DefaultHasher::new();
2809 let mut hasher2 = DefaultHasher::new();
2810 let mut hasher3 = DefaultHasher::new();
2811 let mut hasher4 = DefaultHasher::new();
2812
2813 val1.hash(&mut hasher1);
2814 val2.hash(&mut hasher2);
2815 val3.hash(&mut hasher3);
2816 val4.hash(&mut hasher4);
2817
2818 let hash1 = hasher1.finish();
2819 let hash2 = hasher2.finish();
2820 let hash3 = hasher3.finish();
2821 let hash4 = hasher4.finish();
2822
2823 assert_eq!(hash1, hash2);
2824 assert_eq!(hash1, hash3);
2825 assert_eq!(hash1, hash4);
2826 }
2827
2828 #[test]
2829 fn test_complex_hashset_operations() {
2830 use crate::ComplexRugStrictFinite;
2831 use std::collections::HashSet;
2832 type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2833
2834 let mut set = HashSet::new();
2835
2836 let val1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
2837 .unwrap();
2838 let val2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (3.0, 4.0)))
2839 .unwrap();
2840 let val1_duplicate =
2841 ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
2842 .unwrap();
2843
2844 assert!(set.insert(val1.clone()));
2845 assert!(set.insert(val2.clone()));
2846 assert!(!set.insert(val1_duplicate)); assert_eq!(set.len(), 2);
2849 assert!(set.contains(&val1));
2850 }
2851
2852 #[test]
2853 fn test_complex_different_precision_different_hash() {
2854 use crate::ComplexRugStrictFinite;
2855 use std::collections::hash_map::DefaultHasher;
2856 use std::hash::{Hash, Hasher};
2857
2858 const PRECISION_A: u32 = 64;
2859 const PRECISION_B: u32 = 128;
2860
2861 let val1 = ComplexRugStrictFinite::<PRECISION_A>::try_new(rug::Complex::with_val(
2862 PRECISION_A,
2863 (1.0, 2.0),
2864 ))
2865 .unwrap();
2866 let val2 = ComplexRugStrictFinite::<PRECISION_B>::try_new(rug::Complex::with_val(
2867 PRECISION_B,
2868 (1.0, 2.0),
2869 ))
2870 .unwrap();
2871
2872 let mut hasher1 = DefaultHasher::new();
2874 let mut hasher2 = DefaultHasher::new();
2875
2876 val1.hash(&mut hasher1);
2877 val2.hash(&mut hasher2);
2878
2879 let hash1 = hasher1.finish();
2880 let hash2 = hasher2.finish();
2881
2882 assert_ne!(hash1, hash2);
2884 }
2885 }
2886
2887 mod rug_float {
2888
2889 mod from_f64 {
2890 use crate::{RealRugStrictFinite, RealScalar};
2891
2892 const PRECISION: u32 = 100;
2893
2894 #[test]
2895 fn test_from_f64_valid_constants() {
2896 let pi = RealRugStrictFinite::<PRECISION>::from_f64(std::f64::consts::PI);
2898 let pi_f64 = pi.as_ref().to_f64();
2899 assert!((pi_f64 - std::f64::consts::PI).abs() < 1e-15);
2900
2901 let e = RealRugStrictFinite::<PRECISION>::from_f64(std::f64::consts::E);
2902 let e_f64 = e.as_ref().to_f64();
2903 assert!((e_f64 - std::f64::consts::E).abs() < 1e-15);
2904 }
2905
2906 #[test]
2907 fn test_from_f64_valid_simple_values() {
2908 let x = RealRugStrictFinite::<PRECISION>::from_f64(42.0);
2910 assert_eq!(x.as_ref().to_f64(), 42.0);
2911
2912 let y = RealRugStrictFinite::<PRECISION>::from_f64(-3.0);
2913 assert_eq!(y.as_ref().to_f64(), -3.0);
2914
2915 let z = RealRugStrictFinite::<PRECISION>::from_f64(0.0);
2916 assert_eq!(z.as_ref().to_f64(), 0.0);
2917 }
2918
2919 #[test]
2920 #[should_panic(expected = "RealScalar::from_f64() failed")]
2921 fn test_from_f64_nan_panics() {
2922 let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::NAN);
2923 }
2924
2925 #[test]
2926 #[should_panic(expected = "RealScalar::from_f64() failed")]
2927 fn test_from_f64_infinity_panics() {
2928 let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::INFINITY);
2929 }
2930
2931 #[test]
2932 #[should_panic(expected = "RealScalar::from_f64() failed")]
2933 fn test_from_f64_neg_infinity_panics() {
2934 let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::NEG_INFINITY);
2935 }
2936
2937 #[test]
2938 fn test_try_from_f64_exact_representation() {
2939 let result = RealRugStrictFinite::<PRECISION>::try_from_f64(0.1);
2942 assert!(result.is_ok());
2943
2944 assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(2.5).is_ok());
2946 assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).is_ok());
2947
2948 assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(f64::NAN).is_err());
2950 assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(f64::INFINITY).is_err());
2951 }
2952 }
2953
2954 mod truncate_to_usize {
2955 use crate::kernels::RawRealTrait;
2956 use crate::validation::ErrorsRawRealToInteger;
2957 use rug::Float;
2958
2959 const PRECISION: u32 = 128;
2960
2961 #[test]
2962 fn test_rug_truncate_to_usize_valid() {
2963 assert_eq!(
2964 Float::with_val(PRECISION, 42.0)
2965 .truncate_to_usize()
2966 .unwrap(),
2967 42
2968 );
2969 assert_eq!(
2970 Float::with_val(PRECISION, 42.9)
2971 .truncate_to_usize()
2972 .unwrap(),
2973 42
2974 );
2975 assert_eq!(
2976 Float::with_val(PRECISION, 0.0).truncate_to_usize().unwrap(),
2977 0
2978 );
2979 assert_eq!(
2980 Float::with_val(PRECISION, usize::MAX)
2981 .truncate_to_usize()
2982 .unwrap(),
2983 usize::MAX
2984 );
2985 }
2986
2987 #[test]
2988 fn test_rug_truncate_to_usize_not_finite() {
2989 assert!(matches!(
2990 Float::with_val(PRECISION, f64::NAN).truncate_to_usize(),
2991 Err(ErrorsRawRealToInteger::NotFinite { .. })
2992 ));
2993 assert!(matches!(
2994 Float::with_val(PRECISION, f64::INFINITY).truncate_to_usize(),
2995 Err(ErrorsRawRealToInteger::NotFinite { .. })
2996 ));
2997 assert!(matches!(
2998 Float::with_val(PRECISION, f64::NEG_INFINITY).truncate_to_usize(),
2999 Err(ErrorsRawRealToInteger::NotFinite { .. })
3000 ));
3001 }
3002
3003 #[test]
3004 fn test_rug_truncate_to_usize_out_of_range() {
3005 assert!(matches!(
3007 Float::with_val(PRECISION, -1.0).truncate_to_usize(),
3008 Err(ErrorsRawRealToInteger::OutOfRange { .. })
3009 ));
3010
3011 let mut too_large = Float::with_val(PRECISION, usize::MAX);
3013 too_large += 1;
3014 assert!(matches!(
3015 too_large.truncate_to_usize(),
3016 Err(ErrorsRawRealToInteger::OutOfRange { .. })
3017 ));
3018 }
3019 }
3020 }
3021
3022 mod truncate_to_usize {
3023 use super::*;
3024 use crate::kernels::rug::RealRugStrictFinite;
3025 use rug::Float;
3026 use try_create::TryNew;
3027
3028 const PRECISION: u32 = 1000;
3029
3030 #[test]
3031 fn test_positive_integers() {
3032 let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 42.0))
3033 .unwrap();
3034 assert_eq!(value.truncate_to_usize().unwrap(), 42);
3035
3036 let value =
3037 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
3038 assert_eq!(value.truncate_to_usize().unwrap(), 1);
3039 }
3040
3041 #[test]
3042 fn test_positive_fractionals_truncate() {
3043 let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 42.9))
3044 .unwrap();
3045 assert_eq!(value.truncate_to_usize().unwrap(), 42);
3046
3047 let value =
3048 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.9)).unwrap();
3049 assert_eq!(value.truncate_to_usize().unwrap(), 0);
3050 }
3051
3052 #[test]
3053 fn test_zero_cases() {
3054 let value =
3055 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.0)).unwrap();
3056 assert_eq!(value.truncate_to_usize().unwrap(), 0);
3057 }
3058
3059 #[test]
3060 fn test_negative_values_error() {
3061 let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
3062 .unwrap();
3063 let result = value.truncate_to_usize();
3064 assert!(matches!(
3065 result,
3066 Err(ErrorsRawRealToInteger::OutOfRange { .. })
3067 ));
3068
3069 let value =
3070 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -10.5))
3071 .unwrap();
3072 let result = value.truncate_to_usize();
3073 assert!(matches!(
3074 result,
3075 Err(ErrorsRawRealToInteger::OutOfRange { .. })
3076 ));
3077 }
3078
3079 #[test]
3080 fn test_large_values() {
3081 let value =
3083 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1_000_000.0))
3084 .unwrap();
3085 assert_eq!(value.truncate_to_usize().unwrap(), 1_000_000);
3086
3087 let value = RealRugStrictFinite::<PRECISION>::try_new(
3089 Float::with_val(PRECISION, 1e50), )
3091 .unwrap();
3092 let result = value.truncate_to_usize();
3093 assert!(matches!(
3094 result,
3095 Err(ErrorsRawRealToInteger::OutOfRange { .. })
3096 ));
3097 }
3098
3099 #[test]
3100 fn test_high_precision_truncation() {
3101 let value = RealRugStrictFinite::<PRECISION>::try_new(
3103 Float::parse("42.99999999999999999999999999999")
3104 .unwrap()
3105 .complete(PRECISION),
3106 )
3107 .unwrap();
3108 assert_eq!(value.truncate_to_usize().unwrap(), 42);
3109
3110 let value = RealRugStrictFinite::<PRECISION>::try_new(
3112 Float::parse("0.99999999999999999999999999999")
3113 .unwrap()
3114 .complete(PRECISION),
3115 )
3116 .unwrap();
3117 assert_eq!(value.truncate_to_usize().unwrap(), 0);
3118 }
3119
3120 #[test]
3121 fn test_conversion_from_f64() {
3122 let value = RealRugStrictFinite::<PRECISION>::try_from_f64(42.7).unwrap();
3124 assert_eq!(value.truncate_to_usize().unwrap(), 42);
3125
3126 let value = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
3127 assert_eq!(value.truncate_to_usize().unwrap(), 0);
3128 }
3129 }
3130}