1#![deny(rustdoc::broken_intra_doc_links)]
2
3use crate::{
53 ComplexScalarGetParts, Constants, RealScalar,
54 core::errors::{ErrorsTryFromf64, ErrorsValidationRawComplex},
55 kernels::{ComplexValidated, NumKernelStrictFinite, RealValidated},
56 scalars::AbsoluteTolerance,
57};
58use num::Complex;
59use rug::ops::CompleteRound;
60use std::marker::PhantomData;
61use try_create::{IntoInner, TryNew};
62
63pub type RugStrictFinite<const PRECISION: u32> = NumKernelStrictFinite<rug::Float, PRECISION>;
117pub type RealRugStrictFinite<const PRECISION: u32> = RealValidated<RugStrictFinite<PRECISION>>;
122
123pub type ComplexRugStrictFinite<const PRECISION: u32> =
125 ComplexValidated<RugStrictFinite<PRECISION>>;
126
127impl<const PRECISION: u32> TryFrom<Complex<f64>> for ComplexRugStrictFinite<PRECISION> {
131 type Error = ErrorsValidationRawComplex<ErrorsTryFromf64<rug::Float>>;
132
133 fn try_from(value: Complex<f64>) -> Result<Self, Self::Error> {
134 let real_part = RealRugStrictFinite::<PRECISION>::try_from_f64(value.re);
135 let imag_part = RealRugStrictFinite::<PRECISION>::try_from_f64(value.im);
136
137 match (real_part, imag_part) {
138 (Ok(real_part), Ok(imag_part)) => Ok(Self {
139 value: rug::Complex::with_val(
140 PRECISION,
141 (real_part.into_inner(), imag_part.into_inner()),
142 ),
143 _phantom: PhantomData,
144 }),
145 (Err(error_real_part), Ok(_)) => Err(ErrorsValidationRawComplex::InvalidRealPart {
146 source: error_real_part,
147 }),
148 (Ok(_), Err(error_imaginary_part)) => {
149 Err(ErrorsValidationRawComplex::InvalidImaginaryPart {
150 source: error_imaginary_part,
151 })
152 }
153 (Err(error_real_part), Err(error_imaginary_part)) => {
154 Err(ErrorsValidationRawComplex::InvalidBothParts {
155 real_error: error_real_part,
156 imag_error: error_imaginary_part,
157 })
158 }
159 }
160 }
161}
162impl<const PRECISION: u32> approx::AbsDiffEq for RealRugStrictFinite<PRECISION> {
180 type Epsilon = AbsoluteTolerance<Self>;
181
182 #[inline]
187 fn default_epsilon() -> Self::Epsilon {
188 AbsoluteTolerance::epsilon()
189 }
190
191 #[inline]
195 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
196 let diff = (self.as_ref() - other.as_ref()).complete(PRECISION);
197 diff.abs() <= *epsilon.as_ref().as_ref()
198 }
199}
200
201impl<const PRECISION: u32> approx::RelativeEq for RealRugStrictFinite<PRECISION> {
202 #[inline]
206 fn default_max_relative() -> Self::Epsilon {
207 let eps = Self::epsilon();
208 let eight = rug::Float::with_val(PRECISION, 8);
210 let scaled = Self::try_new(eps.into_inner() * eight)
211 .expect("default_max_relative: validation failed unexpectedly");
212 AbsoluteTolerance::try_new(scaled)
213 .expect("default_max_relative: AbsoluteTolerance validation failed")
214 }
215
216 #[inline]
220 fn relative_eq(
221 &self,
222 other: &Self,
223 epsilon: Self::Epsilon,
224 max_relative: Self::Epsilon,
225 ) -> bool {
226 let diff = (self.as_ref() - other.as_ref()).complete(PRECISION).abs();
227
228 if diff <= *epsilon.as_ref().as_ref() {
229 return true;
230 }
231
232 let abs_self = self.as_ref().clone().abs();
233 let abs_other = other.as_ref().clone().abs();
234 let largest = if abs_self > abs_other {
235 abs_self
236 } else {
237 abs_other
238 };
239
240 diff <= (max_relative.as_ref().as_ref() * &largest).complete(PRECISION)
241 }
242}
243
244impl<const PRECISION: u32> approx::AbsDiffEq for ComplexRugStrictFinite<PRECISION> {
245 type Epsilon = AbsoluteTolerance<RealRugStrictFinite<PRECISION>>;
246
247 #[inline]
249 fn default_epsilon() -> Self::Epsilon {
250 AbsoluteTolerance::epsilon()
251 }
252
253 #[inline]
257 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
258 let real_diff = (self.raw_real_part() - other.raw_real_part()).complete(PRECISION);
259 let imag_diff = (self.raw_imag_part() - other.raw_imag_part()).complete(PRECISION);
260 let eps = epsilon.as_ref().as_ref();
261
262 real_diff.abs() <= *eps && imag_diff.abs() <= *eps
263 }
264}
265
266impl<const PRECISION: u32> approx::RelativeEq for ComplexRugStrictFinite<PRECISION> {
267 #[inline]
269 fn default_max_relative() -> Self::Epsilon {
270 RealRugStrictFinite::<PRECISION>::default_max_relative()
271 }
272
273 #[inline]
277 fn relative_eq(
278 &self,
279 other: &Self,
280 epsilon: Self::Epsilon,
281 max_relative: Self::Epsilon,
282 ) -> bool {
283 let real_self = self.real_part();
285 let real_other = other.real_part();
286 if !real_self.relative_eq(&real_other, epsilon.clone(), max_relative.clone()) {
287 return false;
288 }
289
290 let imag_self = self.imag_part();
292 let imag_other = other.imag_part();
293 imag_self.relative_eq(&imag_other, epsilon, max_relative)
294 }
295}
296#[cfg(test)]
299mod approx_tests {
300 use super::*;
301 use crate::scalars::AbsoluteTolerance;
302 use approx::{AbsDiffEq, assert_abs_diff_eq, assert_abs_diff_ne, assert_relative_eq};
303 use rug::Float;
304 use try_create::TryNew;
305
306 const PRECISION: u32 = 100;
307
308 mod real_rug {
309 use super::*;
310
311 #[test]
312 fn abs_diff_eq_equal_values() {
313 let a =
314 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
315 let b =
316 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
317 assert_abs_diff_eq!(a, b);
318 }
319
320 #[test]
321 fn abs_diff_eq_close_values() {
322 let a =
323 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
324 let mut b_val = Float::with_val(PRECISION, 1.0);
326 b_val += Float::with_val(PRECISION, 1e-25);
327 let b = RealRugStrictFinite::<PRECISION>::try_new(b_val).unwrap();
328
329 let eps_val =
331 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1e-20))
332 .unwrap();
333 let eps = AbsoluteTolerance::try_new(eps_val).unwrap();
334 assert_abs_diff_eq!(a, b, epsilon = eps);
335 }
336
337 #[test]
338 fn abs_diff_ne_different_values() {
339 let a =
340 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
341 let b =
342 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 2.0)).unwrap();
343 assert_abs_diff_ne!(a, b);
344 }
345
346 #[test]
347 fn default_epsilon_is_machine_epsilon() {
348 let eps = RealRugStrictFinite::<PRECISION>::default_epsilon();
349 let expected =
351 AbsoluteTolerance::try_new(RealRugStrictFinite::<PRECISION>::epsilon()).unwrap();
352 assert_eq!(*eps.as_ref(), *expected.as_ref());
353 }
354
355 #[test]
356 fn relative_eq_close_values() {
357 let a = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 100.0))
358 .unwrap();
359 let eps = RealRugStrictFinite::<PRECISION>::epsilon();
361 let mut b_val = Float::with_val(PRECISION, 100.0);
362 b_val += eps.as_ref();
364 let b = RealRugStrictFinite::<PRECISION>::try_new(b_val).unwrap();
365 assert_relative_eq!(a, b);
366 }
367
368 #[test]
369 fn relative_eq_with_custom_tolerance() {
370 let a =
371 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
372 let b = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.001))
373 .unwrap();
374 let max_rel_val =
375 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.01))
376 .unwrap();
377 let max_rel = AbsoluteTolerance::try_new(max_rel_val).unwrap();
378 let eps = RealRugStrictFinite::<PRECISION>::default_epsilon();
379 assert_relative_eq!(a, b, epsilon = eps, max_relative = max_rel);
380 }
381 }
382
383 mod complex_rug {
384 use super::*;
385
386 #[test]
387 fn abs_diff_eq_equal_values() {
388 let a = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
389 PRECISION,
390 (
391 Float::with_val(PRECISION, 1.0),
392 Float::with_val(PRECISION, 2.0),
393 ),
394 ))
395 .unwrap();
396 let b = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
397 PRECISION,
398 (
399 Float::with_val(PRECISION, 1.0),
400 Float::with_val(PRECISION, 2.0),
401 ),
402 ))
403 .unwrap();
404 assert_abs_diff_eq!(a, b);
405 }
406
407 #[test]
408 fn abs_diff_eq_close_values() {
409 let a = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
410 PRECISION,
411 (
412 Float::with_val(PRECISION, 1.0),
413 Float::with_val(PRECISION, 2.0),
414 ),
415 ))
416 .unwrap();
417 let b = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
418 PRECISION,
419 (
420 Float::with_val(PRECISION, 1.0) + Float::with_val(PRECISION, 1e-25),
421 Float::with_val(PRECISION, 2.0) + Float::with_val(PRECISION, 1e-25),
422 ),
423 ))
424 .unwrap();
425 let eps_val =
426 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1e-20))
427 .unwrap();
428 let eps = AbsoluteTolerance::try_new(eps_val).unwrap();
429 assert_abs_diff_eq!(a, b, epsilon = eps);
430 }
431
432 #[test]
433 fn abs_diff_ne_different_values() {
434 let a = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
435 PRECISION,
436 (
437 Float::with_val(PRECISION, 1.0),
438 Float::with_val(PRECISION, 2.0),
439 ),
440 ))
441 .unwrap();
442 let b = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
443 PRECISION,
444 (
445 Float::with_val(PRECISION, 3.0),
446 Float::with_val(PRECISION, 4.0),
447 ),
448 ))
449 .unwrap();
450 assert_abs_diff_ne!(a, b);
451 }
452
453 #[test]
454 fn relative_eq_close_values() {
455 let a = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
456 PRECISION,
457 (
458 Float::with_val(PRECISION, 100.0),
459 Float::with_val(PRECISION, 200.0),
460 ),
461 ))
462 .unwrap();
463 let eps = RealRugStrictFinite::<PRECISION>::epsilon();
465 let b = ComplexRugStrictFinite::<PRECISION>::try_new(rug::Complex::with_val(
466 PRECISION,
467 (
468 Float::with_val(PRECISION, 100.0) + eps.as_ref(),
469 Float::with_val(PRECISION, 200.0) + eps.as_ref(),
470 ),
471 ))
472 .unwrap();
473 assert_relative_eq!(a, b);
474 }
475 }
476}
477
478#[cfg(test)]
479mod tests {
480 use super::*;
481 use crate::{
482 ComplexRugStrictFinite, ComplexScalarConstructors, ComplexScalarGetParts,
483 ComplexScalarMutateParts, ComplexScalarSetParts, Constants, Max, Min, RawRealTrait,
484 core::{
485 errors::{ErrorsRawRealToInteger, ErrorsValidationRawReal},
486 traits::validation::FpChecks,
487 },
488 functions::{
489 ACos, ACosH, ACosHErrors, ACosHInputErrors, ACosRealErrors, ACosRealInputErrors, ASin,
490 ASinRealErrors, ASinRealInputErrors, ATan, ATan2, ATan2Errors, ATanComplexErrors,
491 ATanComplexInputErrors, ATanH, ATanHErrors, ATanHInputErrors, Abs, Clamp, Exp,
492 ExpErrors, Hypot, Ln, Log2, LogarithmComplexErrors, LogarithmComplexInputErrors,
493 NegAssign, Pow, PowComplexBaseRealExponentErrors, PowIntExponentErrors,
494 PowIntExponentInputErrors, PowRealBaseRealExponentErrors, Reciprocal, ReciprocalErrors,
495 Sign, Sqrt, SqrtRealErrors, TotalCmp,
496 },
497 };
498 use num::{One, Zero};
499 use rug::{Float, float::Constant as MpfrConstant, ops::Pow as RugPow};
500 use std::{cmp::Ordering, ops::Neg};
501 use try_create::{TryNew, TryNewValidated};
502
503 const PRECISION: u32 = 53;
504
505 mod fp_checks {
506 use super::*;
507 use rug::Float;
508
509 #[test]
510 fn is_finite() {
511 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
512 assert!(real.is_finite());
513
514 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::INFINITY));
515 assert!(real.is_err());
516
517 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
518 53,
519 (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
520 ))
521 .unwrap();
522 assert!(complex.is_finite());
523
524 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
525 53,
526 (Float::with_val(53, f64::INFINITY), Float::with_val(53, 1.0)),
527 ));
528 assert!(complex.is_err());
529 }
530
531 #[test]
532 fn is_infinite() {
533 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
534 assert!(!real.is_infinite());
535
536 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::INFINITY));
537 assert!(real.is_err());
538
539 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
540 53,
541 (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
542 ))
543 .unwrap();
544 assert!(!complex.is_infinite());
545
546 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
547 53,
548 (Float::with_val(53, f64::INFINITY), Float::with_val(53, 1.0)),
549 ));
550 assert!(complex.is_err());
551 }
552
553 #[test]
554 fn is_nan() {
555 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
556 assert!(!real.is_nan());
557
558 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, f64::NAN));
559 assert!(matches!(real, Err(ErrorsValidationRawReal::IsNaN { .. })));
560
561 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
562 53,
563 (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
564 ))
565 .unwrap();
566 assert!(!complex.is_nan());
567
568 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
569 53,
570 (Float::with_val(53, f64::NAN), Float::with_val(53, 1.0)),
571 ));
572 assert!(matches!(
573 complex,
574 Err(ErrorsValidationRawComplex::InvalidRealPart {
575 source: ErrorsValidationRawReal::IsNaN { .. }
576 })
577 ));
578 }
579
580 #[test]
581 fn is_normal() {
582 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
583 assert!(real.is_normal());
584
585 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
586 assert!(!real.is_normal());
587
588 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
589 53,
590 (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
591 ))
592 .unwrap();
593 assert!(complex.is_normal());
594
595 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
596 53,
597 (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
598 ))
599 .unwrap();
600 assert!(!complex.is_normal());
601 }
602 }
603
604 mod abs {
605 use super::*;
606
607 mod real {
608 use super::*;
609
610 #[test]
611 fn abs_valid() {
612 let value =
613 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, -4.0)).unwrap();
614
615 let expected_result =
616 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 4.0)).unwrap();
617 assert_eq!(value.clone().try_abs().unwrap(), expected_result);
618 assert_eq!(value.abs(), expected_result);
619 }
620
621 #[test]
622 fn abs_zero() {
623 let value =
624 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
625
626 let expected_result =
627 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
628 assert_eq!(value.clone().try_abs().unwrap(), expected_result);
629 assert_eq!(value.abs(), expected_result);
630 }
631
632 }
656
657 mod complex {
658 use super::*;
659
660 #[test]
661 fn abs_valid() {
662 let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
663 53,
664 (rug::Float::with_val(53, 3.0), rug::Float::with_val(53, 4.0)),
665 ))
666 .unwrap();
667
668 let expected_result =
669 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 5.0)).unwrap();
670 assert_eq!(value.clone().try_abs().unwrap(), expected_result);
671 assert_eq!(value.abs(), expected_result);
672 }
673
674 #[test]
675 fn abs_zero() {
676 let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
677 53,
678 (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
679 ))
680 .unwrap();
681
682 let expected_result =
683 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
684 assert_eq!(value.clone().try_abs().unwrap(), expected_result);
685 assert_eq!(value.abs(), expected_result);
686 }
687 }
721 }
722
723 mod max_min {
724 use super::*;
725
726 #[test]
727 fn test_realrug_max() {
728 let value =
729 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
730 let other =
731 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
732 let expected =
733 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
734 assert_eq!(Max::max_by_ref(&value, &other), &expected);
735
736 let neg_value =
737 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
738 .unwrap();
739 let neg_other =
740 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
741 .unwrap();
742 let neg_expected =
743 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
744 .unwrap();
745 assert_eq!(Max::max_by_ref(&neg_value, &neg_other), &neg_expected);
746 }
747
748 #[test]
749 fn test_realrug_min() {
750 let value =
751 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
752 let other =
753 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
754 let expected =
755 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
756 assert_eq!(Min::min_by_ref(&value, &other), &expected);
757
758 let neg_value =
759 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
760 .unwrap();
761 let neg_other =
762 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
763 .unwrap();
764 let neg_expected =
765 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
766 .unwrap();
767 assert_eq!(Min::min_by_ref(&neg_value, &neg_other), &neg_expected);
768 }
769 }
770
771 mod builders {
772 use super::*;
773
774 mod real {
775 use super::*;
776
777 #[test]
778 fn try_new_nan() {
779 let nan = rug::Float::with_val(PRECISION, f64::NAN);
780 let err = RealRugStrictFinite::<PRECISION>::try_new(nan).unwrap_err();
781 assert!(matches!(err, ErrorsValidationRawReal::IsNaN { .. }));
782 }
783
784 #[test]
785 fn try_new_pos_infinity() {
786 let pos_infinity = rug::Float::with_val(PRECISION, f64::INFINITY);
787 let err = RealRugStrictFinite::<PRECISION>::try_new(pos_infinity).unwrap_err();
788 assert!(matches!(err, ErrorsValidationRawReal::IsPosInfinity { .. }));
789 }
790
791 #[test]
792 fn try_new_neg_infinity() {
793 let neg_infinity = rug::Float::with_val(PRECISION, f64::NEG_INFINITY);
794 let err = RealRugStrictFinite::<PRECISION>::try_new(neg_infinity).unwrap_err();
795 assert!(matches!(err, ErrorsValidationRawReal::IsNegInfinity { .. }));
796 }
797 }
798
799 mod complex {
800 use super::*;
801
802 #[test]
803 fn real_part() {
804 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
805 rug::Complex::with_val(PRECISION, (1.23, 4.56)),
806 )
807 .unwrap();
808 assert_eq!(c1.real_part(), 1.23);
809
810 let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
811 rug::Complex::with_val(PRECISION, (-7.89, 0.12)),
812 )
813 .unwrap();
814 assert_eq!(c2.real_part(), -7.89);
815
816 let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
817 rug::Complex::with_val(PRECISION, (0.0, 10.0)),
818 )
819 .unwrap();
820 assert_eq!(c3.real_part(), 0.0);
821
822 let c_nan_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
823 rug::Complex::with_val(PRECISION, (f64::NAN, 5.0)),
824 )
825 .unwrap_err();
826 assert!(matches!(
827 c_nan_re,
828 ErrorsValidationRawComplex::InvalidRealPart {
829 source: ErrorsValidationRawReal::IsNaN { .. }
830 }
831 ));
832
833 let c_inf_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
834 rug::Complex::with_val(PRECISION, (f64::INFINITY, 5.0)),
835 )
836 .unwrap_err();
837 assert!(matches!(
838 c_inf_re,
839 ErrorsValidationRawComplex::InvalidRealPart {
840 source: ErrorsValidationRawReal::IsPosInfinity { .. }
841 }
842 ));
843
844 let c_neg_inf_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
845 rug::Complex::with_val(PRECISION, (f64::NEG_INFINITY, 5.0)),
846 )
847 .unwrap_err();
848 assert!(matches!(
849 c_neg_inf_re,
850 ErrorsValidationRawComplex::InvalidRealPart {
851 source: ErrorsValidationRawReal::IsNegInfinity { .. }
852 }
853 ));
854 }
855
856 #[test]
857 fn imag_part() {
858 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
859 rug::Complex::with_val(PRECISION, (1.23, 4.56)),
860 )
861 .unwrap();
862 assert_eq!(c1.imag_part(), 4.56);
863
864 let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
865 rug::Complex::with_val(PRECISION, (-7.89, 0.12)),
866 )
867 .unwrap();
868 assert_eq!(c2.imag_part(), 0.12);
869
870 let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
871 rug::Complex::with_val(PRECISION, (10.0, 0.0)),
872 )
873 .unwrap();
874 assert_eq!(c3.imag_part(), 0.0);
875
876 let c_nan_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
877 rug::Complex::with_val(PRECISION, (5.0, f64::NAN)),
878 )
879 .unwrap_err();
880 assert!(matches!(
881 c_nan_im,
882 ErrorsValidationRawComplex::InvalidImaginaryPart {
883 source: ErrorsValidationRawReal::IsNaN { .. }
884 }
885 ));
886
887 let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
888 rug::Complex::with_val(PRECISION, (5.0, f64::INFINITY)),
889 )
890 .unwrap_err();
891 assert!(matches!(
892 c_inf_im,
893 ErrorsValidationRawComplex::InvalidImaginaryPart {
894 source: ErrorsValidationRawReal::IsPosInfinity { .. }
895 }
896 ));
897
898 let c_neg_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
899 rug::Complex::with_val(PRECISION, (5.0, f64::NEG_INFINITY)),
900 )
901 .unwrap_err();
902 assert!(matches!(
903 c_neg_inf_im,
904 ErrorsValidationRawComplex::InvalidImaginaryPart {
905 source: ErrorsValidationRawReal::IsNegInfinity { .. }
906 }
907 ));
908 }
909
910 #[test]
911 fn try_new_complex() {
912 let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
913 let i1 = RealRugStrictFinite::<PRECISION>::try_from_f64(4.56).unwrap();
914 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
915 r1.as_ref().clone(),
916 i1.as_ref().clone(),
917 )
918 .unwrap();
919 assert_eq!(c1.real_part(), r1);
920 assert_eq!(c1.imag_part(), i1);
921
922 let r2 = RealRugStrictFinite::<PRECISION>::try_from_f64(-7.89).unwrap();
923 let i2 = RealRugStrictFinite::<PRECISION>::try_from_f64(-0.12).unwrap();
924 let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
925 r2.as_ref().clone(),
926 i2.as_ref().clone(),
927 )
928 .unwrap();
929 assert_eq!(c2.real_part(), r2);
930 assert_eq!(c2.imag_part(), i2);
931
932 let r3 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
933 let i3 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
934 let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
935 r3.as_ref().clone(),
936 i3.as_ref().clone(),
937 )
938 .unwrap();
939 assert_eq!(c3.real_part(), r3);
940 assert_eq!(c3.real_part(), i3);
941 assert!(c3.is_zero());
942
943 let c_nan_re = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
944 Float::with_val(PRECISION, f64::NAN),
945 Float::with_val(PRECISION, 5.0),
946 )
947 .unwrap_err();
948 assert!(matches!(
949 c_nan_re,
950 ErrorsValidationRawComplex::InvalidRealPart { .. }
951 ));
952
953 let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
954 Float::with_val(PRECISION, 10.0),
955 Float::with_val(PRECISION, f64::INFINITY),
956 )
957 .unwrap_err();
958 assert!(matches!(
959 c_inf_im,
960 ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
961 ));
962
963 let c_nan_re_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
964 Float::with_val(PRECISION, f64::NAN),
965 Float::with_val(PRECISION, f64::INFINITY),
966 )
967 .unwrap_err();
968 assert!(matches!(
969 c_nan_re_inf_im,
970 ErrorsValidationRawComplex::InvalidBothParts { .. }
971 ));
972 }
973
974 #[test]
975 fn try_from_complexf64() {
976 let c1_in = num::Complex::new(1.23, 4.56);
977 let c1 = ComplexRugStrictFinite::<PRECISION>::try_from(c1_in).unwrap();
978 assert_eq!(c1.real_part(), c1_in.re);
979 assert_eq!(c1.imag_part(), c1_in.im);
980
981 let c2_in = num::Complex::new(-7.89, -0.12);
982 let c2 = ComplexRugStrictFinite::<PRECISION>::try_from(c2_in).unwrap();
983 assert_eq!(c2.real_part(), c2_in.re);
984 assert_eq!(c2.imag_part(), c2_in.im);
985
986 let c3_in = num::Complex::new(0., 0.);
987 let c3 = ComplexRugStrictFinite::<PRECISION>::try_from(c3_in).unwrap();
988 assert_eq!(c3.real_part(), c3_in.re);
989 assert_eq!(c3.imag_part(), c3_in.im);
990
991 let c_nan_re =
992 ComplexRugStrictFinite::<PRECISION>::try_from(num::Complex::new(f64::NAN, 5.0))
993 .unwrap_err();
994 assert!(matches!(
995 c_nan_re,
996 ErrorsValidationRawComplex::InvalidRealPart { .. }
997 ));
998
999 let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_from(num::Complex::new(
1000 10.0,
1001 f64::INFINITY,
1002 ))
1003 .unwrap_err();
1004 assert!(matches!(
1005 c_inf_im,
1006 ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
1007 ));
1008
1009 let c_nan_re_inf_im = ComplexRugStrictFinite::<PRECISION>::try_from(
1010 num::Complex::new(f64::NAN, f64::INFINITY),
1011 )
1012 .unwrap_err();
1013 assert!(matches!(
1014 c_nan_re_inf_im,
1015 ErrorsValidationRawComplex::InvalidBothParts { .. }
1016 ));
1017 }
1018
1019 #[test]
1020 fn try_new_pure_real() {
1021 let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
1022 let c1 =
1023 ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(r1.as_ref().clone())
1024 .unwrap();
1025 assert_eq!(c1.real_part(), r1);
1026 assert!(c1.imag_part().is_zero());
1027
1028 let c_nan = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
1029 Float::with_val(PRECISION, f64::NAN),
1030 )
1031 .unwrap_err();
1032 assert!(matches!(
1033 c_nan,
1034 ErrorsValidationRawComplex::InvalidRealPart {
1035 source: ErrorsValidationRawReal::IsNaN { .. }
1036 }
1037 ));
1038 }
1039
1040 #[test]
1041 fn try_new_pure_imaginary() {
1042 let i1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
1043 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
1044 i1.as_ref().clone(),
1045 )
1046 .unwrap();
1047 assert!(c1.real_part().is_zero());
1048 assert_eq!(c1.imag_part(), i1);
1049
1050 let c_nan = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
1051 Float::with_val(PRECISION, f64::NAN),
1052 )
1053 .unwrap_err();
1054 assert!(matches!(
1055 c_nan,
1056 ErrorsValidationRawComplex::InvalidImaginaryPart {
1057 source: ErrorsValidationRawReal::IsNaN { .. }
1058 }
1059 ));
1060 }
1061
1062 #[test]
1063 fn add_to_real_part() {
1064 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1065 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1066 )
1067 .unwrap();
1068 c.add_to_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1069 assert_eq!(c.real_part(), 4.0);
1070 assert_eq!(c.imag_part(), 2.0);
1071
1072 c.add_to_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0).unwrap());
1073 assert_eq!(c.real_part(), -1.0);
1074 assert_eq!(c.imag_part(), 2.0);
1075 }
1076
1077 #[test]
1078 fn add_to_imaginary_part() {
1079 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1080 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1081 )
1082 .unwrap();
1083 c.add_to_imaginary_part(
1084 &RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(),
1085 );
1086 assert_eq!(c.real_part(), 1.0);
1087 assert_eq!(c.imag_part(), 5.0);
1088
1089 c.add_to_imaginary_part(
1090 &RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap(),
1091 );
1092 assert_eq!(c.real_part(), 1.0);
1093 assert_eq!(c.imag_part(), 1.0);
1094 }
1095
1096 #[test]
1097 fn multiply_real_part() {
1098 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1099 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1100 )
1101 .unwrap();
1102 c.multiply_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1103 assert_eq!(c.real_part(), 3.0);
1104 assert_eq!(c.imag_part(), 2.0);
1105
1106 c.multiply_real_part(
1107 &RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap(),
1108 );
1109 assert_eq!(c.real_part(), -6.0);
1110 assert_eq!(c.imag_part(), 2.0);
1111 }
1112
1113 #[test]
1114 fn multiply_imaginary_part() {
1115 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1116 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1117 )
1118 .unwrap();
1119 c.multiply_imaginary_part(
1120 &RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(),
1121 );
1122 assert_eq!(c.real_part(), 1.0);
1123 assert_eq!(c.imag_part(), 6.0);
1124
1125 c.multiply_imaginary_part(
1126 &RealRugStrictFinite::<PRECISION>::try_from_f64(-0.5).unwrap(),
1127 );
1128 assert_eq!(c.real_part(), 1.0);
1129 assert_eq!(c.imag_part(), -3.0);
1130 }
1131
1132 #[test]
1133 fn set_real_part() {
1134 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1135 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1136 )
1137 .unwrap();
1138 c.set_real_part(RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1139 assert_eq!(c.real_part(), 3.0);
1140 assert_eq!(c.imag_part(), 2.0);
1141
1142 c.set_real_part(RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap());
1143 assert_eq!(c.real_part(), -4.0);
1144 assert_eq!(c.imag_part(), 2.0);
1145 }
1146
1147 #[test]
1148 fn set_imaginary_part() {
1149 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1150 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1151 )
1152 .unwrap();
1153 c.set_imaginary_part(RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1154 assert_eq!(c.real_part(), 1.0);
1155 assert_eq!(c.imag_part(), 3.0);
1156
1157 c.set_imaginary_part(RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap());
1158 assert_eq!(c.real_part(), 1.0);
1159 assert_eq!(c.imag_part(), -4.0);
1160 }
1161 }
1162 }
1163
1164 mod mul {
1165 use super::*;
1166
1167 mod real {
1168 use super::*;
1169
1170 #[test]
1171 fn multiply_ref() {
1172 let r1 = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1173 PRECISION, 3.0,
1174 ))
1175 .unwrap();
1176 let r2 = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1177 PRECISION, 4.0,
1178 ))
1179 .unwrap();
1180 let result = r1 * &r2;
1181 assert_eq!(
1182 result,
1183 RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1184 PRECISION, 12.0
1185 ))
1186 .unwrap()
1187 );
1188 }
1189 }
1190
1191 mod complex {
1192 use super::*;
1193
1194 #[test]
1195 fn multiply_ref() {
1196 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1197 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1198 )
1199 .unwrap();
1200 let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1201 rug::Complex::with_val(PRECISION, (3.0, 4.0)),
1202 )
1203 .unwrap();
1204 let result = c1 * &c2;
1205 assert_eq!(
1206 result,
1207 ComplexRugStrictFinite::<PRECISION>::try_new_validated(rug::Complex::with_val(
1208 PRECISION,
1209 (-5.0, 10.0),
1210 ))
1211 .unwrap()
1212 ); }
1214
1215 #[test]
1216 fn complex_times_real() {
1217 let r = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1218 PRECISION, 2.0,
1219 ))
1220 .unwrap();
1221 let c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1222 rug::Complex::with_val(PRECISION, (3.0, 4.0)),
1223 )
1224 .unwrap();
1225
1226 let result_expected = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1227 rug::Complex::with_val(PRECISION, (6.0, 8.0)),
1228 )
1229 .unwrap(); let result = c.clone() * &r;
1232 assert_eq!(&result, &result_expected);
1233
1234 let result = c.clone() * r.clone();
1235 assert_eq!(&result, &result_expected);
1236
1237 let mut result = c.clone();
1238 result *= &r;
1239 assert_eq!(&result, &result_expected);
1240
1241 let mut result = c.clone();
1242 result *= r;
1243 assert_eq!(&result, &result_expected);
1244 }
1245
1246 #[test]
1247 fn real_times_complex() {
1248 let r = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1249 PRECISION, 2.0,
1250 ))
1251 .unwrap();
1252 let c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1253 rug::Complex::with_val(PRECISION, (3.0, 4.0)),
1254 )
1255 .unwrap();
1256
1257 let result_expected = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1258 rug::Complex::with_val(PRECISION, (6.0, 8.0)),
1259 )
1260 .unwrap(); let result = &r * c.clone();
1263 assert_eq!(&result, &result_expected);
1264
1265 let result = r * c.clone();
1266 assert_eq!(&result, &result_expected);
1267 }
1268 }
1269 }
1270
1271 mod arithmetic {
1272 use super::*;
1273
1274 mod real {
1275 use super::*;
1276
1277 #[test]
1278 fn neg_assign() {
1279 let mut a = rug::Float::with_val(PRECISION, 1.);
1280 a.neg_assign();
1281 let a_expected = rug::Float::with_val(PRECISION, -1.);
1282 assert_eq!(a, a_expected);
1283
1284 let mut b = RealRugStrictFinite::<PRECISION>::one();
1285 b.neg_assign();
1286 let b_expected = RealRugStrictFinite::<PRECISION>::try_new_validated(
1287 rug::Float::with_val(PRECISION, -1.),
1288 )
1289 .unwrap();
1290 assert_eq!(&b, &b_expected);
1291 }
1292
1293 #[test]
1294 #[should_panic(expected = "Division failed validation")]
1295 fn div_by_zero() {
1296 let one = RealRugStrictFinite::<PRECISION>::one();
1297 let zero = RealRugStrictFinite::<PRECISION>::zero();
1298 let _ = &one / &zero;
1299 }
1300
1301 #[test]
1302 #[should_panic(expected = "Division failed validation")]
1303 fn div_assign_by_zero() {
1304 let mut num = RealRugStrictFinite::<PRECISION>::one();
1305 let zero_ref = &RealRugStrictFinite::<PRECISION>::zero();
1306 num /= zero_ref;
1307 }
1308 }
1309
1310 mod complex {
1311 use super::*;
1312
1313 #[test]
1314 fn neg_assign() {
1315 let re = rug::Float::with_val(PRECISION, 1.);
1316 let im = rug::Float::with_val(PRECISION, 2.);
1317 let mut num = rug::Complex::with_val(PRECISION, (re, im));
1318 num.neg_assign();
1319 let expected = rug::Complex::with_val(
1320 PRECISION,
1321 (
1322 rug::Float::with_val(PRECISION, -1.),
1323 rug::Float::with_val(PRECISION, -2.),
1324 ),
1325 );
1326 assert_eq!(&num, &expected);
1327
1328 let mut num = ComplexRugStrictFinite::<PRECISION>::try_new_validated(num).unwrap();
1329 let expected = num.clone().neg();
1330 num.neg_assign();
1331 assert_eq!(&num, &expected);
1332 }
1333
1334 #[test]
1335 #[should_panic(expected = "Division failed validation")]
1336 fn div_by_zero() {
1337 let one = ComplexRugStrictFinite::<PRECISION>::one();
1338 let zero = ComplexRugStrictFinite::<PRECISION>::zero();
1339 let _ = &one / &zero;
1340 }
1341
1342 #[test]
1343 #[should_panic(expected = "Division failed validation")]
1344 fn div_assign_by_zero() {
1345 let mut num = ComplexRugStrictFinite::<PRECISION>::one();
1346 let zero_ref = &ComplexRugStrictFinite::<PRECISION>::zero();
1347 num /= zero_ref;
1348 }
1349 }
1350 }
1351
1352 mod real_scalar_methods {
1353 use super::*;
1354
1355 #[test]
1356 fn epsilon() {
1357 let eps = RealRugStrictFinite::<PRECISION>::epsilon();
1358 assert!(eps.is_finite() && eps > RealRugStrictFinite::<PRECISION>::zero());
1359 let expected_eps_val =
1360 rug::Float::with_val(PRECISION, 2.0).pow(1i32 - PRECISION as i32);
1361 let expected_eps = RealRugStrictFinite::<PRECISION>::try_new(expected_eps_val).unwrap();
1362 assert_eq!(eps, expected_eps, "Epsilon value mismatch");
1363 }
1364
1365 #[test]
1366 fn clamp_ref() {
1367 let val = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap();
1368 let min_val = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
1369 let max_val = RealRugStrictFinite::<PRECISION>::try_from_f64(10.0).unwrap();
1370
1371 assert_eq!(val.clone().clamp_ref(&min_val, &max_val), val);
1372 assert_eq!(
1373 RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0)
1374 .unwrap()
1375 .clamp_ref(&min_val, &max_val),
1376 min_val
1377 );
1378 assert_eq!(
1379 RealRugStrictFinite::<PRECISION>::try_from_f64(15.0)
1380 .unwrap()
1381 .clamp_ref(&min_val, &max_val),
1382 max_val
1383 );
1384 }
1385
1386 #[test]
1387 fn hypot() {
1388 let a = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap();
1389 let b = RealRugStrictFinite::<PRECISION>::try_from_f64(4.0).unwrap();
1390 let expected = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap();
1391 assert_eq!(a.hypot(&b), expected);
1392 }
1393
1394 #[test]
1395 fn signum() {
1396 assert_eq!(
1397 RealRugStrictFinite::<PRECISION>::try_from_f64(5.0)
1398 .unwrap()
1399 .kernel_signum(),
1400 RealRugStrictFinite::<PRECISION>::one()
1401 );
1402 assert_eq!(
1403 RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0)
1404 .unwrap()
1405 .kernel_signum(),
1406 RealRugStrictFinite::<PRECISION>::negative_one()
1407 );
1408 assert_eq!(
1410 RealRugStrictFinite::<PRECISION>::zero().kernel_signum(),
1411 RealRugStrictFinite::<PRECISION>::one()
1412 );
1413 }
1414
1415 #[test]
1416 fn total_cmp() {
1417 let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0).unwrap();
1418 let r2 = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1419 assert_eq!(r1.total_cmp(&r1), Ordering::Equal);
1420 assert_eq!(r1.total_cmp(&r2), Ordering::Less);
1421 assert_eq!(r2.total_cmp(&r1), Ordering::Greater);
1422 }
1423
1424 #[test]
1425 fn mul_add_mul_mut() {
1426 let mut a = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1427 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);
1432 assert_eq!(
1433 a,
1434 RealRugStrictFinite::<PRECISION>::try_from_f64(26.0).unwrap()
1435 );
1436 }
1437
1438 #[test]
1439 fn mul_sub_mul_mut() {
1440 let mut a = RealRugStrictFinite::<PRECISION>::try_from_f64(10.0).unwrap();
1441 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);
1446 assert_eq!(
1447 a,
1448 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1449 );
1450 }
1451
1452 #[test]
1453 fn test_real_rug_constants() {
1454 let raw_float = |f: f64| Float::with_val(PRECISION, f);
1456
1457 let pi = RealRugStrictFinite::<PRECISION>::pi();
1459 let expected_pi = Float::with_val(PRECISION, MpfrConstant::Pi);
1460 assert_eq!(pi.as_ref(), &expected_pi);
1461
1462 let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
1464 let expected_two_pi = Float::with_val(PRECISION, MpfrConstant::Pi) * 2;
1465 assert_eq!(two_pi.as_ref(), &expected_two_pi);
1466
1467 let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1469 let expected_pi_div_2 = Float::with_val(PRECISION, MpfrConstant::Pi) / 2;
1470 assert_eq!(pi_div_2.as_ref(), &expected_pi_div_2);
1471
1472 let e = RealRugStrictFinite::<PRECISION>::e();
1474 let expected_e = raw_float(1.0).exp();
1475 assert_eq!(e.as_ref(), &expected_e);
1476
1477 let log2_e = RealRugStrictFinite::<PRECISION>::log2_e();
1479 let expected_log2_e = Float::with_val(PRECISION, MpfrConstant::Log2).recip();
1480 assert_eq!(log2_e.as_ref(), &expected_log2_e);
1481
1482 let log10_e = RealRugStrictFinite::<PRECISION>::log10_e();
1484 let ln2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1485 let log2_10 = raw_float(10.0).log2();
1486 let expected_log10_e = (ln2 * log2_10).recip();
1487 assert_eq!(log10_e.as_ref(), &expected_log10_e);
1488
1489 let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1491 let expected_ln_2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1492 assert_eq!(ln_2.as_ref(), &expected_ln_2);
1493
1494 let ln_10 = RealRugStrictFinite::<PRECISION>::ln_10();
1496 let ln2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1497 let log2_10 = raw_float(10.0).log2();
1498 let expected_ln_10 = ln2 * log2_10;
1499 assert_eq!(ln_10.as_ref(), &expected_ln_10);
1500
1501 let log2_10 = RealRugStrictFinite::<PRECISION>::log2_10();
1503 let expected_log2_10 = raw_float(10.0).log2();
1504 assert_eq!(log2_10.as_ref(), &expected_log2_10);
1505
1506 let log10_2 = RealRugStrictFinite::<PRECISION>::log10_2();
1508 let expected_log10_2 = raw_float(2.0).log10();
1509 assert_eq!(log10_2.as_ref(), &expected_log10_2);
1510
1511 let max_finite = RealRugStrictFinite::<PRECISION>::max_finite();
1513 let expected_max_finite = <rug::Float as RawRealTrait>::raw_max_finite(PRECISION);
1514 assert_eq!(max_finite.as_ref(), &expected_max_finite);
1515
1516 let min_finite = RealRugStrictFinite::<PRECISION>::min_finite();
1518 let expected_min_finite = <rug::Float as RawRealTrait>::raw_min_finite(PRECISION);
1519 assert_eq!(min_finite.as_ref(), &expected_min_finite);
1520
1521 let epsilon = RealRugStrictFinite::<PRECISION>::epsilon();
1523 let expected_epsilon = <rug::Float as RawRealTrait>::raw_epsilon(PRECISION);
1524 assert_eq!(epsilon.as_ref(), &expected_epsilon);
1525
1526 assert_eq!(
1528 RealRugStrictFinite::<PRECISION>::negative_one().as_ref(),
1529 &raw_float(-1.0)
1530 );
1531
1532 assert_eq!(
1534 RealRugStrictFinite::<PRECISION>::two().as_ref(),
1535 &raw_float(2.0)
1536 );
1537
1538 assert_eq!(
1540 RealRugStrictFinite::<PRECISION>::one_div_2().as_ref(),
1541 &raw_float(0.5)
1542 );
1543 }
1544
1545 #[test]
1549 fn test_real_rug_constants_mpfr_optimization() {
1550 let pi = RealRugStrictFinite::<PRECISION>::pi();
1552 let expected_pi = Float::with_val(PRECISION, MpfrConstant::Pi);
1553 assert_eq!(pi.as_ref(), &expected_pi);
1554
1555 let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1557 let expected_ln_2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1558 assert_eq!(ln_2.as_ref(), &expected_ln_2);
1559
1560 let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
1562 let expected_two_pi = Float::with_val(PRECISION, MpfrConstant::Pi) * 2;
1563 assert_eq!(two_pi.as_ref(), &expected_two_pi);
1564
1565 let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1566 let expected_pi_div_2 = Float::with_val(PRECISION, MpfrConstant::Pi) / 2;
1567 assert_eq!(pi_div_2.as_ref(), &expected_pi_div_2);
1568 }
1569
1570 #[test]
1572 fn test_real_rug_constants_precision_independence() {
1573 type Real100 = RealRugStrictFinite<100>;
1574 type Real200 = RealRugStrictFinite<200>;
1575 type Real500 = RealRugStrictFinite<500>;
1576
1577 let pi_100 = Real100::pi();
1579 let pi_200 = Real200::pi();
1580 let pi_500 = Real500::pi();
1581
1582 let pi_100_f64 = pi_100.as_ref().to_f64();
1585 let pi_200_f64 = pi_200.as_ref().to_f64();
1586 let pi_500_f64 = pi_500.as_ref().to_f64();
1587
1588 let pi_expected = std::f64::consts::PI;
1589 assert!((pi_100_f64 - pi_expected).abs() < 1e-15);
1590 assert!((pi_200_f64 - pi_expected).abs() < 1e-15);
1591 assert!((pi_500_f64 - pi_expected).abs() < 1e-15);
1592
1593 let e_100 = Real100::e();
1595 let e_200 = Real200::e();
1596
1597 let e_100_f64 = e_100.as_ref().to_f64();
1598 let e_200_f64 = e_200.as_ref().to_f64();
1599
1600 let e_expected = std::f64::consts::E;
1601 assert!((e_100_f64 - e_expected).abs() < 1e-15);
1602 assert!((e_200_f64 - e_expected).abs() < 1e-15);
1603 }
1604
1605 #[test]
1607 fn test_real_rug_constants_mathematical_relationships() {
1608 let pi = RealRugStrictFinite::<PRECISION>::pi();
1609 let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
1610 let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1611
1612 let expected_two_pi = pi.as_ref() * Float::with_val(PRECISION, 2);
1614 assert_eq!(two_pi.as_ref(), &expected_two_pi);
1615
1616 let expected_pi_div_2 = pi.as_ref() / Float::with_val(PRECISION, 2);
1618 assert_eq!(pi_div_2.as_ref(), &expected_pi_div_2);
1619
1620 let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1621 let ln_10 = RealRugStrictFinite::<PRECISION>::ln_10();
1622 let log2_e = RealRugStrictFinite::<PRECISION>::log2_e();
1623 let log10_e = RealRugStrictFinite::<PRECISION>::log10_e();
1624
1625 let product = (log2_e.as_ref() * ln_2.as_ref()).complete(PRECISION);
1627 let one = Float::with_val(PRECISION, 1);
1628 let epsilon = Float::with_val(PRECISION, 1e-10);
1629 let diff = (product - &one).abs();
1630 assert!(diff < epsilon);
1631
1632 let product = (log10_e.as_ref() * ln_10.as_ref()).complete(PRECISION);
1634 let diff = (product - &one).abs();
1635 assert!(diff < epsilon);
1636 }
1637
1638 #[test]
1641 fn test_real_rug_constants_consistency() {
1642 let pi1 = RealRugStrictFinite::<PRECISION>::pi();
1644 let pi2 = RealRugStrictFinite::<PRECISION>::pi();
1645 assert_eq!(pi1.as_ref(), pi2.as_ref());
1646
1647 let e1 = RealRugStrictFinite::<PRECISION>::e();
1648 let e2 = RealRugStrictFinite::<PRECISION>::e();
1649 assert_eq!(e1.as_ref(), e2.as_ref());
1650
1651 let ln2_1 = RealRugStrictFinite::<PRECISION>::ln_2();
1652 let ln2_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1653 assert_eq!(ln2_1.as_ref(), ln2_2.as_ref());
1654
1655 let two_pi1 = RealRugStrictFinite::<PRECISION>::two_pi();
1656 let two_pi2 = RealRugStrictFinite::<PRECISION>::two_pi();
1657 assert_eq!(two_pi1.as_ref(), two_pi2.as_ref());
1658
1659 let pi_div_2_1 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1660 let pi_div_2_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1661 assert_eq!(pi_div_2_1.as_ref(), pi_div_2_2.as_ref());
1662 }
1663 }
1664
1665 mod scalar_constructors {
1666 use super::*;
1667 use crate::{
1668 core::errors::ErrorsValidationRawReal,
1669 functions::{
1670 ATan2InputErrors, LogarithmRealErrors, LogarithmRealInputErrors,
1671 PowComplexBaseRealExponentInputErrors, PowRealBaseRealExponentInputErrors,
1672 ReciprocalInputErrors, SqrtRealInputErrors,
1673 },
1674 };
1675
1676 mod real {
1677 use super::*;
1678
1679 #[test]
1680 fn exp_overflow() {
1681 let large_val = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0e60).unwrap(); let res_large = large_val.try_exp();
1683 assert!(matches!(
1684 res_large,
1685 Err(ExpErrors::Output {
1686 source: ErrorsValidationRawReal::IsPosInfinity { .. }
1687 })
1688 ),);
1689 }
1690
1691 #[test]
1692 fn ln_domain_errors() {
1693 let neg_val = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.0).unwrap();
1694 assert!(matches!(
1695 neg_val.try_ln(),
1696 Err(LogarithmRealErrors::Input {
1697 source: LogarithmRealInputErrors::NegativeArgument { .. }
1698 })
1699 ));
1700
1701 let zero_val = RealRugStrictFinite::<PRECISION>::zero();
1702 assert!(matches!(
1703 zero_val.try_ln(),
1704 Err(LogarithmRealErrors::Input {
1705 source: LogarithmRealInputErrors::ZeroArgument { .. }
1706 })
1707 ));
1708 }
1709 } mod complex {
1712 use super::*;
1713
1714 #[test]
1715 fn log2_zero() {
1716 let zero_val = ComplexRugStrictFinite::<PRECISION>::zero();
1717 assert!(matches!(
1718 zero_val.try_log2(),
1719 Err(LogarithmComplexErrors::Input {
1720 source: LogarithmComplexInputErrors::ZeroArgument { .. }
1721 })
1722 ));
1723 }
1724 } mod pow {
1727 use super::*;
1728
1729 mod real_base {
1730 use super::*;
1731
1732 #[test]
1733 fn negative_base_real_exponent_error() {
1734 let base = RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap();
1735 let exponent = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
1736 let res = base.try_pow(&exponent);
1737 assert!(matches!(
1738 res,
1739 Err(PowRealBaseRealExponentErrors::Input {
1740 source: PowRealBaseRealExponentInputErrors::NegativeBase { .. }
1741 })
1742 ));
1743 }
1744
1745 #[test]
1746 fn real_base_uint_exponent() {
1747 let base = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1748 assert_eq!(
1749 base.clone().try_pow(3u8).unwrap(),
1750 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1751 );
1752 assert_eq!(
1753 base.clone().try_pow(3u16).unwrap(),
1754 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1755 );
1756 assert_eq!(
1757 base.clone().try_pow(3u32).unwrap(),
1758 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1759 );
1760 assert_eq!(
1761 base.clone().try_pow(3u64).unwrap(),
1762 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1763 );
1764 assert_eq!(
1765 base.clone().try_pow(3u128).unwrap(),
1766 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1767 );
1768 assert_eq!(
1769 base.clone().try_pow(3usize).unwrap(),
1770 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1771 );
1772
1773 assert_eq!(
1774 base.clone().pow(3u8),
1775 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1776 );
1777 assert_eq!(
1778 base.clone().pow(3u16),
1779 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1780 );
1781 assert_eq!(
1782 base.clone().pow(3u32),
1783 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1784 );
1785 assert_eq!(
1786 base.clone().pow(3u64),
1787 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1788 );
1789 assert_eq!(
1790 base.clone().pow(3u128),
1791 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1792 );
1793 assert_eq!(
1794 base.clone().pow(3usize),
1795 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1796 );
1797 }
1798
1799 #[test]
1800 fn real_base_int_exponent() {
1801 let base = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1802 assert_eq!(
1803 base.clone().try_pow(3i8).unwrap(),
1804 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1805 );
1806 assert_eq!(
1807 base.clone().try_pow(3i16).unwrap(),
1808 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1809 );
1810 assert_eq!(
1811 base.clone().try_pow(3i32).unwrap(),
1812 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1813 );
1814 assert_eq!(
1815 base.clone().try_pow(3i64).unwrap(),
1816 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1817 );
1818 assert_eq!(
1819 base.clone().try_pow(3i128).unwrap(),
1820 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1821 );
1822 assert_eq!(
1823 base.clone().try_pow(3isize).unwrap(),
1824 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1825 );
1826
1827 assert_eq!(
1828 base.clone().pow(3i8),
1829 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1830 );
1831 assert_eq!(
1832 base.clone().pow(3i16),
1833 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1834 );
1835 assert_eq!(
1836 base.clone().pow(3i32),
1837 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1838 );
1839 assert_eq!(
1840 base.clone().pow(3i64),
1841 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1842 );
1843 assert_eq!(
1844 base.clone().pow(3i128),
1845 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1846 );
1847 assert_eq!(
1848 base.clone().pow(3isize),
1849 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1850 );
1851 }
1852
1853 #[test]
1854 fn real_base_int_exponent_zero_neg_exp_error() {
1855 let base = RealRugStrictFinite::<PRECISION>::zero();
1856 let exponent: i32 = -2;
1857 let res = base.try_pow(exponent);
1858 assert!(matches!(
1859 res,
1860 Err(PowIntExponentErrors::Input {
1861 source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
1862 })
1863 ));
1864 }
1865 }
1866
1867 mod complex_base {
1868 use super::*;
1869
1870 #[test]
1871 fn complex_base_uint_exponent() {
1872 let base = ComplexRugStrictFinite::<PRECISION>::try_new(
1873 rug::Complex::with_val(PRECISION, (2.0, 3.0)),
1874 )
1875 .unwrap();
1876 let expected_res = ComplexRugStrictFinite::<PRECISION>::try_new(
1877 rug::Complex::with_val(PRECISION, (-46.0, 9.0)),
1878 )
1879 .unwrap();
1880
1881 assert_eq!(&base.clone().try_pow(3u8).unwrap(), &expected_res);
1882 assert_eq!(&base.clone().try_pow(3u16).unwrap(), &expected_res);
1883 assert_eq!(&base.clone().try_pow(3u32).unwrap(), &expected_res);
1884 assert_eq!(&base.clone().try_pow(3u64).unwrap(), &expected_res);
1885 assert_eq!(&base.clone().try_pow(3u128).unwrap(), &expected_res);
1886 assert_eq!(&base.clone().try_pow(3usize).unwrap(), &expected_res);
1887
1888 assert_eq!(&base.clone().pow(3u8), &expected_res);
1889 assert_eq!(&base.clone().pow(3u16), &expected_res);
1890 assert_eq!(&base.clone().pow(3u32), &expected_res);
1891 assert_eq!(&base.clone().pow(3u64), &expected_res);
1892 assert_eq!(&base.clone().pow(3u128), &expected_res);
1893 assert_eq!(&base.clone().pow(3usize), &expected_res);
1894 }
1895
1896 #[test]
1897 fn complex_base_int_exponent() {
1898 let base = ComplexRugStrictFinite::<PRECISION>::try_new(
1899 rug::Complex::with_val(PRECISION, (2.0, 3.0)),
1900 )
1901 .unwrap();
1902 let expected_res = ComplexRugStrictFinite::<PRECISION>::try_new(
1903 rug::Complex::with_val(PRECISION, (-46.0, 9.0)),
1904 )
1905 .unwrap();
1906
1907 assert_eq!(&base.clone().try_pow(3i8).unwrap(), &expected_res);
1908 assert_eq!(&base.clone().try_pow(3i16).unwrap(), &expected_res);
1909 assert_eq!(&base.clone().try_pow(3i32).unwrap(), &expected_res);
1910 assert_eq!(&base.clone().try_pow(3i64).unwrap(), &expected_res);
1911 assert_eq!(&base.clone().try_pow(3i128).unwrap(), &expected_res);
1912 assert_eq!(&base.clone().try_pow(3isize).unwrap(), &expected_res);
1913
1914 assert_eq!(&base.clone().pow(3i8), &expected_res);
1915 assert_eq!(&base.clone().pow(3i16), &expected_res);
1916 assert_eq!(&base.clone().pow(3i32), &expected_res);
1917 assert_eq!(&base.clone().pow(3i64), &expected_res);
1918 assert_eq!(&base.clone().pow(3i128), &expected_res);
1919 assert_eq!(&base.clone().pow(3isize), &expected_res);
1920 }
1921
1922 #[test]
1923 fn complex_zero_base_negative_real_exponent_error() {
1924 let base = ComplexRugStrictFinite::<PRECISION>::zero();
1925 let exponent = RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap();
1926 let res = base.try_pow(&exponent);
1927 assert!(matches!(
1928 res,
1929 Err(PowComplexBaseRealExponentErrors::Input {
1930 source:
1931 PowComplexBaseRealExponentInputErrors::ZeroBaseNegativeExponent { .. }
1932 })
1933 ));
1934 }
1935
1936 #[test]
1937 fn complex_zero_base_zero_real_exponent() {
1938 let base = ComplexRugStrictFinite::<PRECISION>::zero();
1939 let exponent = RealRugStrictFinite::<PRECISION>::zero();
1940 let res = base.try_pow(&exponent).unwrap();
1941 assert_eq!(res, ComplexRugStrictFinite::<PRECISION>::one());
1942 }
1943
1944 #[test]
1945 fn complex_base_int_exponent_zero_neg_exp_error() {
1946 let base = ComplexRugStrictFinite::<PRECISION>::zero();
1947 let exponent: i32 = -2;
1948 let res = base.try_pow(exponent);
1949 assert!(matches!(
1950 res,
1951 Err(PowIntExponentErrors::Input {
1952 source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
1953 })
1954 ));
1955 }
1956 }
1957 }
1958
1959 #[test]
1960 fn reciprocal_real_rug_zero() {
1961 let zero_val = RealRugStrictFinite::<PRECISION>::zero();
1962 let res = zero_val.try_reciprocal();
1963 assert!(matches!(
1964 res,
1965 Err(ReciprocalErrors::Input {
1966 source: ReciprocalInputErrors::DivisionByZero { .. }
1967 })
1968 ));
1969 }
1970
1971 #[test]
1972 fn reciprocal_complex_rug_zero() {
1973 let zero_val = ComplexRugStrictFinite::<PRECISION>::zero();
1974 let res = zero_val.try_reciprocal();
1975 assert!(matches!(
1976 res,
1977 Err(ReciprocalErrors::Input {
1978 source: ReciprocalInputErrors::DivisionByZero { .. }
1979 })
1980 ));
1981 }
1982
1983 #[test]
1984 fn sqrt_real_rug_negative_input() {
1985 let neg_val = RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap();
1986 let res = neg_val.try_sqrt();
1987 assert!(matches!(
1988 res,
1989 Err(SqrtRealErrors::Input {
1990 source: SqrtRealInputErrors::NegativeValue { .. }
1991 })
1992 ));
1993 }
1994
1995 mod trigonometric {
1996 use super::*;
1997
1998 #[test]
1999 fn atan2_real_rug_zero_over_zero() {
2000 let zero_val = RealRugStrictFinite::<PRECISION>::zero();
2001 let res = zero_val.try_atan2(&RealRugStrictFinite::<PRECISION>::zero());
2002 assert!(matches!(
2003 res,
2004 Err(ATan2Errors::Input {
2005 source: ATan2InputErrors::ZeroOverZero { .. }
2006 })
2007 ));
2008 }
2009
2010 #[test]
2028 fn asin_real_rug_out_of_domain() {
2029 let val_gt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.5).unwrap();
2030 assert!(matches!(
2031 val_gt_1.try_asin(),
2032 Err(ASinRealErrors::Input {
2033 source: ASinRealInputErrors::OutOfDomain { .. }
2034 })
2035 ));
2036 let val_lt_neg1 = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.5).unwrap();
2037 assert!(matches!(
2038 val_lt_neg1.try_asin(),
2039 Err(ASinRealErrors::Input {
2040 source: ASinRealInputErrors::OutOfDomain { .. }
2041 })
2042 ));
2043 }
2044
2045 #[test]
2046 fn acos_real_rug_out_of_domain() {
2047 let val_gt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.5).unwrap();
2048 assert!(matches!(
2049 val_gt_1.try_acos(),
2050 Err(ACosRealErrors::Input {
2051 source: ACosRealInputErrors::OutOfDomain { .. }
2052 })
2053 ));
2054 let val_lt_neg1 = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.5).unwrap();
2055 assert!(matches!(
2056 val_lt_neg1.try_acos(),
2057 Err(ACosRealErrors::Input {
2058 source: ACosRealInputErrors::OutOfDomain { .. }
2059 })
2060 ));
2061 }
2062
2063 #[test]
2064 fn atan_complex_rug_pole() {
2065 let i_val = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
2067 Float::with_val(PRECISION, 1.0),
2068 )
2069 .unwrap();
2070 assert!(matches!(
2071 i_val.try_atan(),
2072 Err(ATanComplexErrors::Input {
2073 source: ATanComplexInputErrors::ArgumentIsPole { .. }
2074 })
2075 ));
2076
2077 let neg_i_val = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
2078 Float::with_val(PRECISION, -1.0),
2079 )
2080 .unwrap();
2081 assert!(matches!(
2082 neg_i_val.try_atan(),
2083 Err(ATanComplexErrors::Input {
2084 source: ATanComplexInputErrors::ArgumentIsPole { .. }
2085 })
2086 ));
2087 }
2088 } mod hyperbolic {
2091 use super::*;
2092
2093 mod real {
2094 use super::*;
2095
2096 #[test]
2097 fn atanh_real_rug_out_of_domain() {
2098 let val_ge_1 = RealRugStrictFinite::<PRECISION>::one(); assert!(matches!(
2100 val_ge_1.try_atanh(),
2101 Err(ATanHErrors::Input {
2102 source: ATanHInputErrors::OutOfDomain { .. }
2103 })
2104 ));
2105
2106 let val_le_neg1 = RealRugStrictFinite::<PRECISION>::negative_one(); assert!(matches!(
2108 val_le_neg1.try_atanh(),
2109 Err(ATanHErrors::Input {
2110 source: ATanHInputErrors::OutOfDomain { .. }
2111 })
2112 ));
2113 }
2114
2115 #[test]
2116 fn acosh_real_rug_out_of_domain() {
2117 let val_lt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
2118 assert!(matches!(
2119 val_lt_1.try_acosh(),
2120 Err(ACosHErrors::Input {
2121 source: ACosHInputErrors::OutOfDomain { .. }
2122 })
2123 ));
2124 }
2125 }
2126
2127 mod complex {
2128 use super::*;
2129
2130 #[test]
2149 fn acosh_out_of_domain() {
2150 let val_on_branch_cut = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2152 Float::with_val(PRECISION, 0.5),
2153 )
2154 .unwrap();
2155 assert!(matches!(
2156 val_on_branch_cut.try_acosh(),
2157 Err(ACosHErrors::Input {
2158 source: ACosHInputErrors::OutOfDomain { .. }
2159 })
2160 ));
2161
2162 let val_on_branch_cut_neg =
2163 ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(Float::with_val(
2164 PRECISION, -5.0,
2165 ))
2166 .unwrap();
2167 assert!(matches!(
2168 val_on_branch_cut_neg.try_acosh(),
2169 Err(ACosHErrors::Input {
2170 source: ACosHInputErrors::OutOfDomain { .. }
2171 })
2172 ));
2173 }
2174
2175 #[test]
2176 fn atanh_out_of_domain() {
2177 let val_ge_1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2178 Float::with_val(PRECISION, 1.0),
2179 )
2180 .unwrap();
2181 assert!(matches!(
2182 val_ge_1.try_atanh(),
2183 Err(ATanHErrors::Input {
2184 source: ATanHInputErrors::OutOfDomain { .. }
2185 })
2186 ));
2187
2188 let val_le_neg1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2189 Float::with_val(PRECISION, -1.0),
2190 )
2191 .unwrap();
2192 assert!(matches!(
2193 val_le_neg1.try_atanh(),
2194 Err(ATanHErrors::Input {
2195 source: ATanHInputErrors::OutOfDomain { .. }
2196 })
2197 ));
2198 }
2199 }
2200
2201 } }
2219
2220 mod summation {
2221 use super::*;
2222
2223 const PRECISION: u32 = 53;
2224
2225 type RealValidated = RealRugStrictFinite<PRECISION>;
2226 type ComplexValidated = ComplexRugStrictFinite<PRECISION>;
2227
2228 #[test]
2229 fn sum_real() {
2230 let values = vec![
2231 RealValidated::try_from_f64(1.0).unwrap(),
2232 RealValidated::try_from_f64(2.0).unwrap(),
2233 RealValidated::try_from_f64(3.0).unwrap(),
2234 RealValidated::try_from_f64(4.0).unwrap(),
2235 RealValidated::try_from_f64(5.0).unwrap(),
2236 ];
2237 let sum: RealValidated = values.into_iter().sum();
2238 assert_eq!(sum, RealValidated::try_from_f64(15.0).unwrap());
2239 }
2240
2241 #[test]
2242 fn sum_real_compensated() {
2243 let values = vec![
2245 RealValidated::try_from_f64(1.0e100).unwrap(),
2246 RealValidated::try_from_f64(1.0).unwrap(),
2247 RealValidated::try_from_f64(-1.0e100).unwrap(),
2248 ];
2249 let sum: RealValidated = values.into_iter().sum();
2250 assert_eq!(sum, RealValidated::try_from_f64(1.0).unwrap());
2252 }
2253
2254 #[test]
2255 fn sum_complex() {
2256 let values = vec![
2257 ComplexValidated::try_new_complex(
2258 rug::Float::with_val(PRECISION, 1.),
2259 rug::Float::with_val(PRECISION, 2.),
2260 )
2261 .unwrap(),
2262 ComplexValidated::try_new_complex(
2263 rug::Float::with_val(PRECISION, 3.),
2264 rug::Float::with_val(PRECISION, 4.),
2265 )
2266 .unwrap(),
2267 ComplexValidated::try_new_complex(
2268 rug::Float::with_val(PRECISION, 5.),
2269 rug::Float::with_val(PRECISION, 6.),
2270 )
2271 .unwrap(),
2272 ];
2273 let sum: ComplexValidated = values.into_iter().sum();
2274 assert_eq!(
2275 sum,
2276 ComplexValidated::try_new_complex(
2277 rug::Float::with_val(PRECISION, 9.),
2278 rug::Float::with_val(PRECISION, 12.)
2279 )
2280 .unwrap()
2281 );
2282 }
2283
2284 #[test]
2285 fn sum_complex_compensated() {
2286 let values = [
2287 ComplexValidated::try_new_complex(
2288 rug::Float::with_val(PRECISION, 1.0e100),
2289 rug::Float::with_val(PRECISION, -1.0e100),
2290 )
2291 .unwrap(),
2292 ComplexValidated::try_new_complex(
2293 rug::Float::with_val(PRECISION, 1.),
2294 rug::Float::with_val(PRECISION, 2.),
2295 )
2296 .unwrap(),
2297 ComplexValidated::try_new_complex(
2298 rug::Float::with_val(PRECISION, -1.0e100),
2299 rug::Float::with_val(PRECISION, 1.0e100),
2300 )
2301 .unwrap(),
2302 ];
2303 let sum: ComplexValidated = values.iter().cloned().sum();
2304 assert_eq!(
2305 sum,
2306 ComplexValidated::try_new_complex(
2307 rug::Float::with_val(PRECISION, 1.),
2308 rug::Float::with_val(PRECISION, 2.)
2309 )
2310 .unwrap()
2311 );
2312 }
2313 } mod random {
2316 use super::*;
2317 use crate::{RandomSampleFromF64, new_random_vec};
2318 use rand::{Rng, SeedableRng, distr::Uniform, rngs::StdRng};
2319
2320 const PRECISION: u32 = 53;
2321
2322 type RealValidated = RealRugStrictFinite<PRECISION>;
2323 type ComplexValidated = ComplexRugStrictFinite<PRECISION>;
2324
2325 #[test]
2329 fn test_random_real_validated() {
2330 let seed = [42; 32];
2331 let mut rng = StdRng::from_seed(seed);
2332
2333 let random_real: RealValidated = rng.random();
2334
2335 assert_eq!(random_real, 0.23713468825474326);
2337
2338 let mut rng2 = StdRng::from_seed(seed);
2340 let random_real2: RealValidated = rng2.random();
2341 assert_eq!(random_real, random_real2);
2342 }
2343
2344 #[test]
2349 fn test_random_complex_validated() {
2350 let seed = [99; 32];
2351 let mut rng = StdRng::from_seed(seed);
2352
2353 let random_complex: ComplexValidated = rng.random();
2354
2355 let real_part = random_complex.real_part();
2358 let imag_part = random_complex.imag_part();
2359
2360 assert_eq!(real_part, 0.9995546882627792);
2361 assert_eq!(imag_part, 0.08932180682540247);
2362
2363 let mut rng2 = StdRng::from_seed(seed);
2365 let random_complex2: ComplexValidated = rng2.random();
2366 assert_eq!(random_complex, random_complex2);
2367 }
2368
2369 const SEED: [u8; 32] = [42; 32];
2370
2371 #[test]
2372 fn test_sample_real_validated() {
2373 let mut rng = StdRng::from_seed(SEED);
2374 let dist = Uniform::new(-10.0, 10.0).unwrap();
2375
2376 let val = RealValidated::sample_from(&dist, &mut rng);
2377 assert_eq!(val, -5.257306234905137);
2378
2379 let mut rng2 = StdRng::from_seed(SEED);
2381 let val2 = RealValidated::sample_from(&dist, &mut rng2);
2382 assert_eq!(val, val2);
2383 }
2384
2385 #[test]
2386 fn test_sample_complex_validated() {
2387 let mut rng = StdRng::from_seed(SEED);
2388 let dist = Uniform::new(-10.0, 10.0).unwrap();
2389
2390 let val = ComplexValidated::sample_from(&dist, &mut rng);
2391 assert_eq!(val.real_part(), -5.257306234905137);
2392 assert_eq!(val.imag_part(), 7.212119776268775);
2393
2394 let mut rng2 = StdRng::from_seed(SEED);
2396 let val2 = ComplexValidated::sample_from(&dist, &mut rng2);
2397 assert_eq!(val, val2);
2398 }
2399
2400 #[test]
2401 fn new_random_vec_real() {
2402 let mut rng = StdRng::from_seed(SEED);
2403 let dist = Uniform::new(-10.0, 10.0).unwrap();
2404 let vec: Vec<RealValidated> = new_random_vec(3, &dist, &mut rng);
2405 assert_eq!(vec.len(), 3);
2406 assert_eq!(vec[0], -5.257306234905137);
2407 assert_eq!(vec[1], 7.212119776268775);
2408 assert_eq!(vec[2], -4.666248990558111);
2409
2410 let mut rng2 = StdRng::from_seed(SEED);
2412 let vec2: Vec<RealValidated> = new_random_vec(3, &dist, &mut rng2);
2413 assert_eq!(vec, vec2);
2414 }
2415
2416 #[test]
2417 fn new_random_vec_complex() {
2418 let mut rng = StdRng::from_seed(SEED);
2419 let dist = Uniform::new(-10.0, 10.0).unwrap();
2420 let vec: Vec<ComplexValidated> = new_random_vec(3, &dist, &mut rng);
2421 assert_eq!(vec.len(), 3);
2422 assert_eq!(vec[0].real_part(), -5.257306234905137);
2423 assert_eq!(vec[0].imag_part(), 7.212119776268775);
2424 assert_eq!(vec[1].real_part(), -4.666248990558111);
2425 assert_eq!(vec[1].imag_part(), 9.66047141517383);
2426 assert_eq!(vec[2].real_part(), -9.04279551029691);
2427 assert_eq!(vec[2].imag_part(), -1.026624649331671);
2428
2429 let mut rng2 = StdRng::from_seed(SEED);
2431 let vec2: Vec<ComplexValidated> = new_random_vec(3, &dist, &mut rng2);
2432 assert_eq!(vec, vec2);
2433 }
2434 }
2435
2436 mod hash_map_key_usage {
2437 use super::*;
2438 use rug::Float;
2439 use std::collections::HashMap;
2440 use try_create::TryNew;
2441
2442 const PRECISION: u32 = 128;
2443 type RealRugValidated = RealRugStrictFinite<PRECISION>;
2444
2445 #[test]
2446 fn test_rug_as_hashmap_key() {
2447 let mut map = HashMap::new();
2448 let key1 = RealRugValidated::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
2449 let key2 = RealRugValidated::try_new(Float::with_val(PRECISION, 2.5)).unwrap();
2450
2451 map.insert(key1.clone(), "one_rug");
2452 map.insert(key2.clone(), "two_point_five_rug");
2453
2454 assert_eq!(map.get(&key1), Some(&"one_rug"));
2455 assert_eq!(map.len(), 2);
2456
2457 let old_value = map.insert(key1.clone(), "new_one_rug");
2459 assert_eq!(old_value, Some("one_rug"));
2460 assert_eq!(map.get(&key1), Some(&"new_one_rug"));
2461 }
2462
2463 #[test]
2464 fn test_hash_signed_zero() {
2465 use crate::functions::Sign;
2466 use std::collections::hash_map::DefaultHasher;
2467 use std::hash::{Hash, Hasher};
2468
2469 let val1 = RealRugValidated::try_new(Float::with_val(PRECISION, 0.0)).unwrap();
2470 assert!(val1.kernel_is_sign_positive());
2471 let val2 = RealRugValidated::try_new(Float::with_val(PRECISION, -0.0)).unwrap();
2472 assert!(val2.kernel_is_sign_negative());
2473
2474 let mut hasher1 = DefaultHasher::new();
2476 let mut hasher2 = DefaultHasher::new();
2477
2478 val1.hash(&mut hasher1);
2479 val2.hash(&mut hasher2);
2480
2481 assert_eq!(hasher1.finish(), hasher2.finish());
2482 assert_eq!(val1, val2); }
2484
2485 #[test]
2486 fn test_complex_as_hashmap_key() {
2487 use crate::ComplexRugStrictFinite;
2488 type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2489
2490 let mut map = HashMap::new();
2491 let key1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
2492 .unwrap();
2493 let key2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (3.0, 4.0)))
2494 .unwrap();
2495
2496 map.insert(key1.clone(), "one_plus_two_i_rug");
2497 map.insert(key2.clone(), "three_plus_four_i_rug");
2498
2499 assert_eq!(map.get(&key1), Some(&"one_plus_two_i_rug"));
2500 assert_eq!(map.len(), 2);
2501
2502 let old_value = map.insert(key1.clone(), "updated_complex_rug");
2504 assert_eq!(old_value, Some("one_plus_two_i_rug"));
2505 assert_eq!(map.get(&key1), Some(&"updated_complex_rug"));
2506 }
2507
2508 #[test]
2509 fn test_complex_hash_consistency() {
2510 use crate::ComplexRugStrictFinite;
2511 use std::collections::hash_map::DefaultHasher;
2512 use std::hash::{Hash, Hasher};
2513 type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2514
2515 let val1 =
2516 ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.234, 5.678)))
2517 .unwrap();
2518 let val2 =
2519 ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.234, 5.678)))
2520 .unwrap();
2521
2522 let mut hasher1 = DefaultHasher::new();
2524 let mut hasher2 = DefaultHasher::new();
2525
2526 val1.hash(&mut hasher1);
2527 val2.hash(&mut hasher2);
2528
2529 assert_eq!(hasher1.finish(), hasher2.finish());
2530 assert_eq!(val1, val2);
2531 }
2532
2533 #[test]
2534 fn test_complex_hash_signed_zero() {
2535 use crate::ComplexRugStrictFinite;
2536 use std::collections::hash_map::DefaultHasher;
2537 use std::hash::{Hash, Hasher};
2538 type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2539
2540 let val1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (0.0, 0.0)))
2542 .unwrap();
2543 let val2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (-0.0, 0.0)))
2544 .unwrap();
2545 let val3 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (0.0, -0.0)))
2546 .unwrap();
2547 let val4 =
2548 ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (-0.0, -0.0)))
2549 .unwrap();
2550
2551 assert_eq!(val1, val2);
2553 assert_eq!(val1, val3);
2554 assert_eq!(val1, val4);
2555
2556 let mut hasher1 = DefaultHasher::new();
2558 let mut hasher2 = DefaultHasher::new();
2559 let mut hasher3 = DefaultHasher::new();
2560 let mut hasher4 = DefaultHasher::new();
2561
2562 val1.hash(&mut hasher1);
2563 val2.hash(&mut hasher2);
2564 val3.hash(&mut hasher3);
2565 val4.hash(&mut hasher4);
2566
2567 let hash1 = hasher1.finish();
2568 let hash2 = hasher2.finish();
2569 let hash3 = hasher3.finish();
2570 let hash4 = hasher4.finish();
2571
2572 assert_eq!(hash1, hash2);
2573 assert_eq!(hash1, hash3);
2574 assert_eq!(hash1, hash4);
2575 }
2576
2577 #[test]
2578 fn test_complex_hashset_operations() {
2579 use crate::ComplexRugStrictFinite;
2580 use std::collections::HashSet;
2581 type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2582
2583 let mut set = HashSet::new();
2584
2585 let val1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
2586 .unwrap();
2587 let val2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (3.0, 4.0)))
2588 .unwrap();
2589 let val1_duplicate =
2590 ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
2591 .unwrap();
2592
2593 assert!(set.insert(val1.clone()));
2594 assert!(set.insert(val2.clone()));
2595 assert!(!set.insert(val1_duplicate)); assert_eq!(set.len(), 2);
2598 assert!(set.contains(&val1));
2599 }
2600
2601 #[test]
2602 fn test_complex_different_precision_different_hash() {
2603 use crate::ComplexRugStrictFinite;
2604 use std::collections::hash_map::DefaultHasher;
2605 use std::hash::{Hash, Hasher};
2606
2607 const PRECISION_A: u32 = 64;
2608 const PRECISION_B: u32 = 128;
2609
2610 let val1 = ComplexRugStrictFinite::<PRECISION_A>::try_new(rug::Complex::with_val(
2611 PRECISION_A,
2612 (1.0, 2.0),
2613 ))
2614 .unwrap();
2615 let val2 = ComplexRugStrictFinite::<PRECISION_B>::try_new(rug::Complex::with_val(
2616 PRECISION_B,
2617 (1.0, 2.0),
2618 ))
2619 .unwrap();
2620
2621 let mut hasher1 = DefaultHasher::new();
2623 let mut hasher2 = DefaultHasher::new();
2624
2625 val1.hash(&mut hasher1);
2626 val2.hash(&mut hasher2);
2627
2628 let hash1 = hasher1.finish();
2629 let hash2 = hasher2.finish();
2630
2631 assert_ne!(hash1, hash2);
2633 }
2634 }
2635
2636 mod rug_float {
2637
2638 mod from_f64 {
2639 use crate::{RealRugStrictFinite, RealScalar};
2640
2641 const PRECISION: u32 = 100;
2642
2643 #[test]
2644 fn test_from_f64_valid_constants() {
2645 let pi = RealRugStrictFinite::<PRECISION>::from_f64(std::f64::consts::PI);
2647 let pi_f64 = pi.as_ref().to_f64();
2648 assert!((pi_f64 - std::f64::consts::PI).abs() < 1e-15);
2649
2650 let e = RealRugStrictFinite::<PRECISION>::from_f64(std::f64::consts::E);
2651 let e_f64 = e.as_ref().to_f64();
2652 assert!((e_f64 - std::f64::consts::E).abs() < 1e-15);
2653 }
2654
2655 #[test]
2656 fn test_from_f64_valid_simple_values() {
2657 let x = RealRugStrictFinite::<PRECISION>::from_f64(42.0);
2659 assert_eq!(x.as_ref().to_f64(), 42.0);
2660
2661 let y = RealRugStrictFinite::<PRECISION>::from_f64(-3.0);
2662 assert_eq!(y.as_ref().to_f64(), -3.0);
2663
2664 let z = RealRugStrictFinite::<PRECISION>::from_f64(0.0);
2665 assert_eq!(z.as_ref().to_f64(), 0.0);
2666 }
2667
2668 #[test]
2669 #[should_panic(expected = "RealScalar::from_f64() failed")]
2670 fn test_from_f64_nan_panics() {
2671 let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::NAN);
2672 }
2673
2674 #[test]
2675 #[should_panic(expected = "RealScalar::from_f64() failed")]
2676 fn test_from_f64_infinity_panics() {
2677 let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::INFINITY);
2678 }
2679
2680 #[test]
2681 #[should_panic(expected = "RealScalar::from_f64() failed")]
2682 fn test_from_f64_neg_infinity_panics() {
2683 let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::NEG_INFINITY);
2684 }
2685
2686 #[test]
2687 fn test_try_from_f64_exact_representation() {
2688 use crate::core::errors::ErrorsTryFromf64;
2689
2690 assert!(
2694 RealRugStrictFinite::<PRECISION>::try_from_f64(0.1).is_ok(),
2695 "0.1 (as f64 approximation) should be accepted at 100-bit precision"
2696 );
2697 assert!(
2698 RealRugStrictFinite::<PRECISION>::try_from_f64(0.3).is_ok(),
2699 "0.3 (as f64 approximation) should be accepted at 100-bit precision"
2700 );
2701 assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).is_ok());
2702 assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(2.5).is_ok());
2703 assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).is_ok());
2704
2705 assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(f64::NAN).is_err());
2707 assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(f64::INFINITY).is_err());
2708
2709 match RealRugStrictFinite::<52>::try_from_f64(0.5) {
2711 Err(ErrorsTryFromf64::NonRepresentableExactly { precision, .. }) => {
2712 assert_eq!(precision, 52, "Error should report precision 52");
2713 }
2714 _ => panic!("Should reject precision < 53"),
2715 }
2716 }
2717 }
2718
2719 mod truncate_to_usize {
2720 use crate::core::errors::ErrorsRawRealToInteger;
2721 use crate::kernels::RawRealTrait;
2722 use rug::Float;
2723
2724 const PRECISION: u32 = 128;
2725
2726 #[test]
2727 fn test_rug_truncate_to_usize_valid() {
2728 assert_eq!(
2729 Float::with_val(PRECISION, 42.0)
2730 .truncate_to_usize()
2731 .unwrap(),
2732 42
2733 );
2734 assert_eq!(
2735 Float::with_val(PRECISION, 42.9)
2736 .truncate_to_usize()
2737 .unwrap(),
2738 42
2739 );
2740 assert_eq!(
2741 Float::with_val(PRECISION, 0.0).truncate_to_usize().unwrap(),
2742 0
2743 );
2744 assert_eq!(
2745 Float::with_val(PRECISION, usize::MAX)
2746 .truncate_to_usize()
2747 .unwrap(),
2748 usize::MAX
2749 );
2750 }
2751
2752 #[test]
2753 fn test_rug_truncate_to_usize_not_finite() {
2754 assert!(matches!(
2755 Float::with_val(PRECISION, f64::NAN).truncate_to_usize(),
2756 Err(ErrorsRawRealToInteger::NotFinite { .. })
2757 ));
2758 assert!(matches!(
2759 Float::with_val(PRECISION, f64::INFINITY).truncate_to_usize(),
2760 Err(ErrorsRawRealToInteger::NotFinite { .. })
2761 ));
2762 assert!(matches!(
2763 Float::with_val(PRECISION, f64::NEG_INFINITY).truncate_to_usize(),
2764 Err(ErrorsRawRealToInteger::NotFinite { .. })
2765 ));
2766 }
2767
2768 #[test]
2769 fn test_rug_truncate_to_usize_out_of_range() {
2770 assert!(matches!(
2772 Float::with_val(PRECISION, -1.0).truncate_to_usize(),
2773 Err(ErrorsRawRealToInteger::OutOfRange { .. })
2774 ));
2775
2776 let mut too_large = Float::with_val(PRECISION, usize::MAX);
2778 too_large += 1;
2779 assert!(matches!(
2780 too_large.truncate_to_usize(),
2781 Err(ErrorsRawRealToInteger::OutOfRange { .. })
2782 ));
2783 }
2784 }
2785 }
2786
2787 mod truncate_to_usize {
2788 use super::*;
2789 use rug::Float;
2790 use try_create::TryNew;
2791
2792 const PRECISION: u32 = 1000;
2793
2794 #[test]
2795 fn test_positive_integers() {
2796 let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 42.0))
2797 .unwrap();
2798 assert_eq!(value.truncate_to_usize().unwrap(), 42);
2799
2800 let value =
2801 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
2802 assert_eq!(value.truncate_to_usize().unwrap(), 1);
2803 }
2804
2805 #[test]
2806 fn test_positive_fractionals_truncate() {
2807 let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 42.9))
2808 .unwrap();
2809 assert_eq!(value.truncate_to_usize().unwrap(), 42);
2810
2811 let value =
2812 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.9)).unwrap();
2813 assert_eq!(value.truncate_to_usize().unwrap(), 0);
2814 }
2815
2816 #[test]
2817 fn test_zero_cases() {
2818 let value =
2819 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.0)).unwrap();
2820 assert_eq!(value.truncate_to_usize().unwrap(), 0);
2821 }
2822
2823 #[test]
2824 fn test_negative_values_error() {
2825 let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
2826 .unwrap();
2827 let result = value.truncate_to_usize();
2828 assert!(matches!(
2829 result,
2830 Err(ErrorsRawRealToInteger::OutOfRange { .. })
2831 ));
2832
2833 let value =
2834 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -10.5))
2835 .unwrap();
2836 let result = value.truncate_to_usize();
2837 assert!(matches!(
2838 result,
2839 Err(ErrorsRawRealToInteger::OutOfRange { .. })
2840 ));
2841 }
2842
2843 #[test]
2844 fn test_large_values() {
2845 let value =
2847 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1_000_000.0))
2848 .unwrap();
2849 assert_eq!(value.truncate_to_usize().unwrap(), 1_000_000);
2850
2851 let value = RealRugStrictFinite::<PRECISION>::try_new(
2853 Float::with_val(PRECISION, 1e50), )
2855 .unwrap();
2856 let result = value.truncate_to_usize();
2857 assert!(matches!(
2858 result,
2859 Err(ErrorsRawRealToInteger::OutOfRange { .. })
2860 ));
2861 }
2862
2863 #[test]
2864 fn test_high_precision_truncation() {
2865 let value = RealRugStrictFinite::<PRECISION>::try_new(
2867 Float::parse("42.99999999999999999999999999999")
2868 .unwrap()
2869 .complete(PRECISION),
2870 )
2871 .unwrap();
2872 assert_eq!(value.truncate_to_usize().unwrap(), 42);
2873
2874 let value = RealRugStrictFinite::<PRECISION>::try_new(
2876 Float::parse("0.99999999999999999999999999999")
2877 .unwrap()
2878 .complete(PRECISION),
2879 )
2880 .unwrap();
2881 assert_eq!(value.truncate_to_usize().unwrap(), 0);
2882 }
2883
2884 #[test]
2885 fn test_conversion_from_f64() {
2886 let value = RealRugStrictFinite::<PRECISION>::try_from_f64(42.7).unwrap();
2888 assert_eq!(value.truncate_to_usize().unwrap(), 42);
2889
2890 let value = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
2891 assert_eq!(value.truncate_to_usize().unwrap(), 0);
2892 }
2893 }
2894}