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