1use crate::prelude::*;
2use num_traits::pow::Pow;
3
4const EXP_TOLERANCE: Decimal = Decimal::from_parts(2, 0, 0, false, 7);
6const LN10_INVERSE: Decimal = Decimal::from_parts_raw(1763037029, 1670682625, 235431510, 1835008);
8const TRIG_SERIES_UPPER_BOUND: usize = 6;
10const EIGHTH_PI: Decimal = Decimal::from_parts_raw(2822163429, 3244459792, 212882598, 1835008);
12
13const FACTORIAL: [Decimal; 28] = [
15 Decimal::from_parts(1, 0, 0, false, 0),
16 Decimal::from_parts(1, 0, 0, false, 0),
17 Decimal::from_parts(2, 0, 0, false, 0),
18 Decimal::from_parts(6, 0, 0, false, 0),
19 Decimal::from_parts(24, 0, 0, false, 0),
20 Decimal::from_parts(120, 0, 0, false, 0),
22 Decimal::from_parts(720, 0, 0, false, 0),
23 Decimal::from_parts(5040, 0, 0, false, 0),
24 Decimal::from_parts(40320, 0, 0, false, 0),
25 Decimal::from_parts(362880, 0, 0, false, 0),
26 Decimal::from_parts(3628800, 0, 0, false, 0),
28 Decimal::from_parts(39916800, 0, 0, false, 0),
29 Decimal::from_parts(479001600, 0, 0, false, 0),
30 Decimal::from_parts(1932053504, 1, 0, false, 0),
31 Decimal::from_parts(1278945280, 20, 0, false, 0),
32 Decimal::from_parts(2004310016, 304, 0, false, 0),
34 Decimal::from_parts(2004189184, 4871, 0, false, 0),
35 Decimal::from_parts(4006445056, 82814, 0, false, 0),
36 Decimal::from_parts(3396534272, 1490668, 0, false, 0),
37 Decimal::from_parts(109641728, 28322707, 0, false, 0),
38 Decimal::from_parts(2192834560, 566454140, 0, false, 0),
40 Decimal::from_parts(3099852800, 3305602358, 2, false, 0),
41 Decimal::from_parts(3772252160, 4003775155, 60, false, 0),
42 Decimal::from_parts(862453760, 1892515369, 1401, false, 0),
43 Decimal::from_parts(3519021056, 2470695900, 33634, false, 0),
44 Decimal::from_parts(2076180480, 1637855376, 840864, false, 0),
46 Decimal::from_parts(2441084928, 3929534124, 21862473, false, 0),
47 Decimal::from_parts(1484783616, 3018206259, 590286795, false, 0),
48];
49
50pub trait MathematicalOps {
54 fn exp(&self) -> Decimal;
57
58 fn checked_exp(&self) -> Option<Decimal>;
61
62 fn exp_with_tolerance(&self, tolerance: Decimal) -> Decimal;
66
67 fn checked_exp_with_tolerance(&self, tolerance: Decimal) -> Option<Decimal>;
72
73 fn powi(&self, exp: i64) -> Decimal;
75
76 fn checked_powi(&self, exp: i64) -> Option<Decimal>;
78
79 fn powu(&self, exp: u64) -> Decimal;
81
82 fn checked_powu(&self, exp: u64) -> Option<Decimal>;
84
85 fn powf(&self, exp: f64) -> Decimal;
87
88 fn checked_powf(&self, exp: f64) -> Option<Decimal>;
90
91 fn powd(&self, exp: Decimal) -> Decimal;
94
95 fn checked_powd(&self, exp: Decimal) -> Option<Decimal>;
98
99 fn sqrt(&self) -> Option<Decimal>;
101
102 fn ln(&self) -> Decimal;
104
105 fn checked_ln(&self) -> Option<Decimal>;
108
109 fn log10(&self) -> Decimal;
111
112 fn checked_log10(&self) -> Option<Decimal>;
115
116 fn erf(&self) -> Decimal;
118
119 fn norm_cdf(&self) -> Decimal;
121
122 fn norm_pdf(&self) -> Decimal;
124
125 fn checked_norm_pdf(&self) -> Option<Decimal>;
127
128 fn sin(&self) -> Decimal;
131
132 fn checked_sin(&self) -> Option<Decimal>;
134
135 fn cos(&self) -> Decimal;
138
139 fn checked_cos(&self) -> Option<Decimal>;
141
142 fn tan(&self) -> Decimal;
145
146 fn checked_tan(&self) -> Option<Decimal>;
149}
150
151impl MathematicalOps for Decimal {
152 fn exp(&self) -> Decimal {
153 self.exp_with_tolerance(EXP_TOLERANCE)
154 }
155
156 fn checked_exp(&self) -> Option<Decimal> {
157 self.checked_exp_with_tolerance(EXP_TOLERANCE)
158 }
159
160 fn exp_with_tolerance(&self, tolerance: Decimal) -> Decimal {
161 match self.checked_exp_with_tolerance(tolerance) {
162 Some(d) => d,
163 None => {
164 if self.is_sign_negative() {
165 panic!("Exp underflowed")
166 } else {
167 panic!("Exp overflowed")
168 }
169 }
170 }
171 }
172
173 fn checked_exp_with_tolerance(&self, tolerance: Decimal) -> Option<Decimal> {
174 if self.is_zero() {
175 return Some(Decimal::ONE);
176 }
177 if self.is_sign_negative() {
178 let mut flipped = *self;
179 flipped.set_sign_positive(true);
180 let exp = flipped.checked_exp_with_tolerance(tolerance)?;
181 return Decimal::ONE.checked_div(exp);
182 }
183
184 let mut result = self.checked_add(Decimal::ONE)?;
190
191 let mut term = *self;
193
194 const ITERATION_COUNT: u32 = 200;
198
199 for i in 2..ITERATION_COUNT {
200 let i_dec = Decimal::from_u32(i).unwrap();
202
203 term = self.checked_mul(term.checked_div(i_dec)?)?;
204
205 result = result.checked_add(term)?;
206
207 if term <= tolerance {
209 break;
210 }
211 }
212
213 Some(result)
214 }
215
216 fn powi(&self, exp: i64) -> Decimal {
217 match self.checked_powi(exp) {
218 Some(result) => result,
219 None => panic!("Pow overflowed"),
220 }
221 }
222
223 fn checked_powi(&self, exp: i64) -> Option<Decimal> {
224 if exp >= 0 {
227 return self.checked_powu(exp as u64);
228 }
229
230 let exp = exp.unsigned_abs();
232 let pow = match self.checked_powu(exp) {
233 Some(v) => v,
234 None => return None,
235 };
236 Decimal::ONE.checked_div(pow)
237 }
238
239 fn powu(&self, exp: u64) -> Decimal {
240 match self.checked_powu(exp) {
241 Some(result) => result,
242 None => panic!("Pow overflowed"),
243 }
244 }
245
246 fn checked_powu(&self, exp: u64) -> Option<Decimal> {
247 if exp == 0 {
248 return Some(Decimal::ONE);
249 }
250 if self.is_zero() {
251 return Some(Decimal::ZERO);
252 }
253 if self.is_one() {
254 return Some(Decimal::ONE);
255 }
256
257 match exp {
258 0 => unreachable!(),
259 1 => Some(*self),
260 2 => self.checked_mul(*self),
261 _ => {
266 let mut product = Decimal::ONE;
267 let mut mask = exp;
268 let mut power = *self;
269
270 for n in 0..(64 - exp.leading_zeros()) {
272 if n > 0 {
273 power = power.checked_mul(power)?;
274 mask >>= 1;
275 }
276 if mask & 0x01 > 0 {
277 match product.checked_mul(power) {
278 Some(r) => product = r,
279 None => return None,
280 };
281 }
282 }
283 product.normalize_assign();
284 Some(product)
285 }
286 }
287 }
288
289 fn powf(&self, exp: f64) -> Decimal {
290 match self.checked_powf(exp) {
291 Some(result) => result,
292 None => panic!("Pow overflowed"),
293 }
294 }
295
296 fn checked_powf(&self, exp: f64) -> Option<Decimal> {
297 let exp = match Decimal::from_f64(exp) {
298 Some(f) => f,
299 None => return None,
300 };
301 self.checked_powd(exp)
302 }
303
304 fn powd(&self, exp: Decimal) -> Decimal {
305 match self.checked_powd(exp) {
306 Some(result) => result,
307 None => panic!("Pow overflowed"),
308 }
309 }
310
311 fn checked_powd(&self, exp: Decimal) -> Option<Decimal> {
312 if exp.is_zero() {
313 return Some(Decimal::ONE);
314 }
315 if self.is_zero() {
316 return Some(Decimal::ZERO);
317 }
318 if self.is_one() {
319 return Some(Decimal::ONE);
320 }
321 if exp.is_one() {
322 return Some(*self);
323 }
324
325 let exp = exp.normalize();
327 if exp.scale() == 0 {
328 if exp.mid() != 0 || exp.hi() != 0 {
329 return None;
331 }
332
333 return if exp.is_sign_negative() {
334 self.checked_powi(-(exp.lo() as i64))
335 } else {
336 self.checked_powu(exp.lo() as u64)
337 };
338 }
339
340 let negative = self.is_sign_negative();
343 let e = match self.abs().ln().checked_mul(exp) {
344 Some(e) => e,
345 None => return None,
346 };
347 let mut result = e.checked_exp()?;
348 result.set_sign_negative(negative);
349 Some(result)
350 }
351
352 fn sqrt(&self) -> Option<Decimal> {
353 if self.is_sign_negative() {
354 return None;
355 }
356
357 if self.is_zero() {
358 return Some(Decimal::ZERO);
359 }
360
361 let mut result = self / Decimal::TWO;
363 if result.is_zero() {
367 result = *self;
368 }
369 let mut last = result + Decimal::ONE;
370
371 let mut circuit_breaker = 0;
373 while last != result {
374 circuit_breaker += 1;
375 assert!(circuit_breaker < 1000, "geo mean circuit breaker");
376
377 last = result;
378 result = (result + self / result) / Decimal::TWO;
379 }
380
381 Some(result)
382 }
383
384 #[cfg(feature = "maths-nopanic")]
385 fn ln(&self) -> Decimal {
386 match self.checked_ln() {
387 Some(result) => result,
388 None => Decimal::ZERO,
389 }
390 }
391
392 #[cfg(not(feature = "maths-nopanic"))]
393 fn ln(&self) -> Decimal {
394 match self.checked_ln() {
395 Some(result) => result,
396 None => {
397 if self.is_sign_negative() {
398 panic!("Unable to calculate ln for negative numbers")
399 } else if self.is_zero() {
400 panic!("Unable to calculate ln for zero")
401 } else {
402 panic!("Calculation of ln failed for unknown reasons")
403 }
404 }
405 }
406 }
407
408 fn checked_ln(&self) -> Option<Decimal> {
409 if self.is_sign_negative() || self.is_zero() {
410 return None;
411 }
412 if self.is_one() {
413 return Some(Decimal::ZERO);
414 }
415
416 let mut x = *self;
418 let mut count = 0;
419 while x >= Decimal::ONE {
420 x *= Decimal::E_INVERSE;
421 count += 1;
422 }
423 while x <= Decimal::E_INVERSE {
424 x *= Decimal::E;
425 count -= 1;
426 }
427 x -= Decimal::ONE;
428 if x.is_zero() {
429 return Some(Decimal::new(count, 0));
430 }
431 let mut result = Decimal::ZERO;
432 let mut iteration = 0;
433 let mut y = Decimal::ONE;
434 let mut last = Decimal::ONE;
435 while last != result && iteration < 100 {
436 iteration += 1;
437 last = result;
438 y *= -x;
439 result += y / Decimal::new(iteration, 0);
440 }
441 Some(Decimal::new(count, 0) - result)
442 }
443
444 #[cfg(feature = "maths-nopanic")]
445 fn log10(&self) -> Decimal {
446 match self.checked_log10() {
447 Some(result) => result,
448 None => Decimal::ZERO,
449 }
450 }
451
452 #[cfg(not(feature = "maths-nopanic"))]
453 fn log10(&self) -> Decimal {
454 match self.checked_log10() {
455 Some(result) => result,
456 None => {
457 if self.is_sign_negative() {
458 panic!("Unable to calculate log10 for negative numbers")
459 } else if self.is_zero() {
460 panic!("Unable to calculate log10 for zero")
461 } else {
462 panic!("Calculation of log10 failed for unknown reasons")
463 }
464 }
465 }
466 }
467
468 fn checked_log10(&self) -> Option<Decimal> {
469 use crate::ops::array::{div_by_u32, is_all_zero};
470 if self.is_sign_negative() || self.is_zero() {
472 return None;
473 }
474 if self.is_one() {
475 return Some(Decimal::ZERO);
476 }
477
478 let scale = self.scale();
488 let mut working = self.mantissa_array3();
489
490 if scale > 0 && working[2] == 0 && working[1] == 0 && working[0] == 1 {
492 return Some(Decimal::from_parts(scale, 0, 0, true, 0));
493 }
494
495 let mut result = 0;
497 let mut base10 = true;
498 while !is_all_zero(&working) {
499 let remainder = div_by_u32(&mut working, 10u32);
500 if remainder != 0 {
501 base10 = false;
502 break;
503 }
504 result += 1;
505 if working[2] == 0 && working[1] == 0 && working[0] == 1 {
506 break;
507 }
508 }
509 if base10 {
510 return Some((result - scale as i32).into());
511 }
512
513 self.checked_ln().map(|result| LN10_INVERSE * result)
514 }
515
516 fn erf(&self) -> Decimal {
517 if self.is_sign_positive() {
518 let one = &Decimal::ONE;
519
520 let xa1 = self * Decimal::from_parts(705230784, 0, 0, false, 10);
521 let xa2 = self.powi(2) * Decimal::from_parts(422820123, 0, 0, false, 10);
522 let xa3 = self.powi(3) * Decimal::from_parts(92705272, 0, 0, false, 10);
523 let xa4 = self.powi(4) * Decimal::from_parts(1520143, 0, 0, false, 10);
524 let xa5 = self.powi(5) * Decimal::from_parts(2765672, 0, 0, false, 10);
525 let xa6 = self.powi(6) * Decimal::from_parts(430638, 0, 0, false, 10);
526
527 let sum = one + xa1 + xa2 + xa3 + xa4 + xa5 + xa6;
528 one - (one / sum.powi(16))
529 } else {
530 -self.abs().erf()
531 }
532 }
533
534 fn norm_cdf(&self) -> Decimal {
535 (Decimal::ONE + (self / Decimal::from_parts(2318911239, 3292722, 0, false, 16)).erf()) / Decimal::TWO
536 }
537
538 fn norm_pdf(&self) -> Decimal {
539 match self.checked_norm_pdf() {
540 Some(d) => d,
541 None => panic!("Norm Pdf overflowed"),
542 }
543 }
544
545 fn checked_norm_pdf(&self) -> Option<Decimal> {
546 let sqrt2pi = Decimal::from_parts_raw(2133383024, 2079885984, 1358845910, 1835008);
547 let factor = -self.checked_powi(2)?;
548 let factor = factor.checked_div(Decimal::TWO)?;
549 factor.checked_exp()?.checked_div(sqrt2pi)
550 }
551
552 fn sin(&self) -> Decimal {
553 match self.checked_sin() {
554 Some(x) => x,
555 None => panic!("Sin overflowed"),
556 }
557 }
558
559 fn checked_sin(&self) -> Option<Decimal> {
560 if self.is_zero() {
561 return Some(Decimal::ZERO);
562 }
563 if self.is_sign_negative() {
564 return (-self).checked_sin().map(|x| -x);
566 }
567 if self >= &Decimal::TWO_PI {
568 let adjusted = self.checked_rem(Decimal::TWO_PI)?;
570 return adjusted.checked_sin();
571 }
572 if self >= &Decimal::PI {
573 return (self - Decimal::PI).checked_sin().map(|x| -x);
575 }
576 if self > &Decimal::QUARTER_PI {
577 return (Decimal::HALF_PI - self).checked_cos();
579 }
580
581 let mut result = Decimal::ZERO;
586 for n in 0..TRIG_SERIES_UPPER_BOUND {
587 let x = 2 * n + 1;
588 let element = self.checked_powi(x as i64)?.checked_div(FACTORIAL[x])?;
589 if n & 0x1 == 0 {
590 result += element;
591 } else {
592 result -= element;
593 }
594 }
595 Some(result)
596 }
597
598 fn cos(&self) -> Decimal {
599 match self.checked_cos() {
600 Some(x) => x,
601 None => panic!("Cos overflowed"),
602 }
603 }
604
605 fn checked_cos(&self) -> Option<Decimal> {
606 if self.is_zero() {
607 return Some(Decimal::ONE);
608 }
609 if self.is_sign_negative() {
610 return (-self).checked_cos();
612 }
613 if self >= &Decimal::TWO_PI {
614 let adjusted = self.checked_rem(Decimal::TWO_PI)?;
616 return adjusted.checked_cos();
617 }
618 if self >= &Decimal::PI {
619 return (self - Decimal::PI).checked_cos().map(|x| -x);
621 }
622 if self > &Decimal::QUARTER_PI {
623 return (Decimal::HALF_PI - self).checked_sin();
625 }
626
627 let mut result = Decimal::ZERO;
632 for n in 0..TRIG_SERIES_UPPER_BOUND {
633 let x = 2 * n;
634 let element = self.checked_powi(x as i64)?.checked_div(FACTORIAL[x])?;
635 if n & 0x1 == 0 {
636 result += element;
637 } else {
638 result -= element;
639 }
640 }
641 Some(result)
642 }
643
644 fn tan(&self) -> Decimal {
645 match self.checked_tan() {
646 Some(x) => x,
647 None => panic!("Tan overflowed"),
648 }
649 }
650
651 fn checked_tan(&self) -> Option<Decimal> {
652 if self.is_zero() {
653 return Some(Decimal::ZERO);
654 }
655 if self.is_sign_negative() {
656 return (-self).checked_tan().map(|x| -x);
658 }
659 if self >= &Decimal::TWO_PI {
660 let adjusted = self.checked_rem(Decimal::TWO_PI)?;
662 return adjusted.checked_tan();
663 }
664 if self >= &Decimal::PI {
666 return (self - Decimal::PI).checked_tan();
668 }
669 if self > &Decimal::HALF_PI {
671 return ((Decimal::HALF_PI - self) + Decimal::HALF_PI).checked_tan().map(|x| -x);
674 }
675
676 if self > &Decimal::QUARTER_PI {
679 return match (Decimal::HALF_PI - self).checked_tan() {
680 Some(x) => Decimal::ONE.checked_div(x),
681 None => None,
682 };
683 }
684
685 if self > &EIGHTH_PI {
689 let tan_half = (self / Decimal::TWO).checked_tan()?;
691 let dividend = Decimal::TWO.checked_mul(tan_half)?;
693
694 let squared = tan_half.checked_mul(tan_half)?;
696 let divisor = Decimal::ONE - squared;
697 if divisor.is_zero() {
699 return None;
700 }
701 return dividend.checked_div(divisor);
702 }
703
704 const SERIES: [(Decimal, u64); 6] = [
718 (Decimal::from_parts_raw(89478485, 347537611, 180700362, 1835008), 3),
720 (Decimal::from_parts_raw(894784853, 3574988881, 72280144, 1835008), 5),
722 (Decimal::from_parts_raw(905437054, 3907911371, 2925624, 1769472), 7),
724 (Decimal::from_parts_raw(3191872741, 2108928381, 11855473, 1835008), 9),
726 (Decimal::from_parts_raw(3482645539, 2612995122, 4804769, 1835008), 11),
728 (Decimal::from_parts_raw(4189029078, 2192791200, 1947296, 1835008), 13),
730 ];
731 let mut result = *self;
732 for (fraction, pow) in SERIES {
733 result += fraction * self.powu(pow);
734 }
735 Some(result)
736 }
737}
738
739impl Pow<Decimal> for Decimal {
740 type Output = Decimal;
741
742 fn pow(self, rhs: Decimal) -> Self::Output {
743 MathematicalOps::powd(&self, rhs)
744 }
745}
746
747impl Pow<u64> for Decimal {
748 type Output = Decimal;
749
750 fn pow(self, rhs: u64) -> Self::Output {
751 MathematicalOps::powu(&self, rhs)
752 }
753}
754
755impl Pow<i64> for Decimal {
756 type Output = Decimal;
757
758 fn pow(self, rhs: i64) -> Self::Output {
759 MathematicalOps::powi(&self, rhs)
760 }
761}
762
763impl Pow<f64> for Decimal {
764 type Output = Decimal;
765
766 fn pow(self, rhs: f64) -> Self::Output {
767 MathematicalOps::powf(&self, rhs)
768 }
769}
770
771#[cfg(test)]
772mod test {
773 use super::*;
774
775 #[cfg(not(feature = "std"))]
776 use alloc::string::ToString;
777
778 #[test]
779 fn test_factorials() {
780 assert_eq!("1", FACTORIAL[0].to_string(), "0!");
781 assert_eq!("1", FACTORIAL[1].to_string(), "1!");
782 assert_eq!("2", FACTORIAL[2].to_string(), "2!");
783 assert_eq!("6", FACTORIAL[3].to_string(), "3!");
784 assert_eq!("24", FACTORIAL[4].to_string(), "4!");
785 assert_eq!("120", FACTORIAL[5].to_string(), "5!");
786 assert_eq!("720", FACTORIAL[6].to_string(), "6!");
787 assert_eq!("5040", FACTORIAL[7].to_string(), "7!");
788 assert_eq!("40320", FACTORIAL[8].to_string(), "8!");
789 assert_eq!("362880", FACTORIAL[9].to_string(), "9!");
790 assert_eq!("3628800", FACTORIAL[10].to_string(), "10!");
791 assert_eq!("39916800", FACTORIAL[11].to_string(), "11!");
792 assert_eq!("479001600", FACTORIAL[12].to_string(), "12!");
793 assert_eq!("6227020800", FACTORIAL[13].to_string(), "13!");
794 assert_eq!("87178291200", FACTORIAL[14].to_string(), "14!");
795 assert_eq!("1307674368000", FACTORIAL[15].to_string(), "15!");
796 assert_eq!("20922789888000", FACTORIAL[16].to_string(), "16!");
797 assert_eq!("355687428096000", FACTORIAL[17].to_string(), "17!");
798 assert_eq!("6402373705728000", FACTORIAL[18].to_string(), "18!");
799 assert_eq!("121645100408832000", FACTORIAL[19].to_string(), "19!");
800 assert_eq!("2432902008176640000", FACTORIAL[20].to_string(), "20!");
801 assert_eq!("51090942171709440000", FACTORIAL[21].to_string(), "21!");
802 assert_eq!("1124000727777607680000", FACTORIAL[22].to_string(), "22!");
803 assert_eq!("25852016738884976640000", FACTORIAL[23].to_string(), "23!");
804 assert_eq!("620448401733239439360000", FACTORIAL[24].to_string(), "24!");
805 assert_eq!("15511210043330985984000000", FACTORIAL[25].to_string(), "25!");
806 assert_eq!("403291461126605635584000000", FACTORIAL[26].to_string(), "26!");
807 assert_eq!("10888869450418352160768000000", FACTORIAL[27].to_string(), "27!");
808 }
809}