1#![deny(rustdoc::broken_intra_doc_links)]
2
3use crate::{
40 IntegerScalar, ScalarCore,
41 core::{
42 errors::{
43 ErrorsRawRealToInteger, ErrorsValidationRawComplex, ErrorsValidationRawReal,
44 capture_backtrace,
45 },
46 traits::{
47 raw::{
48 RawComplexTrait, RawRealTrait, RawScalarHyperbolic, RawScalarPow, RawScalarTrait,
49 RawScalarTrigonometric, RawScalarValidate,
50 },
51 validation::FpChecks,
52 },
53 },
54 functions::{Conjugate, NegAssign, Rounding, Sign},
55 kernels::PrecisionBits,
56};
57use duplicate::duplicate_item;
58use rug::{
59 float::Constant as MpfrConstant,
60 ops::{CompleteRound, Pow},
61};
62use std::{
63 cmp::Ordering,
64 hash::{Hash, Hasher},
65 num::FpCategory,
66 ops::Neg,
67};
68
69#[duplicate_item(
70 T;
71 [rug::Float];
72 [rug::Complex];
73)]
74impl RawScalarTrigonometric for T {
75 #[duplicate_item(
76 unchecked_method method;
77 [unchecked_sin] [sin];
78 [unchecked_asin] [asin];
79 [unchecked_cos] [cos];
80 [unchecked_acos] [acos];
81 [unchecked_tan] [tan];
82 [unchecked_atan] [atan];)]
83 #[inline(always)]
84 fn unchecked_method(self) -> Self {
85 T::method(self)
86 }
87}
88
89#[duplicate_item(
90 T;
91 [rug::Float];
92 [rug::Complex];
93)]
94impl RawScalarHyperbolic for T {
95 #[duplicate_item(
96 unchecked_method method;
97 [unchecked_sinh] [sinh];
98 [unchecked_asinh] [asinh];
99 [unchecked_cosh] [cosh];
100 [unchecked_acosh] [acosh];
101 [unchecked_tanh] [tanh];
102 [unchecked_atanh] [atanh];)]
103 #[inline(always)]
104 fn unchecked_method(self) -> Self {
105 T::method(self)
106 }
107}
108
109#[duplicate_item(
110 T;
111 [rug::Float];
112 [rug::Complex];
113)]
114impl RawScalarPow for T {
115 #[duplicate_item(
116 unchecked_method exponent_type;
117 [unchecked_pow_exponent_i8] [i8];
118 [unchecked_pow_exponent_i16] [i16];
119 [unchecked_pow_exponent_i32] [i32];
120 [unchecked_pow_exponent_i64] [i64];
121 [unchecked_pow_exponent_i128] [i128];
122 [unchecked_pow_exponent_isize] [isize];
123 [unchecked_pow_exponent_u8] [u8];
124 [unchecked_pow_exponent_u16] [u16];
125 [unchecked_pow_exponent_u32] [u32];
126 [unchecked_pow_exponent_u64] [u64];
127 [unchecked_pow_exponent_u128] [u128];
128 [unchecked_pow_exponent_usize] [usize];
129 )]
130 #[inline(always)]
131 fn unchecked_method(self, exponent: &exponent_type) -> Self {
132 T::pow(self, exponent)
133 }
134}
135
136impl RawScalarValidate for rug::Float {
137 type ValidationError = ErrorsValidationRawReal<rug::Float>;
138
139 #[inline(always)]
140 fn validate_raw_scalar_ref(&self) -> Result<(), Self::ValidationError> {
141 match self.raw_classify() {
142 FpCategory::Nan => Err(ErrorsValidationRawReal::<rug::Float>::IsNaN {
143 value: self.clone(),
144 backtrace: capture_backtrace(),
145 }),
146 FpCategory::Infinite => {
147 if self.is_sign_positive() {
148 Err(ErrorsValidationRawReal::<rug::Float>::IsPosInfinity {
149 backtrace: capture_backtrace(),
150 })
151 } else {
152 Err(ErrorsValidationRawReal::<rug::Float>::IsNegInfinity {
153 backtrace: capture_backtrace(),
154 })
155 }
156 }
157 FpCategory::Subnormal => {
158 unreachable!("rug::Float should not produce subnormal values");
159 }
160 FpCategory::Zero | FpCategory::Normal => {
161 Ok(())
163 }
164 }
165 }
166}
167
168#[duplicate_item(
169 T;
170 [rug::Float];
171 [rug::Complex];
172)]
173impl ScalarCore for T {
174 type RawScalarType = Self;
175
176 fn as_raw_scalar_ref(&self) -> &Self::RawScalarType {
177 self
178 }
179
180 fn into_raw_scalar(self) -> Self::RawScalarType {
181 self
182 }
183}
184
185impl RawScalarTrait for rug::Float {
186 fn raw_zero(precision: u32) -> Self {
187 rug::Float::with_val(precision, 0.)
188 }
189
190 fn is_zero(&self) -> bool {
191 rug::Float::is_zero(self)
192 }
193
194 fn raw_one(precision: u32) -> Self {
195 rug::Float::with_val(precision, 1.)
196 }
197
198 #[duplicate_item(
199 unchecked_method method;
200 [unchecked_reciprocal] [recip];
201 [unchecked_exp] [exp];
202 [unchecked_sqrt] [sqrt];
203 [unchecked_ln] [ln];
204 [unchecked_log2] [log2];
205 [unchecked_log10] [log10];
206 )]
207 #[inline(always)]
208 fn unchecked_method(self) -> Self {
209 rug::Float::method(self)
210 }
211
212 #[inline(always)]
216 fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
217 rug::Float::mul_add(self, b, c)
218 }
219
220 #[inline(always)]
221 fn compute_hash_raw_scalar<H: Hasher>(&self, state: &mut H) {
222 debug_assert!(
223 self.is_finite(),
224 "Hashing a non-finite rug::Float value (i.e., NaN or Infinity) may lead to inconsistent results."
225 );
226 self.prec().hash(state);
228
229 if self.is_zero() {
231 rug::Float::with_val(self.prec(), 0.0)
233 .to_string_radix(10, None)
234 .hash(state);
235 } else {
236 self.to_string_radix(10, None).hash(state)
239 }
240 }
241}
242
243impl PrecisionBits for rug::Float {
244 #[inline(always)]
245 fn precision_bits(&self) -> u32 {
246 self.prec()
247 }
248}
249
250impl RawRealTrait for rug::Float {
251 type RawComplex = rug::Complex;
252
253 #[inline(always)]
254 fn unchecked_abs(self) -> rug::Float {
255 rug::Float::abs(self)
256 }
257
258 #[inline(always)]
259 fn unchecked_atan2(self, denominator: &Self) -> Self {
260 rug::Float::atan2(self, denominator)
261 }
262
263 #[inline(always)]
264 fn unchecked_pow_exponent_real(self, exponent: &Self) -> Self {
265 rug::Float::pow(self, exponent)
266 }
267
268 #[inline(always)]
269 fn unchecked_hypot(self, other: &Self) -> Self {
270 rug::Float::hypot(self, other)
271 }
272
273 #[inline(always)]
274 fn unchecked_ln_1p(self) -> Self {
275 rug::Float::ln_1p(self)
276 }
277
278 #[inline(always)]
279 fn unchecked_exp_m1(self) -> Self {
280 rug::Float::exp_m1(self)
281 }
282
283 #[inline(always)]
286 fn unchecked_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self) {
287 self.mul_add_mul_mut(mul, add_mul1, add_mul2);
288 }
289
290 #[inline(always)]
293 fn unchecked_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self) {
294 self.mul_sub_mul_mut(mul, sub_mul1, sub_mul2);
295 }
296
297 #[inline(always)]
298 fn raw_total_cmp(&self, other: &Self) -> Ordering {
299 rug::Float::total_cmp(self, other)
300 }
301
302 #[inline(always)]
304 fn raw_clamp(self, min: &Self, max: &Self) -> Self {
305 rug::Float::clamp(self, min, max)
306 }
307
308 #[inline(always)]
309 fn raw_classify(&self) -> FpCategory {
310 rug::Float::classify(self)
311 }
312
313 #[inline(always)]
314 fn raw_two(precision: u32) -> Self {
315 rug::Float::with_val(precision, 2.)
316 }
317
318 #[inline(always)]
319 fn raw_one_div_2(precision: u32) -> Self {
320 rug::Float::with_val(precision, 0.5)
321 }
322
323 #[inline(always)]
324 fn raw_pi(precision: u32) -> Self {
325 rug::Float::with_val(precision, MpfrConstant::Pi)
327 }
328
329 #[inline(always)]
330 fn raw_two_pi(precision: u32) -> Self {
331 rug::Float::with_val(precision, MpfrConstant::Pi) * 2
332 }
333
334 #[inline(always)]
335 fn raw_pi_div_2(precision: u32) -> Self {
336 rug::Float::with_val(precision, MpfrConstant::Pi) / 2
337 }
338
339 #[inline(always)]
340 fn raw_max_finite(precision: u32) -> Self {
341 let one = rug::Float::with_val(precision, 1);
347 let eps = rug::Float::with_val(precision, rug::Float::u_pow_u(2, precision)).recip();
348 let significand = one - &eps;
349
350 let max_exp = rug::float::exp_max() - 1;
352 significand * rug::Float::with_val(precision, rug::Float::u_pow_u(2, max_exp as u32))
354 }
355
356 #[inline(always)]
357 fn raw_min_finite(precision: u32) -> Self {
358 Self::raw_max_finite(precision).neg()
359 }
360
361 #[inline(always)]
362 fn raw_epsilon(precision: u32) -> Self {
363 rug::Float::u_pow_u(2, precision - 1)
364 .complete(precision)
365 .recip()
366 }
367
368 #[inline(always)]
369 fn raw_ln_2(precision: u32) -> Self {
370 rug::Float::with_val(precision, MpfrConstant::Log2)
372 }
373
374 #[inline(always)]
375 fn raw_ln_10(precision: u32) -> Self {
376 let ln2 = rug::Float::with_val(precision, MpfrConstant::Log2);
379 let log2_10 = rug::Float::with_val(precision, 10).log2();
380 ln2 * log2_10
381 }
382
383 #[inline(always)]
384 fn raw_log10_2(precision: u32) -> Self {
385 rug::Float::with_val(precision, 2.).log10()
386 }
387
388 #[inline(always)]
389 fn raw_log2_10(precision: u32) -> Self {
390 rug::Float::with_val(precision, 10.).log2()
391 }
392
393 #[inline(always)]
394 fn raw_log2_e(precision: u32) -> Self {
395 rug::Float::with_val(precision, MpfrConstant::Log2).recip()
398 }
399
400 #[inline(always)]
401 fn raw_log10_e(precision: u32) -> Self {
402 let ln2 = rug::Float::with_val(precision, MpfrConstant::Log2);
404 let log2_10 = rug::Float::with_val(precision, 10).log2();
405 (ln2 * log2_10).recip()
406 }
407
408 #[inline(always)]
409 fn raw_e(precision: u32) -> Self {
410 rug::Float::with_val(precision, 1.).exp()
411 }
412
413 #[inline(always)]
414 fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<rug::Float, usize>> {
415 if !self.is_finite() {
416 return Err(ErrorsRawRealToInteger::NotFinite {
417 value: self,
418 backtrace: capture_backtrace(),
419 });
420 }
421
422 let truncation = self.clone().trunc();
423
424 let out_of_range = || ErrorsRawRealToInteger::OutOfRange {
425 value: self,
426 min: usize::MIN,
427 max: usize::MAX,
428 backtrace: capture_backtrace(),
429 };
430
431 let truncation_as_rug_integer = truncation.to_integer().ok_or_else(out_of_range.clone())?;
432
433 truncation_as_rug_integer
434 .to_usize()
435 .ok_or_else(out_of_range)
436 }
437
438 fn unchecked_mul_assign_integer<I>(&mut self, integer: I)
439 where
440 I: IntegerScalar,
441 {
442 let as_rug_integer = match integer.to_i128() {
444 Some(value) => rug::Integer::from(value),
445 None => rug::Integer::from(
446 integer
447 .to_u128()
448 .expect("IntegerScalar values always fit in i128 or u128"),
449 ),
450 };
451 *self *= as_rug_integer;
452 }
453
454 fn unchecked_div_assign_integer<I>(&mut self, integer: I)
455 where
456 I: IntegerScalar,
457 {
458 let as_rug_integer = match integer.to_i128() {
460 Some(value) => rug::Integer::from(value),
461 None => rug::Integer::from(
462 integer
463 .to_u128()
464 .expect("IntegerScalar values always fit in i128 or u128"),
465 ),
466 };
467 *self /= as_rug_integer;
468 }
469}
470
471impl RawScalarValidate for rug::Complex {
472 type ValidationError = ErrorsValidationRawComplex<ErrorsValidationRawReal<rug::Float>>;
473
474 fn validate_raw_scalar_ref(&self) -> Result<(), Self::ValidationError> {
475 let real_validation = self.real().validate_raw_scalar_ref();
476 let imag_validation = self.imag().validate_raw_scalar_ref();
477 match (real_validation, imag_validation) {
478 (Ok(()), Ok(())) => Ok(()),
479 (Ok(()), Err(imag_err)) => Err(ErrorsValidationRawComplex::InvalidImaginaryPart {
480 source: Box::new(imag_err),
481 }),
482 (Err(real_err), Ok(())) => Err(ErrorsValidationRawComplex::InvalidRealPart {
483 source: Box::new(real_err),
484 }),
485 (Err(real_err), Err(imag_err)) => Err(ErrorsValidationRawComplex::InvalidBothParts {
486 real_error: Box::new(real_err),
487 imag_error: Box::new(imag_err),
488 }),
489 }
490 }
491}
492
493impl RawScalarTrait for rug::Complex {
494 fn raw_zero(precision: u32) -> Self {
495 rug::Complex::with_val(precision, (0., 0.))
496 }
497
498 fn is_zero(&self) -> bool {
499 rug::Complex::is_zero(self)
500 }
501
502 fn raw_one(precision: u32) -> Self {
503 rug::Complex::with_val(precision, (1., 0.))
504 }
505
506 #[duplicate_item(
507 unchecked_method method;
508 [unchecked_reciprocal] [recip];
509 [unchecked_exp] [exp];
510 [unchecked_sqrt] [sqrt];
511 [unchecked_ln] [ln];
512 [unchecked_log10] [log10];
513 )]
514 #[inline(always)]
515 fn unchecked_method(self) -> Self {
516 rug::Complex::method(self)
517 }
518
519 #[inline(always)]
520 fn unchecked_log2(self) -> Self {
521 let ln_2 = rug::Float::with_val(self.real().prec(), 2.).ln();
522 rug::Complex::ln(self) / ln_2
523 }
524
525 #[inline(always)]
529 fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
530 rug::Complex::mul_add(self, b, c)
531 }
532
533 fn compute_hash_raw_scalar<H: Hasher>(&self, state: &mut H) {
534 self.raw_real_part().compute_hash_raw_scalar(state);
535 self.raw_imag_part().compute_hash_raw_scalar(state);
536 }
537}
538
539impl Conjugate for rug::Complex {
540 #[inline(always)]
541 fn conjugate(self) -> Self {
542 rug::Complex::conj(self)
543 }
544}
545
546impl RawComplexTrait for rug::Complex {
547 type RawReal = rug::Float;
548
549 fn new_unchecked_raw_complex(real: rug::Float, imag: rug::Float) -> Self {
550 debug_assert_eq!(
551 real.prec(),
552 imag.prec(),
553 "Different precision between real and imaginary part!"
554 );
555 rug::Complex::with_val(real.prec(), (real, imag))
556 }
557
558 fn mut_raw_real_part(&mut self) -> &mut rug::Float {
560 self.mut_real()
561 }
562
563 fn mut_raw_imag_part(&mut self) -> &mut rug::Float {
565 self.mut_imag()
566 }
567
568 #[inline(always)]
569 fn unchecked_abs(self) -> rug::Float {
570 rug::Complex::abs(self).into_real_imag().0
571 }
572
573 #[inline(always)]
574 fn raw_real_part(&self) -> &rug::Float {
575 self.real()
576 }
577
578 #[inline(always)]
579 fn raw_imag_part(&self) -> &rug::Float {
580 self.imag()
581 }
582
583 #[inline(always)]
584 fn unchecked_arg(self) -> rug::Float {
585 rug::Complex::arg(self).into_real_imag().0
586 }
587
588 #[inline(always)]
589 fn unchecked_pow_exponent_real(self, exponent: &rug::Float) -> Self {
590 rug::Complex::pow(self, exponent)
591 }
592}
593
594impl FpChecks for rug::Float {
595 fn is_finite(&self) -> bool {
596 rug::Float::is_finite(self)
597 }
598
599 fn is_infinite(&self) -> bool {
600 rug::Float::is_infinite(self)
601 }
602
603 fn is_nan(&self) -> bool {
604 rug::Float::is_nan(self)
605 }
606 fn is_normal(&self) -> bool {
607 rug::Float::is_normal(self)
608 }
609}
610
611impl FpChecks for rug::Complex {
612 #[inline(always)]
614 fn is_finite(&self) -> bool {
615 self.real().is_finite() && self.imag().is_finite()
616 }
617
618 #[inline(always)]
620 fn is_infinite(&self) -> bool {
621 !self.is_nan() && (self.real().is_infinite() || self.imag().is_infinite())
622 }
623
624 #[inline(always)]
626 fn is_nan(&self) -> bool {
627 self.real().is_nan() || self.imag().is_nan()
628 }
629
630 #[inline(always)]
632 fn is_normal(&self) -> bool {
633 self.real().is_normal() && self.imag().is_normal()
634 }
635}
636
637#[duplicate_item(
639 T;
640 [rug::Float];
641 [rug::Complex];
642)]
643impl NegAssign for T {
645 fn neg_assign(&mut self) {
647 <T as rug::ops::NegAssign>::neg_assign(self);
648 }
649}
650impl Sign for rug::Float {
653 #[inline(always)]
655 fn kernel_copysign(self, sign: &Self) -> Self {
656 self.copysign(sign)
657 }
658
659 #[inline(always)]
661 fn kernel_is_sign_negative(&self) -> bool {
662 self.is_sign_negative()
663 }
664
665 #[inline(always)]
667 fn kernel_is_sign_positive(&self) -> bool {
668 self.is_sign_positive()
669 }
670
671 #[inline(always)]
679 fn kernel_signum(self) -> Self {
680 self.signum()
681 }
682}
683
684impl Rounding for rug::Float {
685 #[inline(always)]
687 fn kernel_ceil(self) -> Self {
688 self.ceil()
689 }
690
691 #[inline(always)]
693 fn kernel_floor(self) -> Self {
694 self.floor()
695 }
696
697 #[inline(always)]
699 fn kernel_fract(self) -> Self {
700 self.fract()
701 }
702
703 #[inline(always)]
705 fn kernel_round(self) -> Self {
706 self.round()
707 }
708
709 #[inline(always)]
730 fn kernel_round_ties_even(self) -> Self {
731 self.round_even()
732 }
733
734 #[inline(always)]
751 fn kernel_trunc(self) -> Self {
752 self.trunc()
753 }
754}
755
756#[cfg(test)]
757mod tests {
758 use crate::kernels::RawRealTrait;
759
760 mod mul_assign_integer {
761 use super::*;
762
763 #[test]
764 fn multiplies_by_signed_integer() {
765 let mut real = rug::Float::with_val(100, 3.5);
766 real.unchecked_mul_assign_integer(-4_i32);
767 assert_eq!(real, rug::Float::with_val(100, -14));
768 }
769
770 #[test]
771 fn multiplies_by_unsigned_integer() {
772 let mut real = rug::Float::with_val(100, 3.5);
773 real.unchecked_mul_assign_integer(4_u16);
774 assert_eq!(real, rug::Float::with_val(100, 14));
775 }
776
777 #[test]
778 fn multiplies_by_i128_beyond_f64_precision() {
779 let mut real = rug::Float::with_val(200, 1);
780 real.unchecked_mul_assign_integer((1_i128 << 100) + 1);
781 assert_eq!(real, rug::Float::with_val(200, (1_i128 << 100) + 1));
782 }
783
784 #[test]
785 fn multiplies_by_u128_beyond_i128_range() {
786 let mut real = rug::Float::with_val(200, 1);
787 real.unchecked_mul_assign_integer(u128::MAX);
788 assert_eq!(
789 real,
790 rug::Float::with_val(200, rug::Integer::from(u128::MAX))
791 );
792 }
793 }
794
795 mod div_assign_integer {
796 use super::*;
797
798 #[test]
799 fn divides_by_signed_integer() {
800 let mut real = rug::Float::with_val(100, 14);
801 real.unchecked_div_assign_integer(-4_i32);
802 assert_eq!(real, rug::Float::with_val(100, -3.5));
803 }
804
805 #[test]
806 fn divides_by_unsigned_integer() {
807 let mut real = rug::Float::with_val(100, 14);
808 real.unchecked_div_assign_integer(4_u16);
809 assert_eq!(real, rug::Float::with_val(100, 3.5));
810 }
811
812 #[test]
813 fn divides_by_i128_beyond_f64_precision() {
814 let mut real = rug::Float::with_val(200, (1_i128 << 100) + 1);
815 real.unchecked_div_assign_integer((1_i128 << 100) + 1);
816 assert_eq!(real, rug::Float::with_val(200, 1));
817 }
818
819 #[test]
820 fn divides_by_u128_beyond_i128_range() {
821 let mut real = rug::Float::with_val(200, rug::Integer::from(u128::MAX));
822 real.unchecked_div_assign_integer(u128::MAX);
823 assert_eq!(real, rug::Float::with_val(200, 1));
824 }
825 }
826
827 mod mul_integer {
828 use super::*;
829
830 #[test]
831 fn returns_product_without_mutating_in_place() {
832 let real = rug::Float::with_val(100, 3.5);
833 assert_eq!(
834 real.unchecked_mul_integer(-4_i32),
835 rug::Float::with_val(100, -14)
836 );
837 }
838 }
839
840 mod div_integer {
841 use super::*;
842
843 #[test]
844 fn returns_quotient_without_mutating_in_place() {
845 let real = rug::Float::with_val(100, 14);
846 assert_eq!(
847 real.unchecked_div_integer(-4_i32),
848 rug::Float::with_val(100, -3.5)
849 );
850 }
851 }
852}