1#![deny(rustdoc::broken_intra_doc_links)]
2
3use crate::{
40 core::{
41 errors::{
42 ErrorsRawRealToInteger, ErrorsValidationRawComplex, ErrorsValidationRawReal,
43 capture_backtrace,
44 },
45 traits::{
46 raw::{
47 RawComplexTrait, RawRealTrait, RawScalarHyperbolic, RawScalarPow, RawScalarTrait,
48 RawScalarTrigonometric, RawScalarValidate,
49 },
50 validation::FpChecks,
51 },
52 },
53 functions::{Conjugate, NegAssign, Rounding, Sign},
54 kernels::PrecisionBits,
55};
56use duplicate::duplicate_item;
57use rug::{
58 float::Constant as MpfrConstant,
59 ops::{CompleteRound, Pow},
60};
61use std::{
62 cmp::Ordering,
63 hash::{Hash, Hasher},
64 num::FpCategory,
65 ops::Neg,
66};
67
68#[duplicate_item(
69 T;
70 [rug::Float];
71 [rug::Complex];
72)]
73impl RawScalarTrigonometric for T {
74 #[duplicate_item(
75 unchecked_method method;
76 [unchecked_sin] [sin];
77 [unchecked_asin] [asin];
78 [unchecked_cos] [cos];
79 [unchecked_acos] [acos];
80 [unchecked_tan] [tan];
81 [unchecked_atan] [atan];)]
82 #[inline(always)]
83 fn unchecked_method(self) -> Self {
84 T::method(self)
85 }
86}
87
88#[duplicate_item(
89 T;
90 [rug::Float];
91 [rug::Complex];
92)]
93impl RawScalarHyperbolic for T {
94 #[duplicate_item(
95 unchecked_method method;
96 [unchecked_sinh] [sinh];
97 [unchecked_asinh] [asinh];
98 [unchecked_cosh] [cosh];
99 [unchecked_acosh] [acosh];
100 [unchecked_tanh] [tanh];
101 [unchecked_atanh] [atanh];)]
102 #[inline(always)]
103 fn unchecked_method(self) -> Self {
104 T::method(self)
105 }
106}
107
108#[duplicate_item(
109 T;
110 [rug::Float];
111 [rug::Complex];
112)]
113impl RawScalarPow for T {
114 #[duplicate_item(
115 unchecked_method exponent_type;
116 [unchecked_pow_exponent_i8] [i8];
117 [unchecked_pow_exponent_i16] [i16];
118 [unchecked_pow_exponent_i32] [i32];
119 [unchecked_pow_exponent_i64] [i64];
120 [unchecked_pow_exponent_i128] [i128];
121 [unchecked_pow_exponent_isize] [isize];
122 [unchecked_pow_exponent_u8] [u8];
123 [unchecked_pow_exponent_u16] [u16];
124 [unchecked_pow_exponent_u32] [u32];
125 [unchecked_pow_exponent_u64] [u64];
126 [unchecked_pow_exponent_u128] [u128];
127 [unchecked_pow_exponent_usize] [usize];
128 )]
129 #[inline(always)]
130 fn unchecked_method(self, exponent: &exponent_type) -> Self {
131 T::pow(self, exponent)
132 }
133}
134
135impl RawScalarValidate for rug::Float {
136 type ValidationError = ErrorsValidationRawReal<rug::Float>;
137
138 #[inline(always)]
139 fn validate_raw_scalar_ref(&self) -> Result<(), Self::ValidationError> {
140 match self.raw_classify() {
141 FpCategory::Nan => Err(ErrorsValidationRawReal::<rug::Float>::IsNaN {
142 value: self.clone(),
143 backtrace: capture_backtrace(),
144 }),
145 FpCategory::Infinite => {
146 if self.is_sign_positive() {
147 Err(ErrorsValidationRawReal::<rug::Float>::IsPosInfinity {
148 backtrace: capture_backtrace(),
149 })
150 } else {
151 Err(ErrorsValidationRawReal::<rug::Float>::IsNegInfinity {
152 backtrace: capture_backtrace(),
153 })
154 }
155 }
156 FpCategory::Subnormal => {
157 unreachable!("rug::Float should not produce subnormal values");
158 }
159 FpCategory::Zero | FpCategory::Normal => {
160 Ok(())
162 }
163 }
164 }
165}
166
167impl RawScalarTrait for rug::Float {
168 fn raw_zero(precision: u32) -> Self {
169 rug::Float::with_val(precision, 0.)
170 }
171
172 fn is_zero(&self) -> bool {
173 rug::Float::is_zero(self)
174 }
175
176 fn raw_one(precision: u32) -> Self {
177 rug::Float::with_val(precision, 1.)
178 }
179
180 #[duplicate_item(
181 unchecked_method method;
182 [unchecked_reciprocal] [recip];
183 [unchecked_exp] [exp];
184 [unchecked_sqrt] [sqrt];
185 [unchecked_ln] [ln];
186 [unchecked_log2] [log2];
187 [unchecked_log10] [log10];
188 )]
189 #[inline(always)]
190 fn unchecked_method(self) -> Self {
191 rug::Float::method(self)
192 }
193
194 #[inline(always)]
198 fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
199 rug::Float::mul_add(self, b, c)
200 }
201
202 #[inline(always)]
203 fn compute_hash_raw_scalar<H: Hasher>(&self, state: &mut H) {
204 debug_assert!(
205 self.is_finite(),
206 "Hashing a non-finite rug::Float value (i.e., NaN or Infinity) may lead to inconsistent results."
207 );
208 self.prec().hash(state);
210
211 if self.is_zero() {
213 rug::Float::with_val(self.prec(), 0.0)
215 .to_string_radix(10, None)
216 .hash(state);
217 } else {
218 self.to_string_radix(10, None).hash(state)
221 }
222 }
223}
224
225impl PrecisionBits for rug::Float {
226 #[inline(always)]
227 fn precision_bits(&self) -> u32 {
228 self.prec()
229 }
230}
231
232impl RawRealTrait for rug::Float {
233 type RawComplex = rug::Complex;
234
235 #[inline(always)]
236 fn unchecked_abs(self) -> rug::Float {
237 rug::Float::abs(self)
238 }
239
240 #[inline(always)]
241 fn unchecked_atan2(self, denominator: &Self) -> Self {
242 rug::Float::atan2(self, denominator)
243 }
244
245 #[inline(always)]
246 fn unchecked_pow_exponent_real(self, exponent: &Self) -> Self {
247 rug::Float::pow(self, exponent)
248 }
249
250 #[inline(always)]
251 fn unchecked_hypot(self, other: &Self) -> Self {
252 rug::Float::hypot(self, other)
253 }
254
255 #[inline(always)]
256 fn unchecked_ln_1p(self) -> Self {
257 rug::Float::ln_1p(self)
258 }
259
260 #[inline(always)]
261 fn unchecked_exp_m1(self) -> Self {
262 rug::Float::exp_m1(self)
263 }
264
265 #[inline(always)]
268 fn unchecked_mul_add_mul_mut(&mut self, mul: &Self, add_mul1: &Self, add_mul2: &Self) {
269 self.mul_add_mul_mut(mul, add_mul1, add_mul2);
270 }
271
272 #[inline(always)]
275 fn unchecked_mul_sub_mul_mut(&mut self, mul: &Self, sub_mul1: &Self, sub_mul2: &Self) {
276 self.mul_sub_mul_mut(mul, sub_mul1, sub_mul2);
277 }
278
279 #[inline(always)]
280 fn raw_total_cmp(&self, other: &Self) -> Ordering {
281 rug::Float::total_cmp(self, other)
282 }
283
284 #[inline(always)]
286 fn raw_clamp(self, min: &Self, max: &Self) -> Self {
287 rug::Float::clamp(self, min, max)
288 }
289
290 #[inline(always)]
291 fn raw_classify(&self) -> FpCategory {
292 rug::Float::classify(self)
293 }
294
295 #[inline(always)]
296 fn raw_two(precision: u32) -> Self {
297 rug::Float::with_val(precision, 2.)
298 }
299
300 #[inline(always)]
301 fn raw_one_div_2(precision: u32) -> Self {
302 rug::Float::with_val(precision, 0.5)
303 }
304
305 #[inline(always)]
306 fn raw_pi(precision: u32) -> Self {
307 rug::Float::with_val(precision, MpfrConstant::Pi)
309 }
310
311 #[inline(always)]
312 fn raw_two_pi(precision: u32) -> Self {
313 rug::Float::with_val(precision, MpfrConstant::Pi) * 2
314 }
315
316 #[inline(always)]
317 fn raw_pi_div_2(precision: u32) -> Self {
318 rug::Float::with_val(precision, MpfrConstant::Pi) / 2
319 }
320
321 #[inline(always)]
322 fn raw_max_finite(precision: u32) -> Self {
323 let one = rug::Float::with_val(precision, 1);
329 let eps = rug::Float::with_val(precision, rug::Float::u_pow_u(2, precision)).recip();
330 let significand = one - &eps;
331
332 let max_exp = rug::float::exp_max() - 1;
334 significand * rug::Float::with_val(precision, rug::Float::u_pow_u(2, max_exp as u32))
336 }
337
338 #[inline(always)]
339 fn raw_min_finite(precision: u32) -> Self {
340 Self::raw_max_finite(precision).neg()
341 }
342
343 #[inline(always)]
344 fn raw_epsilon(precision: u32) -> Self {
345 rug::Float::u_pow_u(2, precision - 1)
346 .complete(precision)
347 .recip()
348 }
349
350 #[inline(always)]
351 fn raw_ln_2(precision: u32) -> Self {
352 rug::Float::with_val(precision, MpfrConstant::Log2)
354 }
355
356 #[inline(always)]
357 fn raw_ln_10(precision: u32) -> Self {
358 let ln2 = rug::Float::with_val(precision, MpfrConstant::Log2);
361 let log2_10 = rug::Float::with_val(precision, 10).log2();
362 ln2 * log2_10
363 }
364
365 #[inline(always)]
366 fn raw_log10_2(precision: u32) -> Self {
367 rug::Float::with_val(precision, 2.).log10()
368 }
369
370 #[inline(always)]
371 fn raw_log2_10(precision: u32) -> Self {
372 rug::Float::with_val(precision, 10.).log2()
373 }
374
375 #[inline(always)]
376 fn raw_log2_e(precision: u32) -> Self {
377 rug::Float::with_val(precision, MpfrConstant::Log2).recip()
380 }
381
382 #[inline(always)]
383 fn raw_log10_e(precision: u32) -> Self {
384 let ln2 = rug::Float::with_val(precision, MpfrConstant::Log2);
386 let log2_10 = rug::Float::with_val(precision, 10).log2();
387 (ln2 * log2_10).recip()
388 }
389
390 #[inline(always)]
391 fn raw_e(precision: u32) -> Self {
392 rug::Float::with_val(precision, 1.).exp()
393 }
394
395 #[inline(always)]
396 fn truncate_to_usize(self) -> Result<usize, ErrorsRawRealToInteger<rug::Float, usize>> {
397 if !self.is_finite() {
398 return Err(ErrorsRawRealToInteger::NotFinite {
399 value: self,
400 backtrace: capture_backtrace(),
401 });
402 }
403
404 let truncation = self.clone().trunc();
405
406 let out_of_range = || ErrorsRawRealToInteger::OutOfRange {
407 value: self,
408 min: usize::MIN,
409 max: usize::MAX,
410 backtrace: capture_backtrace(),
411 };
412
413 let truncation_as_rug_integer = truncation.to_integer().ok_or_else(out_of_range.clone())?;
414
415 truncation_as_rug_integer
416 .to_usize()
417 .ok_or_else(out_of_range)
418 }
419}
420
421impl RawScalarValidate for rug::Complex {
422 type ValidationError = ErrorsValidationRawComplex<ErrorsValidationRawReal<rug::Float>>;
423
424 fn validate_raw_scalar_ref(&self) -> Result<(), Self::ValidationError> {
425 let real_validation = self.real().validate_raw_scalar_ref();
426 let imag_validation = self.imag().validate_raw_scalar_ref();
427 match (real_validation, imag_validation) {
428 (Ok(()), Ok(())) => Ok(()),
429 (Ok(()), Err(imag_err)) => Err(ErrorsValidationRawComplex::InvalidImaginaryPart {
430 source: Box::new(imag_err),
431 }),
432 (Err(real_err), Ok(())) => Err(ErrorsValidationRawComplex::InvalidRealPart {
433 source: Box::new(real_err),
434 }),
435 (Err(real_err), Err(imag_err)) => Err(ErrorsValidationRawComplex::InvalidBothParts {
436 real_error: Box::new(real_err),
437 imag_error: Box::new(imag_err),
438 }),
439 }
440 }
441}
442
443impl RawScalarTrait for rug::Complex {
444 fn raw_zero(precision: u32) -> Self {
445 rug::Complex::with_val(precision, (0., 0.))
446 }
447
448 fn is_zero(&self) -> bool {
449 rug::Complex::is_zero(self)
450 }
451
452 fn raw_one(precision: u32) -> Self {
453 rug::Complex::with_val(precision, (1., 0.))
454 }
455
456 #[duplicate_item(
457 unchecked_method method;
458 [unchecked_reciprocal] [recip];
459 [unchecked_exp] [exp];
460 [unchecked_sqrt] [sqrt];
461 [unchecked_ln] [ln];
462 [unchecked_log10] [log10];
463 )]
464 #[inline(always)]
465 fn unchecked_method(self) -> Self {
466 rug::Complex::method(self)
467 }
468
469 #[inline(always)]
470 fn unchecked_log2(self) -> Self {
471 let ln_2 = rug::Float::with_val(self.real().prec(), 2.).ln();
472 rug::Complex::ln(self) / ln_2
473 }
474
475 #[inline(always)]
479 fn unchecked_mul_add(self, b: &Self, c: &Self) -> Self {
480 rug::Complex::mul_add(self, b, c)
481 }
482
483 fn compute_hash_raw_scalar<H: Hasher>(&self, state: &mut H) {
484 self.raw_real_part().compute_hash_raw_scalar(state);
485 self.raw_imag_part().compute_hash_raw_scalar(state);
486 }
487}
488
489impl Conjugate for rug::Complex {
490 #[inline(always)]
491 fn conjugate(self) -> Self {
492 rug::Complex::conj(self)
493 }
494}
495
496impl RawComplexTrait for rug::Complex {
497 type RawReal = rug::Float;
498
499 fn new_unchecked_raw_complex(real: rug::Float, imag: rug::Float) -> Self {
500 debug_assert_eq!(
501 real.prec(),
502 imag.prec(),
503 "Different precision between real and imaginary part!"
504 );
505 rug::Complex::with_val(real.prec(), (real, imag))
506 }
507
508 fn mut_raw_real_part(&mut self) -> &mut rug::Float {
510 self.mut_real()
511 }
512
513 fn mut_raw_imag_part(&mut self) -> &mut rug::Float {
515 self.mut_imag()
516 }
517
518 #[inline(always)]
519 fn unchecked_abs(self) -> rug::Float {
520 rug::Complex::abs(self).into_real_imag().0
521 }
522
523 #[inline(always)]
524 fn raw_real_part(&self) -> &rug::Float {
525 self.real()
526 }
527
528 #[inline(always)]
529 fn raw_imag_part(&self) -> &rug::Float {
530 self.imag()
531 }
532
533 #[inline(always)]
534 fn unchecked_arg(self) -> rug::Float {
535 rug::Complex::arg(self).into_real_imag().0
536 }
537
538 #[inline(always)]
539 fn unchecked_pow_exponent_real(self, exponent: &rug::Float) -> Self {
540 rug::Complex::pow(self, exponent)
541 }
542}
543
544impl FpChecks for rug::Float {
545 fn is_finite(&self) -> bool {
546 rug::Float::is_finite(self)
547 }
548
549 fn is_infinite(&self) -> bool {
550 rug::Float::is_infinite(self)
551 }
552
553 fn is_nan(&self) -> bool {
554 rug::Float::is_nan(self)
555 }
556 fn is_normal(&self) -> bool {
557 rug::Float::is_normal(self)
558 }
559}
560
561impl FpChecks for rug::Complex {
562 #[inline(always)]
564 fn is_finite(&self) -> bool {
565 self.real().is_finite() && self.imag().is_finite()
566 }
567
568 #[inline(always)]
570 fn is_infinite(&self) -> bool {
571 !self.is_nan() && (self.real().is_infinite() || self.imag().is_infinite())
572 }
573
574 #[inline(always)]
576 fn is_nan(&self) -> bool {
577 self.real().is_nan() || self.imag().is_nan()
578 }
579
580 #[inline(always)]
582 fn is_normal(&self) -> bool {
583 self.real().is_normal() && self.imag().is_normal()
584 }
585}
586
587#[duplicate_item(
589 T;
590 [rug::Float];
591 [rug::Complex];
592)]
593impl NegAssign for T {
595 fn neg_assign(&mut self) {
597 <T as rug::ops::NegAssign>::neg_assign(self);
598 }
599}
600impl Sign for rug::Float {
603 #[inline(always)]
605 fn kernel_copysign(self, sign: &Self) -> Self {
606 self.copysign(sign)
607 }
608
609 #[inline(always)]
611 fn kernel_is_sign_negative(&self) -> bool {
612 self.is_sign_negative()
613 }
614
615 #[inline(always)]
617 fn kernel_is_sign_positive(&self) -> bool {
618 self.is_sign_positive()
619 }
620
621 #[inline(always)]
629 fn kernel_signum(self) -> Self {
630 self.signum()
631 }
632}
633
634impl Rounding for rug::Float {
635 #[inline(always)]
637 fn kernel_ceil(self) -> Self {
638 self.ceil()
639 }
640
641 #[inline(always)]
643 fn kernel_floor(self) -> Self {
644 self.floor()
645 }
646
647 #[inline(always)]
649 fn kernel_fract(self) -> Self {
650 self.fract()
651 }
652
653 #[inline(always)]
655 fn kernel_round(self) -> Self {
656 self.round()
657 }
658
659 #[inline(always)]
680 fn kernel_round_ties_even(self) -> Self {
681 self.round_even()
682 }
683
684 #[inline(always)]
701 fn kernel_trunc(self) -> Self {
702 self.trunc()
703 }
704}