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 term = *self;
185 let mut result = self.checked_add(Decimal::ONE)?;
186
187 for factorial in FACTORIAL.iter().skip(2) {
188 term = self.checked_mul(term)?;
189 let next = result + (term / factorial);
190 let diff = (next - result).abs();
191 result = next;
192 if diff <= tolerance {
193 break;
194 }
195 }
196
197 Some(result)
198 }
199
200 fn powi(&self, exp: i64) -> Decimal {
201 match self.checked_powi(exp) {
202 Some(result) => result,
203 None => panic!("Pow overflowed"),
204 }
205 }
206
207 fn checked_powi(&self, exp: i64) -> Option<Decimal> {
208 if exp >= 0 {
211 return self.checked_powu(exp as u64);
212 }
213
214 let exp = exp.unsigned_abs();
216 let pow = match self.checked_powu(exp) {
217 Some(v) => v,
218 None => return None,
219 };
220 Decimal::ONE.checked_div(pow)
221 }
222
223 fn powu(&self, exp: u64) -> Decimal {
224 match self.checked_powu(exp) {
225 Some(result) => result,
226 None => panic!("Pow overflowed"),
227 }
228 }
229
230 fn checked_powu(&self, exp: u64) -> Option<Decimal> {
231 if exp == 0 {
232 return Some(Decimal::ONE);
233 }
234 if self.is_zero() {
235 return Some(Decimal::ZERO);
236 }
237 if self.is_one() {
238 return Some(Decimal::ONE);
239 }
240
241 match exp {
242 0 => unreachable!(),
243 1 => Some(*self),
244 2 => self.checked_mul(*self),
245 _ => {
250 let mut product = Decimal::ONE;
251 let mut mask = exp;
252 let mut power = *self;
253
254 for n in 0..(64 - exp.leading_zeros()) {
256 if n > 0 {
257 power = power.checked_mul(power)?;
258 mask >>= 1;
259 }
260 if mask & 0x01 > 0 {
261 match product.checked_mul(power) {
262 Some(r) => product = r,
263 None => return None,
264 };
265 }
266 }
267 product.normalize_assign();
268 Some(product)
269 }
270 }
271 }
272
273 fn powf(&self, exp: f64) -> Decimal {
274 match self.checked_powf(exp) {
275 Some(result) => result,
276 None => panic!("Pow overflowed"),
277 }
278 }
279
280 fn checked_powf(&self, exp: f64) -> Option<Decimal> {
281 let exp = match Decimal::from_f64(exp) {
282 Some(f) => f,
283 None => return None,
284 };
285 self.checked_powd(exp)
286 }
287
288 fn powd(&self, exp: Decimal) -> Decimal {
289 match self.checked_powd(exp) {
290 Some(result) => result,
291 None => panic!("Pow overflowed"),
292 }
293 }
294
295 fn checked_powd(&self, exp: Decimal) -> Option<Decimal> {
296 if exp.is_zero() {
297 return Some(Decimal::ONE);
298 }
299 if self.is_zero() {
300 return Some(Decimal::ZERO);
301 }
302 if self.is_one() {
303 return Some(Decimal::ONE);
304 }
305 if exp.is_one() {
306 return Some(*self);
307 }
308
309 let exp = exp.normalize();
311 if exp.scale() == 0 {
312 if exp.mid() != 0 || exp.hi() != 0 {
313 return None;
315 }
316
317 return if exp.is_sign_negative() {
318 self.checked_powi(-(exp.lo() as i64))
319 } else {
320 self.checked_powu(exp.lo() as u64)
321 };
322 }
323
324 let negative = self.is_sign_negative();
327 let e = match self.abs().ln().checked_mul(exp) {
328 Some(e) => e,
329 None => return None,
330 };
331 let mut result = e.checked_exp()?;
332 result.set_sign_negative(negative);
333 Some(result)
334 }
335
336 fn sqrt(&self) -> Option<Decimal> {
337 if self.is_sign_negative() {
338 return None;
339 }
340
341 if self.is_zero() {
342 return Some(Decimal::ZERO);
343 }
344
345 let mut result = self / Decimal::TWO;
347 if result.is_zero() {
351 result = *self;
352 }
353 let mut last = result + Decimal::ONE;
354
355 let mut circuit_breaker = 0;
357 while last != result {
358 circuit_breaker += 1;
359 assert!(circuit_breaker < 1000, "geo mean circuit breaker");
360
361 last = result;
362 result = (result + self / result) / Decimal::TWO;
363 }
364
365 Some(result)
366 }
367
368 #[cfg(feature = "maths-nopanic")]
369 fn ln(&self) -> Decimal {
370 match self.checked_ln() {
371 Some(result) => result,
372 None => Decimal::ZERO,
373 }
374 }
375
376 #[cfg(not(feature = "maths-nopanic"))]
377 fn ln(&self) -> Decimal {
378 match self.checked_ln() {
379 Some(result) => result,
380 None => {
381 if self.is_sign_negative() {
382 panic!("Unable to calculate ln for negative numbers")
383 } else if self.is_zero() {
384 panic!("Unable to calculate ln for zero")
385 } else {
386 panic!("Calculation of ln failed for unknown reasons")
387 }
388 }
389 }
390 }
391
392 fn checked_ln(&self) -> Option<Decimal> {
393 if self.is_sign_negative() || self.is_zero() {
394 return None;
395 }
396 if self.is_one() {
397 return Some(Decimal::ZERO);
398 }
399
400 let mut x = *self;
402 let mut count = 0;
403 while x >= Decimal::ONE {
404 x *= Decimal::E_INVERSE;
405 count += 1;
406 }
407 while x <= Decimal::E_INVERSE {
408 x *= Decimal::E;
409 count -= 1;
410 }
411 x -= Decimal::ONE;
412 if x.is_zero() {
413 return Some(Decimal::new(count, 0));
414 }
415 let mut result = Decimal::ZERO;
416 let mut iteration = 0;
417 let mut y = Decimal::ONE;
418 let mut last = Decimal::ONE;
419 while last != result && iteration < 100 {
420 iteration += 1;
421 last = result;
422 y *= -x;
423 result += y / Decimal::new(iteration, 0);
424 }
425 Some(Decimal::new(count, 0) - result)
426 }
427
428 #[cfg(feature = "maths-nopanic")]
429 fn log10(&self) -> Decimal {
430 match self.checked_log10() {
431 Some(result) => result,
432 None => Decimal::ZERO,
433 }
434 }
435
436 #[cfg(not(feature = "maths-nopanic"))]
437 fn log10(&self) -> Decimal {
438 match self.checked_log10() {
439 Some(result) => result,
440 None => {
441 if self.is_sign_negative() {
442 panic!("Unable to calculate log10 for negative numbers")
443 } else if self.is_zero() {
444 panic!("Unable to calculate log10 for zero")
445 } else {
446 panic!("Calculation of log10 failed for unknown reasons")
447 }
448 }
449 }
450 }
451
452 fn checked_log10(&self) -> Option<Decimal> {
453 use crate::ops::array::{div_by_u32, is_all_zero};
454 if self.is_sign_negative() || self.is_zero() {
456 return None;
457 }
458 if self.is_one() {
459 return Some(Decimal::ZERO);
460 }
461
462 let scale = self.scale();
472 let mut working = self.mantissa_array3();
473
474 if scale > 0 && working[2] == 0 && working[1] == 0 && working[0] == 1 {
476 return Some(Decimal::from_parts(scale, 0, 0, true, 0));
477 }
478
479 let mut result = 0;
481 let mut base10 = true;
482 while !is_all_zero(&working) {
483 let remainder = div_by_u32(&mut working, 10u32);
484 if remainder != 0 {
485 base10 = false;
486 break;
487 }
488 result += 1;
489 if working[2] == 0 && working[1] == 0 && working[0] == 1 {
490 break;
491 }
492 }
493 if base10 {
494 return Some((result - scale as i32).into());
495 }
496
497 self.checked_ln().map(|result| LN10_INVERSE * result)
498 }
499
500 fn erf(&self) -> Decimal {
501 if self.is_sign_positive() {
502 let one = &Decimal::ONE;
503
504 let xa1 = self * Decimal::from_parts(705230784, 0, 0, false, 10);
505 let xa2 = self.powi(2) * Decimal::from_parts(422820123, 0, 0, false, 10);
506 let xa3 = self.powi(3) * Decimal::from_parts(92705272, 0, 0, false, 10);
507 let xa4 = self.powi(4) * Decimal::from_parts(1520143, 0, 0, false, 10);
508 let xa5 = self.powi(5) * Decimal::from_parts(2765672, 0, 0, false, 10);
509 let xa6 = self.powi(6) * Decimal::from_parts(430638, 0, 0, false, 10);
510
511 let sum = one + xa1 + xa2 + xa3 + xa4 + xa5 + xa6;
512 one - (one / sum.powi(16))
513 } else {
514 -self.abs().erf()
515 }
516 }
517
518 fn norm_cdf(&self) -> Decimal {
519 (Decimal::ONE + (self / Decimal::from_parts(2318911239, 3292722, 0, false, 16)).erf()) / Decimal::TWO
520 }
521
522 fn norm_pdf(&self) -> Decimal {
523 match self.checked_norm_pdf() {
524 Some(d) => d,
525 None => panic!("Norm Pdf overflowed"),
526 }
527 }
528
529 fn checked_norm_pdf(&self) -> Option<Decimal> {
530 let sqrt2pi = Decimal::from_parts_raw(2133383024, 2079885984, 1358845910, 1835008);
531 let factor = -self.checked_powi(2)?;
532 let factor = factor.checked_div(Decimal::TWO)?;
533 factor.checked_exp()?.checked_div(sqrt2pi)
534 }
535
536 fn sin(&self) -> Decimal {
537 match self.checked_sin() {
538 Some(x) => x,
539 None => panic!("Sin overflowed"),
540 }
541 }
542
543 fn checked_sin(&self) -> Option<Decimal> {
544 if self.is_zero() {
545 return Some(Decimal::ZERO);
546 }
547 if self.is_sign_negative() {
548 return (-self).checked_sin().map(|x| -x);
550 }
551 if self >= &Decimal::TWO_PI {
552 let adjusted = self.checked_rem(Decimal::TWO_PI)?;
554 return adjusted.checked_sin();
555 }
556 if self >= &Decimal::PI {
557 return (self - Decimal::PI).checked_sin().map(|x| -x);
559 }
560 if self > &Decimal::QUARTER_PI {
561 return (Decimal::HALF_PI - self).checked_cos();
563 }
564
565 let mut result = Decimal::ZERO;
570 for n in 0..TRIG_SERIES_UPPER_BOUND {
571 let x = 2 * n + 1;
572 let element = self.checked_powi(x as i64)?.checked_div(FACTORIAL[x])?;
573 if n & 0x1 == 0 {
574 result += element;
575 } else {
576 result -= element;
577 }
578 }
579 Some(result)
580 }
581
582 fn cos(&self) -> Decimal {
583 match self.checked_cos() {
584 Some(x) => x,
585 None => panic!("Cos overflowed"),
586 }
587 }
588
589 fn checked_cos(&self) -> Option<Decimal> {
590 if self.is_zero() {
591 return Some(Decimal::ONE);
592 }
593 if self.is_sign_negative() {
594 return (-self).checked_cos();
596 }
597 if self >= &Decimal::TWO_PI {
598 let adjusted = self.checked_rem(Decimal::TWO_PI)?;
600 return adjusted.checked_cos();
601 }
602 if self >= &Decimal::PI {
603 return (self - Decimal::PI).checked_cos().map(|x| -x);
605 }
606 if self > &Decimal::QUARTER_PI {
607 return (Decimal::HALF_PI - self).checked_sin();
609 }
610
611 let mut result = Decimal::ZERO;
616 for n in 0..TRIG_SERIES_UPPER_BOUND {
617 let x = 2 * n;
618 let element = self.checked_powi(x as i64)?.checked_div(FACTORIAL[x])?;
619 if n & 0x1 == 0 {
620 result += element;
621 } else {
622 result -= element;
623 }
624 }
625 Some(result)
626 }
627
628 fn tan(&self) -> Decimal {
629 match self.checked_tan() {
630 Some(x) => x,
631 None => panic!("Tan overflowed"),
632 }
633 }
634
635 fn checked_tan(&self) -> Option<Decimal> {
636 if self.is_zero() {
637 return Some(Decimal::ZERO);
638 }
639 if self.is_sign_negative() {
640 return (-self).checked_tan().map(|x| -x);
642 }
643 if self >= &Decimal::TWO_PI {
644 let adjusted = self.checked_rem(Decimal::TWO_PI)?;
646 return adjusted.checked_tan();
647 }
648 if self >= &Decimal::PI {
650 return (self - Decimal::PI).checked_tan();
652 }
653 if self > &Decimal::HALF_PI {
655 return ((Decimal::HALF_PI - self) + Decimal::HALF_PI).checked_tan().map(|x| -x);
658 }
659
660 if self > &Decimal::QUARTER_PI {
663 return match (Decimal::HALF_PI - self).checked_tan() {
664 Some(x) => Decimal::ONE.checked_div(x),
665 None => None,
666 };
667 }
668
669 if self > &EIGHTH_PI {
673 let tan_half = (self / Decimal::TWO).checked_tan()?;
675 let dividend = Decimal::TWO.checked_mul(tan_half)?;
677
678 let squared = tan_half.checked_mul(tan_half)?;
680 let divisor = Decimal::ONE - squared;
681 if divisor.is_zero() {
683 return None;
684 }
685 return dividend.checked_div(divisor);
686 }
687
688 const SERIES: [(Decimal, u64); 6] = [
702 (Decimal::from_parts_raw(89478485, 347537611, 180700362, 1835008), 3),
704 (Decimal::from_parts_raw(894784853, 3574988881, 72280144, 1835008), 5),
706 (Decimal::from_parts_raw(905437054, 3907911371, 2925624, 1769472), 7),
708 (Decimal::from_parts_raw(3191872741, 2108928381, 11855473, 1835008), 9),
710 (Decimal::from_parts_raw(3482645539, 2612995122, 4804769, 1835008), 11),
712 (Decimal::from_parts_raw(4189029078, 2192791200, 1947296, 1835008), 13),
714 ];
715 let mut result = *self;
716 for (fraction, pow) in SERIES {
717 result += fraction * self.powu(pow);
718 }
719 Some(result)
720 }
721}
722
723impl Pow<Decimal> for Decimal {
724 type Output = Decimal;
725
726 fn pow(self, rhs: Decimal) -> Self::Output {
727 MathematicalOps::powd(&self, rhs)
728 }
729}
730
731impl Pow<u64> for Decimal {
732 type Output = Decimal;
733
734 fn pow(self, rhs: u64) -> Self::Output {
735 MathematicalOps::powu(&self, rhs)
736 }
737}
738
739impl Pow<i64> for Decimal {
740 type Output = Decimal;
741
742 fn pow(self, rhs: i64) -> Self::Output {
743 MathematicalOps::powi(&self, rhs)
744 }
745}
746
747impl Pow<f64> for Decimal {
748 type Output = Decimal;
749
750 fn pow(self, rhs: f64) -> Self::Output {
751 MathematicalOps::powf(&self, rhs)
752 }
753}
754
755#[cfg(test)]
756mod test {
757 use super::*;
758
759 #[cfg(not(feature = "std"))]
760 use alloc::string::ToString;
761
762 #[test]
763 fn test_factorials() {
764 assert_eq!("1", FACTORIAL[0].to_string(), "0!");
765 assert_eq!("1", FACTORIAL[1].to_string(), "1!");
766 assert_eq!("2", FACTORIAL[2].to_string(), "2!");
767 assert_eq!("6", FACTORIAL[3].to_string(), "3!");
768 assert_eq!("24", FACTORIAL[4].to_string(), "4!");
769 assert_eq!("120", FACTORIAL[5].to_string(), "5!");
770 assert_eq!("720", FACTORIAL[6].to_string(), "6!");
771 assert_eq!("5040", FACTORIAL[7].to_string(), "7!");
772 assert_eq!("40320", FACTORIAL[8].to_string(), "8!");
773 assert_eq!("362880", FACTORIAL[9].to_string(), "9!");
774 assert_eq!("3628800", FACTORIAL[10].to_string(), "10!");
775 assert_eq!("39916800", FACTORIAL[11].to_string(), "11!");
776 assert_eq!("479001600", FACTORIAL[12].to_string(), "12!");
777 assert_eq!("6227020800", FACTORIAL[13].to_string(), "13!");
778 assert_eq!("87178291200", FACTORIAL[14].to_string(), "14!");
779 assert_eq!("1307674368000", FACTORIAL[15].to_string(), "15!");
780 assert_eq!("20922789888000", FACTORIAL[16].to_string(), "16!");
781 assert_eq!("355687428096000", FACTORIAL[17].to_string(), "17!");
782 assert_eq!("6402373705728000", FACTORIAL[18].to_string(), "18!");
783 assert_eq!("121645100408832000", FACTORIAL[19].to_string(), "19!");
784 assert_eq!("2432902008176640000", FACTORIAL[20].to_string(), "20!");
785 assert_eq!("51090942171709440000", FACTORIAL[21].to_string(), "21!");
786 assert_eq!("1124000727777607680000", FACTORIAL[22].to_string(), "22!");
787 assert_eq!("25852016738884976640000", FACTORIAL[23].to_string(), "23!");
788 assert_eq!("620448401733239439360000", FACTORIAL[24].to_string(), "24!");
789 assert_eq!("15511210043330985984000000", FACTORIAL[25].to_string(), "25!");
790 assert_eq!("403291461126605635584000000", FACTORIAL[26].to_string(), "26!");
791 assert_eq!("10888869450418352160768000000", FACTORIAL[27].to_string(), "27!");
792 }
793}