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