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: Box::new(error_real_part),
147 }),
148 (Ok(_), Err(error_imaginary_part)) => {
149 Err(ErrorsValidationRawComplex::InvalidImaginaryPart {
150 source: Box::new(error_imaginary_part),
151 })
152 }
153 (Err(error_real_part), Err(error_imaginary_part)) => {
154 Err(ErrorsValidationRawComplex::InvalidBothParts {
155 real_error: Box::new(error_real_part),
156 imag_error: Box::new(error_imaginary_part),
157 })
158 }
159 }
160 }
161}
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::{assert_matches, 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 err = 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 .unwrap_err();
573 assert_matches!(
574 err,
575 ErrorsValidationRawComplex::InvalidRealPart {
576 source
577 } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
578 );
579 }
580
581 #[test]
582 fn is_normal() {
583 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 1.0)).unwrap();
584 assert!(real.is_normal());
585
586 let real = RealRugStrictFinite::<53>::try_new(Float::with_val(53, 0.0)).unwrap();
587 assert!(!real.is_normal());
588
589 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
590 53,
591 (Float::with_val(53, 1.0), Float::with_val(53, 1.0)),
592 ))
593 .unwrap();
594 assert!(complex.is_normal());
595
596 let complex = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
597 53,
598 (Float::with_val(53, 0.0), Float::with_val(53, 0.0)),
599 ))
600 .unwrap();
601 assert!(!complex.is_normal());
602 }
603 }
604
605 mod abs {
606 use super::*;
607
608 mod real {
609 use super::*;
610
611 #[test]
612 fn abs_valid() {
613 let value =
614 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, -4.0)).unwrap();
615
616 let expected_result =
617 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 4.0)).unwrap();
618 assert_eq!(value.clone().try_abs().unwrap(), expected_result);
619 assert_eq!(value.abs(), expected_result);
620 }
621
622 #[test]
623 fn abs_zero() {
624 let value =
625 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
626
627 let expected_result =
628 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
629 assert_eq!(value.clone().try_abs().unwrap(), expected_result);
630 assert_eq!(value.abs(), expected_result);
631 }
632
633 }
657
658 mod complex {
659 use super::*;
660
661 #[test]
662 fn abs_valid() {
663 let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
664 53,
665 (rug::Float::with_val(53, 3.0), rug::Float::with_val(53, 4.0)),
666 ))
667 .unwrap();
668
669 let expected_result =
670 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 5.0)).unwrap();
671 assert_eq!(value.clone().try_abs().unwrap(), expected_result);
672 assert_eq!(value.abs(), expected_result);
673 }
674
675 #[test]
676 fn abs_zero() {
677 let value = ComplexRugStrictFinite::<53>::try_new(rug::Complex::with_val(
678 53,
679 (rug::Float::with_val(53, 0.0), rug::Float::with_val(53, 0.0)),
680 ))
681 .unwrap();
682
683 let expected_result =
684 RealRugStrictFinite::<53>::try_new(rug::Float::with_val(53, 0.0)).unwrap();
685 assert_eq!(value.clone().try_abs().unwrap(), expected_result);
686 assert_eq!(value.abs(), expected_result);
687 }
688 }
722 }
723
724 mod max_min {
725 use super::*;
726
727 #[test]
728 fn test_realrug_max() {
729 let value =
730 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
731 let other =
732 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
733 let expected =
734 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
735 assert_eq!(Max::max_by_ref(&value, &other), &expected);
736
737 let neg_value =
738 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
739 .unwrap();
740 let neg_other =
741 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
742 .unwrap();
743 let neg_expected =
744 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
745 .unwrap();
746 assert_eq!(Max::max_by_ref(&neg_value, &neg_other), &neg_expected);
747 }
748
749 #[test]
750 fn test_realrug_min() {
751 let value =
752 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
753 let other =
754 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 5.0)).unwrap();
755 let expected =
756 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 3.0)).unwrap();
757 assert_eq!(Min::min_by_ref(&value, &other), &expected);
758
759 let neg_value =
760 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -3.0))
761 .unwrap();
762 let neg_other =
763 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
764 .unwrap();
765 let neg_expected =
766 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -5.0))
767 .unwrap();
768 assert_eq!(Min::min_by_ref(&neg_value, &neg_other), &neg_expected);
769 }
770 }
771
772 mod builders {
773 use super::*;
774
775 mod real {
776 use super::*;
777
778 #[test]
779 fn try_new_nan() {
780 let nan = rug::Float::with_val(PRECISION, f64::NAN);
781 let err = RealRugStrictFinite::<PRECISION>::try_new(nan).unwrap_err();
782 assert!(matches!(err, ErrorsValidationRawReal::IsNaN { .. }));
783 }
784
785 #[test]
786 fn try_new_pos_infinity() {
787 let pos_infinity = rug::Float::with_val(PRECISION, f64::INFINITY);
788 let err = RealRugStrictFinite::<PRECISION>::try_new(pos_infinity).unwrap_err();
789 assert!(matches!(err, ErrorsValidationRawReal::IsPosInfinity { .. }));
790 }
791
792 #[test]
793 fn try_new_neg_infinity() {
794 let neg_infinity = rug::Float::with_val(PRECISION, f64::NEG_INFINITY);
795 let err = RealRugStrictFinite::<PRECISION>::try_new(neg_infinity).unwrap_err();
796 assert!(matches!(err, ErrorsValidationRawReal::IsNegInfinity { .. }));
797 }
798 }
799
800 mod complex {
801 use super::*;
802
803 #[test]
804 fn real_part() {
805 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
806 rug::Complex::with_val(PRECISION, (1.23, 4.56)),
807 )
808 .unwrap();
809 assert_eq!(c1.real_part(), 1.23);
810
811 let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
812 rug::Complex::with_val(PRECISION, (-7.89, 0.12)),
813 )
814 .unwrap();
815 assert_eq!(c2.real_part(), -7.89);
816
817 let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
818 rug::Complex::with_val(PRECISION, (0.0, 10.0)),
819 )
820 .unwrap();
821 assert_eq!(c3.real_part(), 0.0);
822
823 let c_nan_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
824 rug::Complex::with_val(PRECISION, (f64::NAN, 5.0)),
825 )
826 .unwrap_err();
827 assert_matches!(
828 c_nan_re,
829 ErrorsValidationRawComplex::InvalidRealPart {
830 source
831 } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
832 );
833
834 let c_inf_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
835 rug::Complex::with_val(PRECISION, (f64::INFINITY, 5.0)),
836 )
837 .unwrap_err();
838 assert_matches!(
839 c_inf_re,
840 ErrorsValidationRawComplex::InvalidRealPart {
841 source
842 } if matches!(*source, ErrorsValidationRawReal::IsPosInfinity { .. })
843 );
844
845 let c_neg_inf_re = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
846 rug::Complex::with_val(PRECISION, (f64::NEG_INFINITY, 5.0)),
847 )
848 .unwrap_err();
849 assert_matches!(
850 c_neg_inf_re,
851 ErrorsValidationRawComplex::InvalidRealPart {
852 source
853 } if matches!(*source, ErrorsValidationRawReal::IsNegInfinity { .. })
854 );
855 }
856
857 #[test]
858 fn imag_part() {
859 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
860 rug::Complex::with_val(PRECISION, (1.23, 4.56)),
861 )
862 .unwrap();
863 assert_eq!(c1.imag_part(), 4.56);
864
865 let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
866 rug::Complex::with_val(PRECISION, (-7.89, 0.12)),
867 )
868 .unwrap();
869 assert_eq!(c2.imag_part(), 0.12);
870
871 let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
872 rug::Complex::with_val(PRECISION, (10.0, 0.0)),
873 )
874 .unwrap();
875 assert_eq!(c3.imag_part(), 0.0);
876
877 let c_nan_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
878 rug::Complex::with_val(PRECISION, (5.0, f64::NAN)),
879 )
880 .unwrap_err();
881 assert_matches!(
882 c_nan_im,
883 ErrorsValidationRawComplex::InvalidImaginaryPart {
884 source
885 } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
886 );
887
888 let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
889 rug::Complex::with_val(PRECISION, (5.0, f64::INFINITY)),
890 )
891 .unwrap_err();
892 assert_matches!(
893 c_inf_im,
894 ErrorsValidationRawComplex::InvalidImaginaryPart {
895 source
896 } if matches!(*source, ErrorsValidationRawReal::IsPosInfinity { .. })
897 );
898
899 let c_neg_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
900 rug::Complex::with_val(PRECISION, (5.0, f64::NEG_INFINITY)),
901 )
902 .unwrap_err();
903 assert_matches!(
904 c_neg_inf_im,
905 ErrorsValidationRawComplex::InvalidImaginaryPart {
906 source
907 } if matches!(*source, ErrorsValidationRawReal::IsNegInfinity { .. })
908 );
909 }
910
911 #[test]
912 fn try_new_complex() {
913 let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
914 let i1 = RealRugStrictFinite::<PRECISION>::try_from_f64(4.56).unwrap();
915 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
916 r1.as_ref().clone(),
917 i1.as_ref().clone(),
918 )
919 .unwrap();
920 assert_eq!(c1.real_part(), r1);
921 assert_eq!(c1.imag_part(), i1);
922
923 let r2 = RealRugStrictFinite::<PRECISION>::try_from_f64(-7.89).unwrap();
924 let i2 = RealRugStrictFinite::<PRECISION>::try_from_f64(-0.12).unwrap();
925 let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
926 r2.as_ref().clone(),
927 i2.as_ref().clone(),
928 )
929 .unwrap();
930 assert_eq!(c2.real_part(), r2);
931 assert_eq!(c2.imag_part(), i2);
932
933 let r3 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
934 let i3 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
935 let c3 = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
936 r3.as_ref().clone(),
937 i3.as_ref().clone(),
938 )
939 .unwrap();
940 assert_eq!(c3.real_part(), r3);
941 assert_eq!(c3.real_part(), i3);
942 assert!(c3.is_zero());
943
944 let c_nan_re = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
945 Float::with_val(PRECISION, f64::NAN),
946 Float::with_val(PRECISION, 5.0),
947 )
948 .unwrap_err();
949 assert!(matches!(
950 c_nan_re,
951 ErrorsValidationRawComplex::InvalidRealPart { .. }
952 ));
953
954 let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
955 Float::with_val(PRECISION, 10.0),
956 Float::with_val(PRECISION, f64::INFINITY),
957 )
958 .unwrap_err();
959 assert!(matches!(
960 c_inf_im,
961 ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
962 ));
963
964 let c_nan_re_inf_im = ComplexRugStrictFinite::<PRECISION>::try_new_complex(
965 Float::with_val(PRECISION, f64::NAN),
966 Float::with_val(PRECISION, f64::INFINITY),
967 )
968 .unwrap_err();
969 assert!(matches!(
970 c_nan_re_inf_im,
971 ErrorsValidationRawComplex::InvalidBothParts { .. }
972 ));
973 }
974
975 #[test]
976 fn try_from_complexf64() {
977 let c1_in = num::Complex::new(1.23, 4.56);
978 let c1 = ComplexRugStrictFinite::<PRECISION>::try_from(c1_in).unwrap();
979 assert_eq!(c1.real_part(), c1_in.re);
980 assert_eq!(c1.imag_part(), c1_in.im);
981
982 let c2_in = num::Complex::new(-7.89, -0.12);
983 let c2 = ComplexRugStrictFinite::<PRECISION>::try_from(c2_in).unwrap();
984 assert_eq!(c2.real_part(), c2_in.re);
985 assert_eq!(c2.imag_part(), c2_in.im);
986
987 let c3_in = num::Complex::new(0., 0.);
988 let c3 = ComplexRugStrictFinite::<PRECISION>::try_from(c3_in).unwrap();
989 assert_eq!(c3.real_part(), c3_in.re);
990 assert_eq!(c3.imag_part(), c3_in.im);
991
992 let c_nan_re =
993 ComplexRugStrictFinite::<PRECISION>::try_from(num::Complex::new(f64::NAN, 5.0))
994 .unwrap_err();
995 assert!(matches!(
996 c_nan_re,
997 ErrorsValidationRawComplex::InvalidRealPart { .. }
998 ));
999
1000 let c_inf_im = ComplexRugStrictFinite::<PRECISION>::try_from(num::Complex::new(
1001 10.0,
1002 f64::INFINITY,
1003 ))
1004 .unwrap_err();
1005 assert!(matches!(
1006 c_inf_im,
1007 ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
1008 ));
1009
1010 let c_nan_re_inf_im = ComplexRugStrictFinite::<PRECISION>::try_from(
1011 num::Complex::new(f64::NAN, f64::INFINITY),
1012 )
1013 .unwrap_err();
1014 assert!(matches!(
1015 c_nan_re_inf_im,
1016 ErrorsValidationRawComplex::InvalidBothParts { .. }
1017 ));
1018 }
1019
1020 #[test]
1021 fn try_new_pure_real() {
1022 let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
1023 let c1 =
1024 ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(r1.as_ref().clone())
1025 .unwrap();
1026 assert_eq!(c1.real_part(), r1);
1027 assert!(c1.imag_part().is_zero());
1028
1029 let c_nan = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
1030 Float::with_val(PRECISION, f64::NAN),
1031 )
1032 .unwrap_err();
1033 assert_matches!(
1034 c_nan,
1035 ErrorsValidationRawComplex::InvalidRealPart {
1036 source
1037 } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
1038 );
1039 }
1040
1041 #[test]
1042 fn try_new_pure_imaginary() {
1043 let i1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.23).unwrap();
1044 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
1045 i1.as_ref().clone(),
1046 )
1047 .unwrap();
1048 assert!(c1.real_part().is_zero());
1049 assert_eq!(c1.imag_part(), i1);
1050
1051 let c_nan = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
1052 Float::with_val(PRECISION, f64::NAN),
1053 )
1054 .unwrap_err();
1055 assert_matches!(
1056 c_nan,
1057 ErrorsValidationRawComplex::InvalidImaginaryPart {
1058 source
1059 } if matches!(*source, ErrorsValidationRawReal::IsNaN { .. })
1060 );
1061 }
1062
1063 #[test]
1064 fn add_to_real_part() {
1065 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1066 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1067 )
1068 .unwrap();
1069 c.add_to_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1070 assert_eq!(c.real_part(), 4.0);
1071 assert_eq!(c.imag_part(), 2.0);
1072
1073 c.add_to_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0).unwrap());
1074 assert_eq!(c.real_part(), -1.0);
1075 assert_eq!(c.imag_part(), 2.0);
1076 }
1077
1078 #[test]
1079 fn add_to_imaginary_part() {
1080 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1081 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1082 )
1083 .unwrap();
1084 c.add_to_imaginary_part(
1085 &RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(),
1086 );
1087 assert_eq!(c.real_part(), 1.0);
1088 assert_eq!(c.imag_part(), 5.0);
1089
1090 c.add_to_imaginary_part(
1091 &RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap(),
1092 );
1093 assert_eq!(c.real_part(), 1.0);
1094 assert_eq!(c.imag_part(), 1.0);
1095 }
1096
1097 #[test]
1098 fn multiply_real_part() {
1099 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1100 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1101 )
1102 .unwrap();
1103 c.multiply_real_part(&RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1104 assert_eq!(c.real_part(), 3.0);
1105 assert_eq!(c.imag_part(), 2.0);
1106
1107 c.multiply_real_part(
1108 &RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap(),
1109 );
1110 assert_eq!(c.real_part(), -6.0);
1111 assert_eq!(c.imag_part(), 2.0);
1112 }
1113
1114 #[test]
1115 fn multiply_imaginary_part() {
1116 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1117 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1118 )
1119 .unwrap();
1120 c.multiply_imaginary_part(
1121 &RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap(),
1122 );
1123 assert_eq!(c.real_part(), 1.0);
1124 assert_eq!(c.imag_part(), 6.0);
1125
1126 c.multiply_imaginary_part(
1127 &RealRugStrictFinite::<PRECISION>::try_from_f64(-0.5).unwrap(),
1128 );
1129 assert_eq!(c.real_part(), 1.0);
1130 assert_eq!(c.imag_part(), -3.0);
1131 }
1132
1133 #[test]
1134 fn set_real_part() {
1135 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1136 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1137 )
1138 .unwrap();
1139 c.set_real_part(RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1140 assert_eq!(c.real_part(), 3.0);
1141 assert_eq!(c.imag_part(), 2.0);
1142
1143 c.set_real_part(RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap());
1144 assert_eq!(c.real_part(), -4.0);
1145 assert_eq!(c.imag_part(), 2.0);
1146 }
1147
1148 #[test]
1149 fn set_imaginary_part() {
1150 let mut c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1151 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1152 )
1153 .unwrap();
1154 c.set_imaginary_part(RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap());
1155 assert_eq!(c.real_part(), 1.0);
1156 assert_eq!(c.imag_part(), 3.0);
1157
1158 c.set_imaginary_part(RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap());
1159 assert_eq!(c.real_part(), 1.0);
1160 assert_eq!(c.imag_part(), -4.0);
1161 }
1162 }
1163 }
1164
1165 mod mul {
1166 use super::*;
1167
1168 mod real {
1169 use super::*;
1170
1171 #[test]
1172 fn multiply_ref() {
1173 let r1 = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1174 PRECISION, 3.0,
1175 ))
1176 .unwrap();
1177 let r2 = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1178 PRECISION, 4.0,
1179 ))
1180 .unwrap();
1181 let result = r1 * &r2;
1182 assert_eq!(
1183 result,
1184 RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1185 PRECISION, 12.0
1186 ))
1187 .unwrap()
1188 );
1189 }
1190 }
1191
1192 mod complex {
1193 use super::*;
1194
1195 #[test]
1196 fn multiply_ref() {
1197 let c1 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1198 rug::Complex::with_val(PRECISION, (1.0, 2.0)),
1199 )
1200 .unwrap();
1201 let c2 = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1202 rug::Complex::with_val(PRECISION, (3.0, 4.0)),
1203 )
1204 .unwrap();
1205 let result = c1 * &c2;
1206 assert_eq!(
1207 result,
1208 ComplexRugStrictFinite::<PRECISION>::try_new_validated(rug::Complex::with_val(
1209 PRECISION,
1210 (-5.0, 10.0),
1211 ))
1212 .unwrap()
1213 ); }
1215
1216 #[test]
1217 fn complex_times_real() {
1218 let r = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1219 PRECISION, 2.0,
1220 ))
1221 .unwrap();
1222 let c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1223 rug::Complex::with_val(PRECISION, (3.0, 4.0)),
1224 )
1225 .unwrap();
1226
1227 let result_expected = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1228 rug::Complex::with_val(PRECISION, (6.0, 8.0)),
1229 )
1230 .unwrap(); let result = c.clone() * &r;
1233 assert_eq!(&result, &result_expected);
1234
1235 let result = c.clone() * r.clone();
1236 assert_eq!(&result, &result_expected);
1237
1238 let mut result = c.clone();
1239 result *= &r;
1240 assert_eq!(&result, &result_expected);
1241
1242 let mut result = c.clone();
1243 result *= r;
1244 assert_eq!(&result, &result_expected);
1245 }
1246
1247 #[test]
1248 fn real_times_complex() {
1249 let r = RealRugStrictFinite::<PRECISION>::try_new_validated(rug::Float::with_val(
1250 PRECISION, 2.0,
1251 ))
1252 .unwrap();
1253 let c = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1254 rug::Complex::with_val(PRECISION, (3.0, 4.0)),
1255 )
1256 .unwrap();
1257
1258 let result_expected = ComplexRugStrictFinite::<PRECISION>::try_new_validated(
1259 rug::Complex::with_val(PRECISION, (6.0, 8.0)),
1260 )
1261 .unwrap(); let result = &r * c.clone();
1264 assert_eq!(&result, &result_expected);
1265
1266 let result = r * c.clone();
1267 assert_eq!(&result, &result_expected);
1268 }
1269 }
1270 }
1271
1272 mod arithmetic {
1273 use super::*;
1274
1275 mod real {
1276 use super::*;
1277
1278 #[test]
1279 fn neg_assign() {
1280 let mut a = rug::Float::with_val(PRECISION, 1.);
1281 a.neg_assign();
1282 let a_expected = rug::Float::with_val(PRECISION, -1.);
1283 assert_eq!(a, a_expected);
1284
1285 let mut b = RealRugStrictFinite::<PRECISION>::one();
1286 b.neg_assign();
1287 let b_expected = RealRugStrictFinite::<PRECISION>::try_new_validated(
1288 rug::Float::with_val(PRECISION, -1.),
1289 )
1290 .unwrap();
1291 assert_eq!(&b, &b_expected);
1292 }
1293
1294 #[test]
1295 #[should_panic(expected = "Division failed validation")]
1296 fn div_by_zero() {
1297 let one = RealRugStrictFinite::<PRECISION>::one();
1298 let zero = RealRugStrictFinite::<PRECISION>::zero();
1299 let _ = &one / &zero;
1300 }
1301
1302 #[test]
1303 #[should_panic(expected = "Division failed validation")]
1304 fn div_assign_by_zero() {
1305 let mut num = RealRugStrictFinite::<PRECISION>::one();
1306 let zero_ref = &RealRugStrictFinite::<PRECISION>::zero();
1307 num /= zero_ref;
1308 }
1309 }
1310
1311 mod complex {
1312 use super::*;
1313
1314 #[test]
1315 fn neg_assign() {
1316 let re = rug::Float::with_val(PRECISION, 1.);
1317 let im = rug::Float::with_val(PRECISION, 2.);
1318 let mut num = rug::Complex::with_val(PRECISION, (re, im));
1319 num.neg_assign();
1320 let expected = rug::Complex::with_val(
1321 PRECISION,
1322 (
1323 rug::Float::with_val(PRECISION, -1.),
1324 rug::Float::with_val(PRECISION, -2.),
1325 ),
1326 );
1327 assert_eq!(&num, &expected);
1328
1329 let mut num = ComplexRugStrictFinite::<PRECISION>::try_new_validated(num).unwrap();
1330 let expected = num.clone().neg();
1331 num.neg_assign();
1332 assert_eq!(&num, &expected);
1333 }
1334
1335 #[test]
1336 #[should_panic(expected = "Division failed validation")]
1337 fn div_by_zero() {
1338 let one = ComplexRugStrictFinite::<PRECISION>::one();
1339 let zero = ComplexRugStrictFinite::<PRECISION>::zero();
1340 let _ = &one / &zero;
1341 }
1342
1343 #[test]
1344 #[should_panic(expected = "Division failed validation")]
1345 fn div_assign_by_zero() {
1346 let mut num = ComplexRugStrictFinite::<PRECISION>::one();
1347 let zero_ref = &ComplexRugStrictFinite::<PRECISION>::zero();
1348 num /= zero_ref;
1349 }
1350 }
1351 }
1352
1353 mod real_scalar_methods {
1354 use super::*;
1355
1356 #[test]
1357 fn epsilon() {
1358 let eps = RealRugStrictFinite::<PRECISION>::epsilon();
1359 assert!(eps.is_finite() && eps > RealRugStrictFinite::<PRECISION>::zero());
1360 let expected_eps_val =
1361 rug::Float::with_val(PRECISION, 2.0).pow(1i32 - PRECISION as i32);
1362 let expected_eps = RealRugStrictFinite::<PRECISION>::try_new(expected_eps_val).unwrap();
1363 assert_eq!(eps, expected_eps, "Epsilon value mismatch");
1364 }
1365
1366 #[test]
1367 fn clamp_ref() {
1368 let val = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap();
1369 let min_val = RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).unwrap();
1370 let max_val = RealRugStrictFinite::<PRECISION>::try_from_f64(10.0).unwrap();
1371
1372 assert_eq!(val.clone().clamp_ref(&min_val, &max_val), val);
1373 assert_eq!(
1374 RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0)
1375 .unwrap()
1376 .clamp_ref(&min_val, &max_val),
1377 min_val
1378 );
1379 assert_eq!(
1380 RealRugStrictFinite::<PRECISION>::try_from_f64(15.0)
1381 .unwrap()
1382 .clamp_ref(&min_val, &max_val),
1383 max_val
1384 );
1385 }
1386
1387 #[test]
1388 fn hypot() {
1389 let a = RealRugStrictFinite::<PRECISION>::try_from_f64(3.0).unwrap();
1390 let b = RealRugStrictFinite::<PRECISION>::try_from_f64(4.0).unwrap();
1391 let expected = RealRugStrictFinite::<PRECISION>::try_from_f64(5.0).unwrap();
1392 assert_eq!(a.hypot(&b), expected);
1393 }
1394
1395 #[test]
1396 fn signum() {
1397 assert_eq!(
1398 RealRugStrictFinite::<PRECISION>::try_from_f64(5.0)
1399 .unwrap()
1400 .kernel_signum(),
1401 RealRugStrictFinite::<PRECISION>::one()
1402 );
1403 assert_eq!(
1404 RealRugStrictFinite::<PRECISION>::try_from_f64(-5.0)
1405 .unwrap()
1406 .kernel_signum(),
1407 RealRugStrictFinite::<PRECISION>::negative_one()
1408 );
1409 assert_eq!(
1411 RealRugStrictFinite::<PRECISION>::zero().kernel_signum(),
1412 RealRugStrictFinite::<PRECISION>::one()
1413 );
1414 }
1415
1416 #[test]
1417 fn total_cmp() {
1418 let r1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0).unwrap();
1419 let r2 = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1420 assert_eq!(r1.total_cmp(&r1), Ordering::Equal);
1421 assert_eq!(r1.total_cmp(&r2), Ordering::Less);
1422 assert_eq!(r2.total_cmp(&r1), Ordering::Greater);
1423 }
1424
1425 #[test]
1426 fn mul_add_mul_mut() {
1427 let mut a = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1428 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);
1433 assert_eq!(
1434 a,
1435 RealRugStrictFinite::<PRECISION>::try_from_f64(26.0).unwrap()
1436 );
1437 }
1438
1439 #[test]
1440 fn mul_sub_mul_mut() {
1441 let mut a = RealRugStrictFinite::<PRECISION>::try_from_f64(10.0).unwrap();
1442 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);
1447 assert_eq!(
1448 a,
1449 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1450 );
1451 }
1452
1453 #[test]
1454 fn test_real_rug_constants() {
1455 let raw_float = |f: f64| Float::with_val(PRECISION, f);
1457
1458 let pi = RealRugStrictFinite::<PRECISION>::pi();
1460 let expected_pi = Float::with_val(PRECISION, MpfrConstant::Pi);
1461 assert_eq!(pi.as_ref(), &expected_pi);
1462
1463 let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
1465 let expected_two_pi = Float::with_val(PRECISION, MpfrConstant::Pi) * 2;
1466 assert_eq!(two_pi.as_ref(), &expected_two_pi);
1467
1468 let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1470 let expected_pi_div_2 = Float::with_val(PRECISION, MpfrConstant::Pi) / 2;
1471 assert_eq!(pi_div_2.as_ref(), &expected_pi_div_2);
1472
1473 let e = RealRugStrictFinite::<PRECISION>::e();
1475 let expected_e = raw_float(1.0).exp();
1476 assert_eq!(e.as_ref(), &expected_e);
1477
1478 let log2_e = RealRugStrictFinite::<PRECISION>::log2_e();
1480 let expected_log2_e = Float::with_val(PRECISION, MpfrConstant::Log2).recip();
1481 assert_eq!(log2_e.as_ref(), &expected_log2_e);
1482
1483 let log10_e = RealRugStrictFinite::<PRECISION>::log10_e();
1485 let ln2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1486 let log2_10 = raw_float(10.0).log2();
1487 let expected_log10_e = (ln2 * log2_10).recip();
1488 assert_eq!(log10_e.as_ref(), &expected_log10_e);
1489
1490 let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1492 let expected_ln_2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1493 assert_eq!(ln_2.as_ref(), &expected_ln_2);
1494
1495 let ln_10 = RealRugStrictFinite::<PRECISION>::ln_10();
1497 let ln2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1498 let log2_10 = raw_float(10.0).log2();
1499 let expected_ln_10 = ln2 * log2_10;
1500 assert_eq!(ln_10.as_ref(), &expected_ln_10);
1501
1502 let log2_10 = RealRugStrictFinite::<PRECISION>::log2_10();
1504 let expected_log2_10 = raw_float(10.0).log2();
1505 assert_eq!(log2_10.as_ref(), &expected_log2_10);
1506
1507 let log10_2 = RealRugStrictFinite::<PRECISION>::log10_2();
1509 let expected_log10_2 = raw_float(2.0).log10();
1510 assert_eq!(log10_2.as_ref(), &expected_log10_2);
1511
1512 let max_finite = RealRugStrictFinite::<PRECISION>::max_finite();
1514 let expected_max_finite = <rug::Float as RawRealTrait>::raw_max_finite(PRECISION);
1515 assert_eq!(max_finite.as_ref(), &expected_max_finite);
1516
1517 let min_finite = RealRugStrictFinite::<PRECISION>::min_finite();
1519 let expected_min_finite = <rug::Float as RawRealTrait>::raw_min_finite(PRECISION);
1520 assert_eq!(min_finite.as_ref(), &expected_min_finite);
1521
1522 let epsilon = RealRugStrictFinite::<PRECISION>::epsilon();
1524 let expected_epsilon = <rug::Float as RawRealTrait>::raw_epsilon(PRECISION);
1525 assert_eq!(epsilon.as_ref(), &expected_epsilon);
1526
1527 assert_eq!(
1529 RealRugStrictFinite::<PRECISION>::negative_one().as_ref(),
1530 &raw_float(-1.0)
1531 );
1532
1533 assert_eq!(
1535 RealRugStrictFinite::<PRECISION>::two().as_ref(),
1536 &raw_float(2.0)
1537 );
1538
1539 assert_eq!(
1541 RealRugStrictFinite::<PRECISION>::one_div_2().as_ref(),
1542 &raw_float(0.5)
1543 );
1544 }
1545
1546 #[test]
1550 fn test_real_rug_constants_mpfr_optimization() {
1551 let pi = RealRugStrictFinite::<PRECISION>::pi();
1553 let expected_pi = Float::with_val(PRECISION, MpfrConstant::Pi);
1554 assert_eq!(pi.as_ref(), &expected_pi);
1555
1556 let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1558 let expected_ln_2 = Float::with_val(PRECISION, MpfrConstant::Log2);
1559 assert_eq!(ln_2.as_ref(), &expected_ln_2);
1560
1561 let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
1563 let expected_two_pi = Float::with_val(PRECISION, MpfrConstant::Pi) * 2;
1564 assert_eq!(two_pi.as_ref(), &expected_two_pi);
1565
1566 let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1567 let expected_pi_div_2 = Float::with_val(PRECISION, MpfrConstant::Pi) / 2;
1568 assert_eq!(pi_div_2.as_ref(), &expected_pi_div_2);
1569 }
1570
1571 #[test]
1573 fn test_real_rug_constants_precision_independence() {
1574 type Real100 = RealRugStrictFinite<100>;
1575 type Real200 = RealRugStrictFinite<200>;
1576 type Real500 = RealRugStrictFinite<500>;
1577
1578 let pi_100 = Real100::pi();
1580 let pi_200 = Real200::pi();
1581 let pi_500 = Real500::pi();
1582
1583 let pi_100_f64 = pi_100.as_ref().to_f64();
1586 let pi_200_f64 = pi_200.as_ref().to_f64();
1587 let pi_500_f64 = pi_500.as_ref().to_f64();
1588
1589 let pi_expected = std::f64::consts::PI;
1590 assert!((pi_100_f64 - pi_expected).abs() < 1e-15);
1591 assert!((pi_200_f64 - pi_expected).abs() < 1e-15);
1592 assert!((pi_500_f64 - pi_expected).abs() < 1e-15);
1593
1594 let e_100 = Real100::e();
1596 let e_200 = Real200::e();
1597
1598 let e_100_f64 = e_100.as_ref().to_f64();
1599 let e_200_f64 = e_200.as_ref().to_f64();
1600
1601 let e_expected = std::f64::consts::E;
1602 assert!((e_100_f64 - e_expected).abs() < 1e-15);
1603 assert!((e_200_f64 - e_expected).abs() < 1e-15);
1604 }
1605
1606 #[test]
1608 fn test_real_rug_constants_mathematical_relationships() {
1609 let pi = RealRugStrictFinite::<PRECISION>::pi();
1610 let two_pi = RealRugStrictFinite::<PRECISION>::two_pi();
1611 let pi_div_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1612
1613 let expected_two_pi = pi.as_ref() * Float::with_val(PRECISION, 2);
1615 assert_eq!(two_pi.as_ref(), &expected_two_pi);
1616
1617 let expected_pi_div_2 = pi.as_ref() / Float::with_val(PRECISION, 2);
1619 assert_eq!(pi_div_2.as_ref(), &expected_pi_div_2);
1620
1621 let ln_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1622 let ln_10 = RealRugStrictFinite::<PRECISION>::ln_10();
1623 let log2_e = RealRugStrictFinite::<PRECISION>::log2_e();
1624 let log10_e = RealRugStrictFinite::<PRECISION>::log10_e();
1625
1626 let product = (log2_e.as_ref() * ln_2.as_ref()).complete(PRECISION);
1628 let one = Float::with_val(PRECISION, 1);
1629 let epsilon = Float::with_val(PRECISION, 1e-10);
1630 let diff = (product - &one).abs();
1631 assert!(diff < epsilon);
1632
1633 let product = (log10_e.as_ref() * ln_10.as_ref()).complete(PRECISION);
1635 let diff = (product - &one).abs();
1636 assert!(diff < epsilon);
1637 }
1638
1639 #[test]
1642 fn test_real_rug_constants_consistency() {
1643 let pi1 = RealRugStrictFinite::<PRECISION>::pi();
1645 let pi2 = RealRugStrictFinite::<PRECISION>::pi();
1646 assert_eq!(pi1.as_ref(), pi2.as_ref());
1647
1648 let e1 = RealRugStrictFinite::<PRECISION>::e();
1649 let e2 = RealRugStrictFinite::<PRECISION>::e();
1650 assert_eq!(e1.as_ref(), e2.as_ref());
1651
1652 let ln2_1 = RealRugStrictFinite::<PRECISION>::ln_2();
1653 let ln2_2 = RealRugStrictFinite::<PRECISION>::ln_2();
1654 assert_eq!(ln2_1.as_ref(), ln2_2.as_ref());
1655
1656 let two_pi1 = RealRugStrictFinite::<PRECISION>::two_pi();
1657 let two_pi2 = RealRugStrictFinite::<PRECISION>::two_pi();
1658 assert_eq!(two_pi1.as_ref(), two_pi2.as_ref());
1659
1660 let pi_div_2_1 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1661 let pi_div_2_2 = RealRugStrictFinite::<PRECISION>::pi_div_2();
1662 assert_eq!(pi_div_2_1.as_ref(), pi_div_2_2.as_ref());
1663 }
1664 }
1665
1666 mod scalar_constructors {
1667 use super::*;
1668 use crate::{
1669 core::errors::ErrorsValidationRawReal,
1670 functions::{
1671 ATan2InputErrors, LogarithmRealErrors, LogarithmRealInputErrors,
1672 PowComplexBaseRealExponentInputErrors, PowRealBaseRealExponentInputErrors,
1673 ReciprocalInputErrors, SqrtRealInputErrors,
1674 },
1675 };
1676
1677 mod real {
1678 use super::*;
1679
1680 #[test]
1681 fn exp_overflow() {
1682 let large_val = RealRugStrictFinite::<PRECISION>::try_from_f64(1.0e60).unwrap(); let res_large = large_val.try_exp();
1684 assert!(matches!(
1685 res_large,
1686 Err(ExpErrors::Output {
1687 source: ErrorsValidationRawReal::IsPosInfinity { .. }
1688 })
1689 ),);
1690 }
1691
1692 #[test]
1693 fn ln_domain_errors() {
1694 let neg_val = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.0).unwrap();
1695 assert!(matches!(
1696 neg_val.try_ln(),
1697 Err(LogarithmRealErrors::Input {
1698 source: LogarithmRealInputErrors::NegativeArgument { .. }
1699 })
1700 ));
1701
1702 let zero_val = RealRugStrictFinite::<PRECISION>::zero();
1703 assert!(matches!(
1704 zero_val.try_ln(),
1705 Err(LogarithmRealErrors::Input {
1706 source: LogarithmRealInputErrors::ZeroArgument { .. }
1707 })
1708 ));
1709 }
1710 } mod complex {
1713 use super::*;
1714
1715 #[test]
1716 fn log2_zero() {
1717 let zero_val = ComplexRugStrictFinite::<PRECISION>::zero();
1718 assert!(matches!(
1719 zero_val.try_log2(),
1720 Err(LogarithmComplexErrors::Input {
1721 source: LogarithmComplexInputErrors::ZeroArgument { .. }
1722 })
1723 ));
1724 }
1725 } mod pow {
1728 use super::*;
1729
1730 mod real_base {
1731 use super::*;
1732
1733 #[test]
1734 fn negative_base_real_exponent_error() {
1735 let base = RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap();
1736 let exponent = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
1737 let res = base.try_pow(&exponent);
1738 assert!(matches!(
1739 res,
1740 Err(PowRealBaseRealExponentErrors::Input {
1741 source: PowRealBaseRealExponentInputErrors::NegativeBase { .. }
1742 })
1743 ));
1744 }
1745
1746 #[test]
1747 fn real_base_uint_exponent() {
1748 let base = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1749 assert_eq!(
1750 base.clone().try_pow(3u8).unwrap(),
1751 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1752 );
1753 assert_eq!(
1754 base.clone().try_pow(3u16).unwrap(),
1755 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1756 );
1757 assert_eq!(
1758 base.clone().try_pow(3u32).unwrap(),
1759 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1760 );
1761 assert_eq!(
1762 base.clone().try_pow(3u64).unwrap(),
1763 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1764 );
1765 assert_eq!(
1766 base.clone().try_pow(3u128).unwrap(),
1767 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1768 );
1769 assert_eq!(
1770 base.clone().try_pow(3usize).unwrap(),
1771 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1772 );
1773
1774 assert_eq!(
1775 base.clone().pow(3u8),
1776 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1777 );
1778 assert_eq!(
1779 base.clone().pow(3u16),
1780 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1781 );
1782 assert_eq!(
1783 base.clone().pow(3u32),
1784 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1785 );
1786 assert_eq!(
1787 base.clone().pow(3u64),
1788 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1789 );
1790 assert_eq!(
1791 base.clone().pow(3u128),
1792 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1793 );
1794 assert_eq!(
1795 base.clone().pow(3usize),
1796 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1797 );
1798 }
1799
1800 #[test]
1801 fn real_base_int_exponent() {
1802 let base = RealRugStrictFinite::<PRECISION>::try_from_f64(2.0).unwrap();
1803 assert_eq!(
1804 base.clone().try_pow(3i8).unwrap(),
1805 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1806 );
1807 assert_eq!(
1808 base.clone().try_pow(3i16).unwrap(),
1809 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1810 );
1811 assert_eq!(
1812 base.clone().try_pow(3i32).unwrap(),
1813 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1814 );
1815 assert_eq!(
1816 base.clone().try_pow(3i64).unwrap(),
1817 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1818 );
1819 assert_eq!(
1820 base.clone().try_pow(3i128).unwrap(),
1821 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1822 );
1823 assert_eq!(
1824 base.clone().try_pow(3isize).unwrap(),
1825 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1826 );
1827
1828 assert_eq!(
1829 base.clone().pow(3i8),
1830 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1831 );
1832 assert_eq!(
1833 base.clone().pow(3i16),
1834 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1835 );
1836 assert_eq!(
1837 base.clone().pow(3i32),
1838 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1839 );
1840 assert_eq!(
1841 base.clone().pow(3i64),
1842 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1843 );
1844 assert_eq!(
1845 base.clone().pow(3i128),
1846 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1847 );
1848 assert_eq!(
1849 base.clone().pow(3isize),
1850 RealRugStrictFinite::<PRECISION>::try_from_f64(8.0).unwrap()
1851 );
1852 }
1853
1854 #[test]
1855 fn real_base_int_exponent_zero_neg_exp_error() {
1856 let base = RealRugStrictFinite::<PRECISION>::zero();
1857 let exponent: i32 = -2;
1858 let res = base.try_pow(exponent);
1859 assert!(matches!(
1860 res,
1861 Err(PowIntExponentErrors::Input {
1862 source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
1863 })
1864 ));
1865 }
1866 }
1867
1868 mod complex_base {
1869 use super::*;
1870
1871 #[test]
1872 fn complex_base_uint_exponent() {
1873 let base = ComplexRugStrictFinite::<PRECISION>::try_new(
1874 rug::Complex::with_val(PRECISION, (2.0, 3.0)),
1875 )
1876 .unwrap();
1877 let expected_res = ComplexRugStrictFinite::<PRECISION>::try_new(
1878 rug::Complex::with_val(PRECISION, (-46.0, 9.0)),
1879 )
1880 .unwrap();
1881
1882 assert_eq!(&base.clone().try_pow(3u8).unwrap(), &expected_res);
1883 assert_eq!(&base.clone().try_pow(3u16).unwrap(), &expected_res);
1884 assert_eq!(&base.clone().try_pow(3u32).unwrap(), &expected_res);
1885 assert_eq!(&base.clone().try_pow(3u64).unwrap(), &expected_res);
1886 assert_eq!(&base.clone().try_pow(3u128).unwrap(), &expected_res);
1887 assert_eq!(&base.clone().try_pow(3usize).unwrap(), &expected_res);
1888
1889 assert_eq!(&base.clone().pow(3u8), &expected_res);
1890 assert_eq!(&base.clone().pow(3u16), &expected_res);
1891 assert_eq!(&base.clone().pow(3u32), &expected_res);
1892 assert_eq!(&base.clone().pow(3u64), &expected_res);
1893 assert_eq!(&base.clone().pow(3u128), &expected_res);
1894 assert_eq!(&base.clone().pow(3usize), &expected_res);
1895 }
1896
1897 #[test]
1898 fn complex_base_int_exponent() {
1899 let base = ComplexRugStrictFinite::<PRECISION>::try_new(
1900 rug::Complex::with_val(PRECISION, (2.0, 3.0)),
1901 )
1902 .unwrap();
1903 let expected_res = ComplexRugStrictFinite::<PRECISION>::try_new(
1904 rug::Complex::with_val(PRECISION, (-46.0, 9.0)),
1905 )
1906 .unwrap();
1907
1908 assert_eq!(&base.clone().try_pow(3i8).unwrap(), &expected_res);
1909 assert_eq!(&base.clone().try_pow(3i16).unwrap(), &expected_res);
1910 assert_eq!(&base.clone().try_pow(3i32).unwrap(), &expected_res);
1911 assert_eq!(&base.clone().try_pow(3i64).unwrap(), &expected_res);
1912 assert_eq!(&base.clone().try_pow(3i128).unwrap(), &expected_res);
1913 assert_eq!(&base.clone().try_pow(3isize).unwrap(), &expected_res);
1914
1915 assert_eq!(&base.clone().pow(3i8), &expected_res);
1916 assert_eq!(&base.clone().pow(3i16), &expected_res);
1917 assert_eq!(&base.clone().pow(3i32), &expected_res);
1918 assert_eq!(&base.clone().pow(3i64), &expected_res);
1919 assert_eq!(&base.clone().pow(3i128), &expected_res);
1920 assert_eq!(&base.clone().pow(3isize), &expected_res);
1921 }
1922
1923 #[test]
1924 fn complex_zero_base_negative_real_exponent_error() {
1925 let base = ComplexRugStrictFinite::<PRECISION>::zero();
1926 let exponent = RealRugStrictFinite::<PRECISION>::try_from_f64(-2.0).unwrap();
1927 let res = base.try_pow(&exponent);
1928 assert!(matches!(
1929 res,
1930 Err(PowComplexBaseRealExponentErrors::Input {
1931 source:
1932 PowComplexBaseRealExponentInputErrors::ZeroBaseNegativeExponent { .. }
1933 })
1934 ));
1935 }
1936
1937 #[test]
1938 fn complex_zero_base_zero_real_exponent() {
1939 let base = ComplexRugStrictFinite::<PRECISION>::zero();
1940 let exponent = RealRugStrictFinite::<PRECISION>::zero();
1941 let res = base.try_pow(&exponent).unwrap();
1942 assert_eq!(res, ComplexRugStrictFinite::<PRECISION>::one());
1943 }
1944
1945 #[test]
1946 fn complex_base_int_exponent_zero_neg_exp_error() {
1947 let base = ComplexRugStrictFinite::<PRECISION>::zero();
1948 let exponent: i32 = -2;
1949 let res = base.try_pow(exponent);
1950 assert!(matches!(
1951 res,
1952 Err(PowIntExponentErrors::Input {
1953 source: PowIntExponentInputErrors::ZeroBaseNegativeExponent { .. }
1954 })
1955 ));
1956 }
1957 }
1958 }
1959
1960 #[test]
1961 fn reciprocal_real_rug_zero() {
1962 let zero_val = RealRugStrictFinite::<PRECISION>::zero();
1963 let res = zero_val.try_reciprocal();
1964 assert!(matches!(
1965 res,
1966 Err(ReciprocalErrors::Input {
1967 source: ReciprocalInputErrors::DivisionByZero { .. }
1968 })
1969 ));
1970 }
1971
1972 #[test]
1973 fn reciprocal_complex_rug_zero() {
1974 let zero_val = ComplexRugStrictFinite::<PRECISION>::zero();
1975 let res = zero_val.try_reciprocal();
1976 assert!(matches!(
1977 res,
1978 Err(ReciprocalErrors::Input {
1979 source: ReciprocalInputErrors::DivisionByZero { .. }
1980 })
1981 ));
1982 }
1983
1984 #[test]
1985 fn sqrt_real_rug_negative_input() {
1986 let neg_val = RealRugStrictFinite::<PRECISION>::try_from_f64(-4.0).unwrap();
1987 let res = neg_val.try_sqrt();
1988 assert!(matches!(
1989 res,
1990 Err(SqrtRealErrors::Input {
1991 source: SqrtRealInputErrors::NegativeValue { .. }
1992 })
1993 ));
1994 }
1995
1996 mod trigonometric {
1997 use super::*;
1998
1999 #[test]
2000 fn atan2_real_rug_zero_over_zero() {
2001 let zero_val = RealRugStrictFinite::<PRECISION>::zero();
2002 let res = zero_val.try_atan2(&RealRugStrictFinite::<PRECISION>::zero());
2003 assert!(matches!(
2004 res,
2005 Err(ATan2Errors::Input {
2006 source: ATan2InputErrors::ZeroOverZero { .. }
2007 })
2008 ));
2009 }
2010
2011 #[test]
2029 fn asin_real_rug_out_of_domain() {
2030 let val_gt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.5).unwrap();
2031 assert!(matches!(
2032 val_gt_1.try_asin(),
2033 Err(ASinRealErrors::Input {
2034 source: ASinRealInputErrors::OutOfDomain { .. }
2035 })
2036 ));
2037 let val_lt_neg1 = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.5).unwrap();
2038 assert!(matches!(
2039 val_lt_neg1.try_asin(),
2040 Err(ASinRealErrors::Input {
2041 source: ASinRealInputErrors::OutOfDomain { .. }
2042 })
2043 ));
2044 }
2045
2046 #[test]
2047 fn acos_real_rug_out_of_domain() {
2048 let val_gt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(1.5).unwrap();
2049 assert!(matches!(
2050 val_gt_1.try_acos(),
2051 Err(ACosRealErrors::Input {
2052 source: ACosRealInputErrors::OutOfDomain { .. }
2053 })
2054 ));
2055 let val_lt_neg1 = RealRugStrictFinite::<PRECISION>::try_from_f64(-1.5).unwrap();
2056 assert!(matches!(
2057 val_lt_neg1.try_acos(),
2058 Err(ACosRealErrors::Input {
2059 source: ACosRealInputErrors::OutOfDomain { .. }
2060 })
2061 ));
2062 }
2063
2064 #[test]
2065 fn atan_complex_rug_pole() {
2066 let i_val = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
2068 Float::with_val(PRECISION, 1.0),
2069 )
2070 .unwrap();
2071 assert!(matches!(
2072 i_val.try_atan(),
2073 Err(ATanComplexErrors::Input {
2074 source: ATanComplexInputErrors::ArgumentIsPole { .. }
2075 })
2076 ));
2077
2078 let neg_i_val = ComplexRugStrictFinite::<PRECISION>::try_new_pure_imaginary(
2079 Float::with_val(PRECISION, -1.0),
2080 )
2081 .unwrap();
2082 assert!(matches!(
2083 neg_i_val.try_atan(),
2084 Err(ATanComplexErrors::Input {
2085 source: ATanComplexInputErrors::ArgumentIsPole { .. }
2086 })
2087 ));
2088 }
2089 } mod hyperbolic {
2092 use super::*;
2093
2094 mod real {
2095 use super::*;
2096
2097 #[test]
2098 fn atanh_real_rug_out_of_domain() {
2099 let val_ge_1 = RealRugStrictFinite::<PRECISION>::one(); assert!(matches!(
2101 val_ge_1.try_atanh(),
2102 Err(ATanHErrors::Input {
2103 source: ATanHInputErrors::OutOfDomain { .. }
2104 })
2105 ));
2106
2107 let val_le_neg1 = RealRugStrictFinite::<PRECISION>::negative_one(); assert!(matches!(
2109 val_le_neg1.try_atanh(),
2110 Err(ATanHErrors::Input {
2111 source: ATanHInputErrors::OutOfDomain { .. }
2112 })
2113 ));
2114 }
2115
2116 #[test]
2117 fn acosh_real_rug_out_of_domain() {
2118 let val_lt_1 = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
2119 assert!(matches!(
2120 val_lt_1.try_acosh(),
2121 Err(ACosHErrors::Input {
2122 source: ACosHInputErrors::OutOfDomain { .. }
2123 })
2124 ));
2125 }
2126 }
2127
2128 mod complex {
2129 use super::*;
2130
2131 #[test]
2150 fn acosh_out_of_domain() {
2151 let val_on_branch_cut = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2153 Float::with_val(PRECISION, 0.5),
2154 )
2155 .unwrap();
2156 assert!(matches!(
2157 val_on_branch_cut.try_acosh(),
2158 Err(ACosHErrors::Input {
2159 source: ACosHInputErrors::OutOfDomain { .. }
2160 })
2161 ));
2162
2163 let val_on_branch_cut_neg =
2164 ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(Float::with_val(
2165 PRECISION, -5.0,
2166 ))
2167 .unwrap();
2168 assert!(matches!(
2169 val_on_branch_cut_neg.try_acosh(),
2170 Err(ACosHErrors::Input {
2171 source: ACosHInputErrors::OutOfDomain { .. }
2172 })
2173 ));
2174 }
2175
2176 #[test]
2177 fn atanh_out_of_domain() {
2178 let val_ge_1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2179 Float::with_val(PRECISION, 1.0),
2180 )
2181 .unwrap();
2182 assert!(matches!(
2183 val_ge_1.try_atanh(),
2184 Err(ATanHErrors::Input {
2185 source: ATanHInputErrors::OutOfDomain { .. }
2186 })
2187 ));
2188
2189 let val_le_neg1 = ComplexRugStrictFinite::<PRECISION>::try_new_pure_real(
2190 Float::with_val(PRECISION, -1.0),
2191 )
2192 .unwrap();
2193 assert!(matches!(
2194 val_le_neg1.try_atanh(),
2195 Err(ATanHErrors::Input {
2196 source: ATanHInputErrors::OutOfDomain { .. }
2197 })
2198 ));
2199 }
2200 }
2201
2202 } }
2220
2221 mod summation {
2222 use super::*;
2223
2224 const PRECISION: u32 = 53;
2225
2226 type RealValidated = RealRugStrictFinite<PRECISION>;
2227 type ComplexValidated = ComplexRugStrictFinite<PRECISION>;
2228
2229 #[test]
2230 fn sum_real() {
2231 let values = vec![
2232 RealValidated::try_from_f64(1.0).unwrap(),
2233 RealValidated::try_from_f64(2.0).unwrap(),
2234 RealValidated::try_from_f64(3.0).unwrap(),
2235 RealValidated::try_from_f64(4.0).unwrap(),
2236 RealValidated::try_from_f64(5.0).unwrap(),
2237 ];
2238 let sum: RealValidated = values.into_iter().sum();
2239 assert_eq!(sum, RealValidated::try_from_f64(15.0).unwrap());
2240 }
2241
2242 #[test]
2243 fn sum_real_compensated() {
2244 let values = vec![
2246 RealValidated::try_from_f64(1.0e100).unwrap(),
2247 RealValidated::try_from_f64(1.0).unwrap(),
2248 RealValidated::try_from_f64(-1.0e100).unwrap(),
2249 ];
2250 let sum: RealValidated = values.into_iter().sum();
2251 assert_eq!(sum, RealValidated::try_from_f64(1.0).unwrap());
2253 }
2254
2255 #[test]
2256 fn sum_complex() {
2257 let values = vec![
2258 ComplexValidated::try_new_complex(
2259 rug::Float::with_val(PRECISION, 1.),
2260 rug::Float::with_val(PRECISION, 2.),
2261 )
2262 .unwrap(),
2263 ComplexValidated::try_new_complex(
2264 rug::Float::with_val(PRECISION, 3.),
2265 rug::Float::with_val(PRECISION, 4.),
2266 )
2267 .unwrap(),
2268 ComplexValidated::try_new_complex(
2269 rug::Float::with_val(PRECISION, 5.),
2270 rug::Float::with_val(PRECISION, 6.),
2271 )
2272 .unwrap(),
2273 ];
2274 let sum: ComplexValidated = values.into_iter().sum();
2275 assert_eq!(
2276 sum,
2277 ComplexValidated::try_new_complex(
2278 rug::Float::with_val(PRECISION, 9.),
2279 rug::Float::with_val(PRECISION, 12.)
2280 )
2281 .unwrap()
2282 );
2283 }
2284
2285 #[test]
2286 fn sum_complex_compensated() {
2287 let values = [
2288 ComplexValidated::try_new_complex(
2289 rug::Float::with_val(PRECISION, 1.0e100),
2290 rug::Float::with_val(PRECISION, -1.0e100),
2291 )
2292 .unwrap(),
2293 ComplexValidated::try_new_complex(
2294 rug::Float::with_val(PRECISION, 1.),
2295 rug::Float::with_val(PRECISION, 2.),
2296 )
2297 .unwrap(),
2298 ComplexValidated::try_new_complex(
2299 rug::Float::with_val(PRECISION, -1.0e100),
2300 rug::Float::with_val(PRECISION, 1.0e100),
2301 )
2302 .unwrap(),
2303 ];
2304 let sum: ComplexValidated = values.iter().cloned().sum();
2305 assert_eq!(
2306 sum,
2307 ComplexValidated::try_new_complex(
2308 rug::Float::with_val(PRECISION, 1.),
2309 rug::Float::with_val(PRECISION, 2.)
2310 )
2311 .unwrap()
2312 );
2313 }
2314 } mod random {
2317 use super::*;
2318 use crate::{RandomSampleFromF64, new_random_vec};
2319 use rand::{RngExt, SeedableRng, distr::Uniform, rngs::StdRng};
2320
2321 const PRECISION: u32 = 53;
2322
2323 type RealValidated = RealRugStrictFinite<PRECISION>;
2324 type ComplexValidated = ComplexRugStrictFinite<PRECISION>;
2325
2326 #[test]
2330 fn test_random_real_validated() {
2331 let seed = [42; 32];
2332 let mut rng = StdRng::from_seed(seed);
2333
2334 let random_real: RealValidated = rng.random();
2335
2336 assert_eq!(random_real, 0.23713468825474326);
2338
2339 let mut rng2 = StdRng::from_seed(seed);
2341 let random_real2: RealValidated = rng2.random();
2342 assert_eq!(random_real, random_real2);
2343 }
2344
2345 #[test]
2350 fn test_random_complex_validated() {
2351 let seed = [99; 32];
2352 let mut rng = StdRng::from_seed(seed);
2353
2354 let random_complex: ComplexValidated = rng.random();
2355
2356 let real_part = random_complex.real_part();
2359 let imag_part = random_complex.imag_part();
2360
2361 assert_eq!(real_part, 0.9995546882627792);
2362 assert_eq!(imag_part, 0.08932180682540247);
2363
2364 let mut rng2 = StdRng::from_seed(seed);
2366 let random_complex2: ComplexValidated = rng2.random();
2367 assert_eq!(random_complex, random_complex2);
2368 }
2369
2370 const SEED: [u8; 32] = [42; 32];
2371
2372 #[test]
2373 fn test_sample_real_validated() {
2374 let mut rng = StdRng::from_seed(SEED);
2375 let dist = Uniform::new(-10.0, 10.0).unwrap();
2376
2377 let val = RealValidated::sample_from(&dist, &mut rng);
2378 assert_eq!(val, -5.257306234905137);
2379
2380 let mut rng2 = StdRng::from_seed(SEED);
2382 let val2 = RealValidated::sample_from(&dist, &mut rng2);
2383 assert_eq!(val, val2);
2384 }
2385
2386 #[test]
2387 fn test_sample_complex_validated() {
2388 let mut rng = StdRng::from_seed(SEED);
2389 let dist = Uniform::new(-10.0, 10.0).unwrap();
2390
2391 let val = ComplexValidated::sample_from(&dist, &mut rng);
2392 assert_eq!(val.real_part(), -5.257306234905137);
2393 assert_eq!(val.imag_part(), 7.212119776268775);
2394
2395 let mut rng2 = StdRng::from_seed(SEED);
2397 let val2 = ComplexValidated::sample_from(&dist, &mut rng2);
2398 assert_eq!(val, val2);
2399 }
2400
2401 #[test]
2402 fn new_random_vec_real() {
2403 let mut rng = StdRng::from_seed(SEED);
2404 let dist = Uniform::new(-10.0, 10.0).unwrap();
2405 let vec: Vec<RealValidated> = new_random_vec(3, &dist, &mut rng);
2406 assert_eq!(vec.len(), 3);
2407 assert_eq!(vec[0], -5.257306234905137);
2408 assert_eq!(vec[1], 7.212119776268775);
2409 assert_eq!(vec[2], -4.666248990558111);
2410
2411 let mut rng2 = StdRng::from_seed(SEED);
2413 let vec2: Vec<RealValidated> = new_random_vec(3, &dist, &mut rng2);
2414 assert_eq!(vec, vec2);
2415 }
2416
2417 #[test]
2418 fn new_random_vec_complex() {
2419 let mut rng = StdRng::from_seed(SEED);
2420 let dist = Uniform::new(-10.0, 10.0).unwrap();
2421 let vec: Vec<ComplexValidated> = new_random_vec(3, &dist, &mut rng);
2422 assert_eq!(vec.len(), 3);
2423 assert_eq!(vec[0].real_part(), -5.257306234905137);
2424 assert_eq!(vec[0].imag_part(), 7.212119776268775);
2425 assert_eq!(vec[1].real_part(), -4.666248990558111);
2426 assert_eq!(vec[1].imag_part(), 9.66047141517383);
2427 assert_eq!(vec[2].real_part(), -9.04279551029691);
2428 assert_eq!(vec[2].imag_part(), -1.026624649331671);
2429
2430 let mut rng2 = StdRng::from_seed(SEED);
2432 let vec2: Vec<ComplexValidated> = new_random_vec(3, &dist, &mut rng2);
2433 assert_eq!(vec, vec2);
2434 }
2435 }
2436
2437 mod hash_map_key_usage {
2438 use super::*;
2439 use rug::Float;
2440 use std::collections::HashMap;
2441 use try_create::TryNew;
2442
2443 const PRECISION: u32 = 128;
2444 type RealRugValidated = RealRugStrictFinite<PRECISION>;
2445
2446 #[test]
2447 fn test_rug_as_hashmap_key() {
2448 let mut map = HashMap::new();
2449 let key1 = RealRugValidated::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
2450 let key2 = RealRugValidated::try_new(Float::with_val(PRECISION, 2.5)).unwrap();
2451
2452 map.insert(key1.clone(), "one_rug");
2453 map.insert(key2.clone(), "two_point_five_rug");
2454
2455 assert_eq!(map.get(&key1), Some(&"one_rug"));
2456 assert_eq!(map.len(), 2);
2457
2458 let old_value = map.insert(key1.clone(), "new_one_rug");
2460 assert_eq!(old_value, Some("one_rug"));
2461 assert_eq!(map.get(&key1), Some(&"new_one_rug"));
2462 }
2463
2464 #[test]
2465 fn test_hash_signed_zero() {
2466 use crate::functions::Sign;
2467 use std::collections::hash_map::DefaultHasher;
2468 use std::hash::{Hash, Hasher};
2469
2470 let val1 = RealRugValidated::try_new(Float::with_val(PRECISION, 0.0)).unwrap();
2471 assert!(val1.kernel_is_sign_positive());
2472 let val2 = RealRugValidated::try_new(Float::with_val(PRECISION, -0.0)).unwrap();
2473 assert!(val2.kernel_is_sign_negative());
2474
2475 let mut hasher1 = DefaultHasher::new();
2477 let mut hasher2 = DefaultHasher::new();
2478
2479 val1.hash(&mut hasher1);
2480 val2.hash(&mut hasher2);
2481
2482 assert_eq!(hasher1.finish(), hasher2.finish());
2483 assert_eq!(val1, val2); }
2485
2486 #[test]
2487 fn test_complex_as_hashmap_key() {
2488 use crate::ComplexRugStrictFinite;
2489 type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2490
2491 let mut map = HashMap::new();
2492 let key1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
2493 .unwrap();
2494 let key2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (3.0, 4.0)))
2495 .unwrap();
2496
2497 map.insert(key1.clone(), "one_plus_two_i_rug");
2498 map.insert(key2.clone(), "three_plus_four_i_rug");
2499
2500 assert_eq!(map.get(&key1), Some(&"one_plus_two_i_rug"));
2501 assert_eq!(map.len(), 2);
2502
2503 let old_value = map.insert(key1.clone(), "updated_complex_rug");
2505 assert_eq!(old_value, Some("one_plus_two_i_rug"));
2506 assert_eq!(map.get(&key1), Some(&"updated_complex_rug"));
2507 }
2508
2509 #[test]
2510 fn test_complex_hash_consistency() {
2511 use crate::ComplexRugStrictFinite;
2512 use std::collections::hash_map::DefaultHasher;
2513 use std::hash::{Hash, Hasher};
2514 type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2515
2516 let val1 =
2517 ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.234, 5.678)))
2518 .unwrap();
2519 let val2 =
2520 ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.234, 5.678)))
2521 .unwrap();
2522
2523 let mut hasher1 = DefaultHasher::new();
2525 let mut hasher2 = DefaultHasher::new();
2526
2527 val1.hash(&mut hasher1);
2528 val2.hash(&mut hasher2);
2529
2530 assert_eq!(hasher1.finish(), hasher2.finish());
2531 assert_eq!(val1, val2);
2532 }
2533
2534 #[test]
2535 fn test_complex_hash_signed_zero() {
2536 use crate::ComplexRugStrictFinite;
2537 use std::collections::hash_map::DefaultHasher;
2538 use std::hash::{Hash, Hasher};
2539 type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2540
2541 let val1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (0.0, 0.0)))
2543 .unwrap();
2544 let val2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (-0.0, 0.0)))
2545 .unwrap();
2546 let val3 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (0.0, -0.0)))
2547 .unwrap();
2548 let val4 =
2549 ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (-0.0, -0.0)))
2550 .unwrap();
2551
2552 assert_eq!(val1, val2);
2554 assert_eq!(val1, val3);
2555 assert_eq!(val1, val4);
2556
2557 let mut hasher1 = DefaultHasher::new();
2559 let mut hasher2 = DefaultHasher::new();
2560 let mut hasher3 = DefaultHasher::new();
2561 let mut hasher4 = DefaultHasher::new();
2562
2563 val1.hash(&mut hasher1);
2564 val2.hash(&mut hasher2);
2565 val3.hash(&mut hasher3);
2566 val4.hash(&mut hasher4);
2567
2568 let hash1 = hasher1.finish();
2569 let hash2 = hasher2.finish();
2570 let hash3 = hasher3.finish();
2571 let hash4 = hasher4.finish();
2572
2573 assert_eq!(hash1, hash2);
2574 assert_eq!(hash1, hash3);
2575 assert_eq!(hash1, hash4);
2576 }
2577
2578 #[test]
2579 fn test_complex_hashset_operations() {
2580 use crate::ComplexRugStrictFinite;
2581 use std::collections::HashSet;
2582 type ComplexRugValidated = ComplexRugStrictFinite<PRECISION>;
2583
2584 let mut set = HashSet::new();
2585
2586 let val1 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
2587 .unwrap();
2588 let val2 = ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (3.0, 4.0)))
2589 .unwrap();
2590 let val1_duplicate =
2591 ComplexRugValidated::try_new(rug::Complex::with_val(PRECISION, (1.0, 2.0)))
2592 .unwrap();
2593
2594 assert!(set.insert(val1.clone()));
2595 assert!(set.insert(val2.clone()));
2596 assert!(!set.insert(val1_duplicate)); assert_eq!(set.len(), 2);
2599 assert!(set.contains(&val1));
2600 }
2601
2602 #[test]
2603 fn test_complex_different_precision_different_hash() {
2604 use crate::ComplexRugStrictFinite;
2605 use std::collections::hash_map::DefaultHasher;
2606 use std::hash::{Hash, Hasher};
2607
2608 const PRECISION_A: u32 = 64;
2609 const PRECISION_B: u32 = 128;
2610
2611 let val1 = ComplexRugStrictFinite::<PRECISION_A>::try_new(rug::Complex::with_val(
2612 PRECISION_A,
2613 (1.0, 2.0),
2614 ))
2615 .unwrap();
2616 let val2 = ComplexRugStrictFinite::<PRECISION_B>::try_new(rug::Complex::with_val(
2617 PRECISION_B,
2618 (1.0, 2.0),
2619 ))
2620 .unwrap();
2621
2622 let mut hasher1 = DefaultHasher::new();
2624 let mut hasher2 = DefaultHasher::new();
2625
2626 val1.hash(&mut hasher1);
2627 val2.hash(&mut hasher2);
2628
2629 let hash1 = hasher1.finish();
2630 let hash2 = hasher2.finish();
2631
2632 assert_ne!(hash1, hash2);
2634 }
2635 }
2636
2637 mod rug_float {
2638
2639 mod from_f64 {
2640 use crate::{RealRugStrictFinite, RealScalar};
2641
2642 const PRECISION: u32 = 100;
2643
2644 #[test]
2645 fn test_from_f64_valid_constants() {
2646 let pi = RealRugStrictFinite::<PRECISION>::from_f64(std::f64::consts::PI);
2648 let pi_f64 = pi.as_ref().to_f64();
2649 assert!((pi_f64 - std::f64::consts::PI).abs() < 1e-15);
2650
2651 let e = RealRugStrictFinite::<PRECISION>::from_f64(std::f64::consts::E);
2652 let e_f64 = e.as_ref().to_f64();
2653 assert!((e_f64 - std::f64::consts::E).abs() < 1e-15);
2654 }
2655
2656 #[test]
2657 fn test_from_f64_valid_simple_values() {
2658 let x = RealRugStrictFinite::<PRECISION>::from_f64(42.0);
2660 assert_eq!(x.as_ref().to_f64(), 42.0);
2661
2662 let y = RealRugStrictFinite::<PRECISION>::from_f64(-3.0);
2663 assert_eq!(y.as_ref().to_f64(), -3.0);
2664
2665 let z = RealRugStrictFinite::<PRECISION>::from_f64(0.0);
2666 assert_eq!(z.as_ref().to_f64(), 0.0);
2667 }
2668
2669 #[test]
2670 #[should_panic(expected = "RealScalar::from_f64() failed")]
2671 fn test_from_f64_nan_panics() {
2672 let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::NAN);
2673 }
2674
2675 #[test]
2676 #[should_panic(expected = "RealScalar::from_f64() failed")]
2677 fn test_from_f64_infinity_panics() {
2678 let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::INFINITY);
2679 }
2680
2681 #[test]
2682 #[should_panic(expected = "RealScalar::from_f64() failed")]
2683 fn test_from_f64_neg_infinity_panics() {
2684 let _ = RealRugStrictFinite::<PRECISION>::from_f64(f64::NEG_INFINITY);
2685 }
2686
2687 #[test]
2688 fn test_try_from_f64_exact_representation() {
2689 use crate::core::errors::ErrorsTryFromf64;
2690
2691 assert!(
2695 RealRugStrictFinite::<PRECISION>::try_from_f64(0.1).is_ok(),
2696 "0.1 (as f64 approximation) should be accepted at 100-bit precision"
2697 );
2698 assert!(
2699 RealRugStrictFinite::<PRECISION>::try_from_f64(0.3).is_ok(),
2700 "0.3 (as f64 approximation) should be accepted at 100-bit precision"
2701 );
2702 assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).is_ok());
2703 assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(2.5).is_ok());
2704 assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(0.0).is_ok());
2705
2706 assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(f64::NAN).is_err());
2708 assert!(RealRugStrictFinite::<PRECISION>::try_from_f64(f64::INFINITY).is_err());
2709
2710 match RealRugStrictFinite::<52>::try_from_f64(0.5) {
2712 Err(ErrorsTryFromf64::NonRepresentableExactly { precision, .. }) => {
2713 assert_eq!(precision, 52, "Error should report precision 52");
2714 }
2715 _ => panic!("Should reject precision < 53"),
2716 }
2717 }
2718 }
2719
2720 mod truncate_to_usize {
2721 use crate::core::errors::ErrorsRawRealToInteger;
2722 use crate::kernels::RawRealTrait;
2723 use rug::Float;
2724
2725 const PRECISION: u32 = 128;
2726
2727 #[test]
2728 fn test_rug_truncate_to_usize_valid() {
2729 assert_eq!(
2730 Float::with_val(PRECISION, 42.0)
2731 .truncate_to_usize()
2732 .unwrap(),
2733 42
2734 );
2735 assert_eq!(
2736 Float::with_val(PRECISION, 42.9)
2737 .truncate_to_usize()
2738 .unwrap(),
2739 42
2740 );
2741 assert_eq!(
2742 Float::with_val(PRECISION, 0.0).truncate_to_usize().unwrap(),
2743 0
2744 );
2745 assert_eq!(
2746 Float::with_val(PRECISION, usize::MAX)
2747 .truncate_to_usize()
2748 .unwrap(),
2749 usize::MAX
2750 );
2751 }
2752
2753 #[test]
2754 fn test_rug_truncate_to_usize_not_finite() {
2755 assert!(matches!(
2756 Float::with_val(PRECISION, f64::NAN).truncate_to_usize(),
2757 Err(ErrorsRawRealToInteger::NotFinite { .. })
2758 ));
2759 assert!(matches!(
2760 Float::with_val(PRECISION, f64::INFINITY).truncate_to_usize(),
2761 Err(ErrorsRawRealToInteger::NotFinite { .. })
2762 ));
2763 assert!(matches!(
2764 Float::with_val(PRECISION, f64::NEG_INFINITY).truncate_to_usize(),
2765 Err(ErrorsRawRealToInteger::NotFinite { .. })
2766 ));
2767 }
2768
2769 #[test]
2770 fn test_rug_truncate_to_usize_out_of_range() {
2771 assert!(matches!(
2773 Float::with_val(PRECISION, -1.0).truncate_to_usize(),
2774 Err(ErrorsRawRealToInteger::OutOfRange { .. })
2775 ));
2776
2777 let mut too_large = Float::with_val(PRECISION, usize::MAX);
2779 too_large += 1;
2780 assert!(matches!(
2781 too_large.truncate_to_usize(),
2782 Err(ErrorsRawRealToInteger::OutOfRange { .. })
2783 ));
2784 }
2785 }
2786 }
2787
2788 mod truncate_to_usize {
2789 use super::*;
2790 use rug::Float;
2791 use try_create::TryNew;
2792
2793 const PRECISION: u32 = 1000;
2794
2795 #[test]
2796 fn test_positive_integers() {
2797 let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 42.0))
2798 .unwrap();
2799 assert_eq!(value.truncate_to_usize().unwrap(), 42);
2800
2801 let value =
2802 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1.0)).unwrap();
2803 assert_eq!(value.truncate_to_usize().unwrap(), 1);
2804 }
2805
2806 #[test]
2807 fn test_positive_fractionals_truncate() {
2808 let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 42.9))
2809 .unwrap();
2810 assert_eq!(value.truncate_to_usize().unwrap(), 42);
2811
2812 let value =
2813 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.9)).unwrap();
2814 assert_eq!(value.truncate_to_usize().unwrap(), 0);
2815 }
2816
2817 #[test]
2818 fn test_zero_cases() {
2819 let value =
2820 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 0.0)).unwrap();
2821 assert_eq!(value.truncate_to_usize().unwrap(), 0);
2822 }
2823
2824 #[test]
2825 fn test_negative_values_error() {
2826 let value = RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -1.0))
2827 .unwrap();
2828 let result = value.truncate_to_usize();
2829 assert!(matches!(
2830 result,
2831 Err(ErrorsRawRealToInteger::OutOfRange { .. })
2832 ));
2833
2834 let value =
2835 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, -10.5))
2836 .unwrap();
2837 let result = value.truncate_to_usize();
2838 assert!(matches!(
2839 result,
2840 Err(ErrorsRawRealToInteger::OutOfRange { .. })
2841 ));
2842 }
2843
2844 #[test]
2845 fn test_large_values() {
2846 let value =
2848 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, 1_000_000.0))
2849 .unwrap();
2850 assert_eq!(value.truncate_to_usize().unwrap(), 1_000_000);
2851
2852 let value = RealRugStrictFinite::<PRECISION>::try_new(
2854 Float::with_val(PRECISION, 1e50), )
2856 .unwrap();
2857 let result = value.truncate_to_usize();
2858 assert!(matches!(
2859 result,
2860 Err(ErrorsRawRealToInteger::OutOfRange { .. })
2861 ));
2862 }
2863
2864 #[test]
2865 fn test_high_precision_truncation() {
2866 let value = RealRugStrictFinite::<PRECISION>::try_new(
2868 Float::parse("42.99999999999999999999999999999")
2869 .unwrap()
2870 .complete(PRECISION),
2871 )
2872 .unwrap();
2873 assert_eq!(value.truncate_to_usize().unwrap(), 42);
2874
2875 let value = RealRugStrictFinite::<PRECISION>::try_new(
2877 Float::parse("0.99999999999999999999999999999")
2878 .unwrap()
2879 .complete(PRECISION),
2880 )
2881 .unwrap();
2882 assert_eq!(value.truncate_to_usize().unwrap(), 0);
2883 }
2884
2885 #[test]
2886 fn test_conversion_from_f64() {
2887 let value = RealRugStrictFinite::<PRECISION>::try_from_f64(42.7).unwrap();
2889 assert_eq!(value.truncate_to_usize().unwrap(), 42);
2890
2891 let value = RealRugStrictFinite::<PRECISION>::try_from_f64(0.5).unwrap();
2892 assert_eq!(value.truncate_to_usize().unwrap(), 0);
2893 }
2894 }
2895}