1use crate::prelude::*;
2use num_traits::pow::Pow;
3
4const LN10_INVERSE: Decimal = Decimal::from_parts_raw(1763037029, 1670682625, 235431510, 1835008);
6const EIGHTH_PI: Decimal = Decimal::from_parts_raw(2822163429, 3244459792, 212882598, 1835008);
8
9#[cfg(test)]
11const FACTORIAL: [Decimal; 28] = [
12 Decimal::from_parts(1, 0, 0, false, 0),
13 Decimal::from_parts(1, 0, 0, false, 0),
14 Decimal::from_parts(2, 0, 0, false, 0),
15 Decimal::from_parts(6, 0, 0, false, 0),
16 Decimal::from_parts(24, 0, 0, false, 0),
17 Decimal::from_parts(120, 0, 0, false, 0),
19 Decimal::from_parts(720, 0, 0, false, 0),
20 Decimal::from_parts(5040, 0, 0, false, 0),
21 Decimal::from_parts(40320, 0, 0, false, 0),
22 Decimal::from_parts(362880, 0, 0, false, 0),
23 Decimal::from_parts(3628800, 0, 0, false, 0),
25 Decimal::from_parts(39916800, 0, 0, false, 0),
26 Decimal::from_parts(479001600, 0, 0, false, 0),
27 Decimal::from_parts(1932053504, 1, 0, false, 0),
28 Decimal::from_parts(1278945280, 20, 0, false, 0),
29 Decimal::from_parts(2004310016, 304, 0, false, 0),
31 Decimal::from_parts(2004189184, 4871, 0, false, 0),
32 Decimal::from_parts(4006445056, 82814, 0, false, 0),
33 Decimal::from_parts(3396534272, 1490668, 0, false, 0),
34 Decimal::from_parts(109641728, 28322707, 0, false, 0),
35 Decimal::from_parts(2192834560, 566454140, 0, false, 0),
37 Decimal::from_parts(3099852800, 3305602358, 2, false, 0),
38 Decimal::from_parts(3772252160, 4003775155, 60, false, 0),
39 Decimal::from_parts(862453760, 1892515369, 1401, false, 0),
40 Decimal::from_parts(3519021056, 2470695900, 33634, false, 0),
41 Decimal::from_parts(2076180480, 1637855376, 840864, false, 0),
43 Decimal::from_parts(2441084928, 3929534124, 21862473, false, 0),
44 Decimal::from_parts(1484783616, 3018206259, 590286795, false, 0),
45];
46
47pub trait MathematicalOps {
51 fn exp(&self) -> Decimal;
54
55 fn checked_exp(&self) -> Option<Decimal>;
58
59 fn exp_with_tolerance(&self, tolerance: Decimal) -> Decimal;
63
64 fn checked_exp_with_tolerance(&self, tolerance: Decimal) -> Option<Decimal>;
69
70 fn powi(&self, exp: i64) -> Decimal;
72
73 fn checked_powi(&self, exp: i64) -> Option<Decimal>;
75
76 fn powu(&self, exp: u64) -> Decimal;
78
79 fn checked_powu(&self, exp: u64) -> Option<Decimal>;
81
82 fn powf(&self, exp: f64) -> Decimal;
84
85 fn checked_powf(&self, exp: f64) -> Option<Decimal>;
87
88 fn powd(&self, exp: Decimal) -> Decimal;
91
92 fn checked_powd(&self, exp: Decimal) -> Option<Decimal>;
95
96 fn sqrt(&self) -> Option<Decimal>;
98
99 fn ln(&self) -> Decimal;
101
102 fn checked_ln(&self) -> Option<Decimal>;
105
106 fn log10(&self) -> Decimal;
108
109 fn checked_log10(&self) -> Option<Decimal>;
112
113 fn erf(&self) -> Decimal;
115
116 fn norm_cdf(&self) -> Decimal;
118
119 fn norm_pdf(&self) -> Decimal;
121
122 fn checked_norm_pdf(&self) -> Option<Decimal>;
124
125 fn sin(&self) -> Decimal;
128
129 fn checked_sin(&self) -> Option<Decimal>;
131
132 fn cos(&self) -> Decimal;
135
136 fn checked_cos(&self) -> Option<Decimal>;
138
139 fn tan(&self) -> Decimal;
142
143 fn checked_tan(&self) -> Option<Decimal>;
146}
147
148impl MathematicalOps for Decimal {
149 fn exp(&self) -> Decimal {
150 match self.checked_exp() {
151 Some(d) => d,
152 None => {
153 if self.is_sign_negative() {
154 panic!("Exp underflowed")
155 } else {
156 panic!("Exp overflowed")
157 }
158 }
159 }
160 }
161
162 fn checked_exp(&self) -> Option<Decimal> {
163 crate::ops::wide::exp_wide(self)
164 }
165
166 fn exp_with_tolerance(&self, tolerance: Decimal) -> Decimal {
167 match self.checked_exp_with_tolerance(tolerance) {
168 Some(d) => d,
169 None => {
170 if self.is_sign_negative() {
171 panic!("Exp underflowed")
172 } else {
173 panic!("Exp overflowed")
174 }
175 }
176 }
177 }
178
179 fn checked_exp_with_tolerance(&self, tolerance: Decimal) -> Option<Decimal> {
180 if self.is_zero() {
181 return Some(Decimal::ONE);
182 }
183 if self.is_sign_negative() {
184 let mut flipped = *self;
185 flipped.set_sign_positive(true);
186 let exp = flipped.checked_exp_with_tolerance(tolerance)?;
187 return Decimal::ONE.checked_div(exp);
188 }
189
190 let mut result = self.checked_add(Decimal::ONE)?;
195 let mut term = *self;
196
197 for i in 2..200u32 {
198 let i_dec = Decimal::from_u32(i).unwrap();
199 term = self.checked_mul(term.checked_div(i_dec)?)?;
200 result = result.checked_add(term)?;
201 if term <= tolerance {
202 break;
203 }
204 }
205
206 Some(result)
207 }
208
209 fn powi(&self, exp: i64) -> Decimal {
210 match self.checked_powi(exp) {
211 Some(result) => result,
212 None => panic!("Pow overflowed"),
213 }
214 }
215
216 fn checked_powi(&self, exp: i64) -> Option<Decimal> {
217 if exp >= 0 {
220 return self.checked_powu(exp as u64);
221 }
222
223 let exp = exp.unsigned_abs();
225 let pow = self.checked_powu(exp)?;
226 Decimal::ONE.checked_div(pow)
227 }
228
229 fn powu(&self, exp: u64) -> Decimal {
230 match self.checked_powu(exp) {
231 Some(result) => result,
232 None => panic!("Pow overflowed"),
233 }
234 }
235
236 fn checked_powu(&self, exp: u64) -> Option<Decimal> {
237 crate::ops::wide::powu_wide(self, exp)
238 }
239
240 fn powf(&self, exp: f64) -> Decimal {
241 match self.checked_powf(exp) {
242 Some(result) => result,
243 None => panic!("Pow overflowed"),
244 }
245 }
246
247 fn checked_powf(&self, exp: f64) -> Option<Decimal> {
248 let exp = Decimal::from_f64(exp)?;
249 self.checked_powd(exp)
250 }
251
252 fn powd(&self, exp: Decimal) -> Decimal {
253 match self.checked_powd(exp) {
254 Some(result) => result,
255 None => panic!("Pow overflowed"),
256 }
257 }
258
259 fn checked_powd(&self, exp: Decimal) -> Option<Decimal> {
260 if exp.is_zero() {
261 return Some(Decimal::ONE);
262 }
263 if self.is_zero() {
264 return Some(Decimal::ZERO);
265 }
266 if self.is_one() {
267 return Some(Decimal::ONE);
268 }
269 if exp.is_one() {
270 return Some(*self);
271 }
272
273 let exp = exp.normalize();
275 if exp.scale() == 0 {
276 if exp.mid() != 0 || exp.hi() != 0 {
277 return None;
279 }
280
281 return if exp.is_sign_negative() {
282 self.checked_powi(-(exp.lo() as i64))
283 } else {
284 self.checked_powu(exp.lo() as u64)
285 };
286 }
287
288 let negative = self.is_sign_negative();
291 let e = self.abs().ln().checked_mul(exp)?;
292 let mut result = e.checked_exp()?;
293 result.set_sign_negative(negative);
294 Some(result)
295 }
296
297 fn sqrt(&self) -> Option<Decimal> {
298 if self.is_sign_negative() {
299 return None;
300 }
301
302 if self.is_zero() {
303 return Some(Decimal::ZERO);
304 }
305
306 let mut result = self / Decimal::TWO;
308 if result.is_zero() {
312 result = *self;
313 }
314 let mut last = result + Decimal::ONE;
315
316 let mut circuit_breaker = 0;
318 while last != result {
319 circuit_breaker += 1;
320 assert!(circuit_breaker < 1000, "geo mean circuit breaker");
321
322 last = result;
323 result = (result + self / result) / Decimal::TWO;
324 }
325
326 Some(result)
327 }
328
329 #[cfg(feature = "maths-nopanic")]
330 fn ln(&self) -> Decimal {
331 match self.checked_ln() {
332 Some(result) => result,
333 None => Decimal::ZERO,
334 }
335 }
336
337 #[cfg(not(feature = "maths-nopanic"))]
338 fn ln(&self) -> Decimal {
339 match self.checked_ln() {
340 Some(result) => result,
341 None => {
342 if self.is_sign_negative() {
343 panic!("Unable to calculate ln for negative numbers")
344 } else if self.is_zero() {
345 panic!("Unable to calculate ln for zero")
346 } else {
347 panic!("Calculation of ln failed for unknown reasons")
348 }
349 }
350 }
351 }
352
353 fn checked_ln(&self) -> Option<Decimal> {
354 crate::ops::wide::ln_wide(self)
355 }
356
357 #[cfg(feature = "maths-nopanic")]
358 fn log10(&self) -> Decimal {
359 match self.checked_log10() {
360 Some(result) => result,
361 None => Decimal::ZERO,
362 }
363 }
364
365 #[cfg(not(feature = "maths-nopanic"))]
366 fn log10(&self) -> Decimal {
367 match self.checked_log10() {
368 Some(result) => result,
369 None => {
370 if self.is_sign_negative() {
371 panic!("Unable to calculate log10 for negative numbers")
372 } else if self.is_zero() {
373 panic!("Unable to calculate log10 for zero")
374 } else {
375 panic!("Calculation of log10 failed for unknown reasons")
376 }
377 }
378 }
379 }
380
381 fn checked_log10(&self) -> Option<Decimal> {
382 use crate::ops::array::{div_by_u32, is_all_zero};
383 if self.is_sign_negative() || self.is_zero() {
385 return None;
386 }
387 if self.is_one() {
388 return Some(Decimal::ZERO);
389 }
390
391 let scale = self.scale();
401 let mut working = self.mantissa_array3();
402
403 if scale > 0 && working[2] == 0 && working[1] == 0 && working[0] == 1 {
405 return Some(Decimal::from_parts(scale, 0, 0, true, 0));
406 }
407
408 let mut result = 0;
410 let mut base10 = true;
411 while !is_all_zero(&working) {
412 let remainder = div_by_u32(&mut working, 10u32);
413 if remainder != 0 {
414 base10 = false;
415 break;
416 }
417 result += 1;
418 if working[2] == 0 && working[1] == 0 && working[0] == 1 {
419 break;
420 }
421 }
422 if base10 {
423 return Some((result - scale as i32).into());
424 }
425
426 self.checked_ln().map(|result| LN10_INVERSE * result)
427 }
428
429 fn erf(&self) -> Decimal {
430 if self.is_sign_positive() {
431 let one = &Decimal::ONE;
432
433 let xa1 = self * Decimal::from_parts(705230784, 0, 0, false, 10);
434 let xa2 = self.powi(2) * Decimal::from_parts(422820123, 0, 0, false, 10);
435 let xa3 = self.powi(3) * Decimal::from_parts(92705272, 0, 0, false, 10);
436 let xa4 = self.powi(4) * Decimal::from_parts(1520143, 0, 0, false, 10);
437 let xa5 = self.powi(5) * Decimal::from_parts(2765672, 0, 0, false, 10);
438 let xa6 = self.powi(6) * Decimal::from_parts(430638, 0, 0, false, 10);
439
440 let sum = one + xa1 + xa2 + xa3 + xa4 + xa5 + xa6;
441 one - (one / sum.powi(16))
442 } else {
443 -self.abs().erf()
444 }
445 }
446
447 fn norm_cdf(&self) -> Decimal {
448 (Decimal::ONE + (self / Decimal::from_parts(2318911239, 3292722, 0, false, 16)).erf()) / Decimal::TWO
449 }
450
451 fn norm_pdf(&self) -> Decimal {
452 match self.checked_norm_pdf() {
453 Some(d) => d,
454 None => panic!("Norm Pdf overflowed"),
455 }
456 }
457
458 fn checked_norm_pdf(&self) -> Option<Decimal> {
459 let sqrt2pi = Decimal::from_parts_raw(2133383024, 2079885984, 1358845910, 1835008);
460 let factor = -self.checked_powi(2)?;
461 let factor = factor.checked_div(Decimal::TWO)?;
462 factor.checked_exp()?.checked_div(sqrt2pi)
463 }
464
465 fn sin(&self) -> Decimal {
466 match self.checked_sin() {
467 Some(x) => x,
468 None => panic!("Sin overflowed"),
469 }
470 }
471
472 fn checked_sin(&self) -> Option<Decimal> {
473 crate::ops::wide::sin_wide(self)
474 }
475
476 fn cos(&self) -> Decimal {
477 match self.checked_cos() {
478 Some(x) => x,
479 None => panic!("Cos overflowed"),
480 }
481 }
482
483 fn checked_cos(&self) -> Option<Decimal> {
484 crate::ops::wide::cos_wide(self)
485 }
486
487 fn tan(&self) -> Decimal {
488 match self.checked_tan() {
489 Some(x) => x,
490 None => panic!("Tan overflowed"),
491 }
492 }
493
494 fn checked_tan(&self) -> Option<Decimal> {
495 if self.is_zero() {
496 return Some(Decimal::ZERO);
497 }
498 if self.is_sign_negative() {
499 return (-self).checked_tan().map(|x| -x);
501 }
502 if self >= &Decimal::TWO_PI {
503 let adjusted = self.checked_rem(Decimal::TWO_PI)?;
505 return adjusted.checked_tan();
506 }
507 if self >= &Decimal::PI {
509 return (self - Decimal::PI).checked_tan();
511 }
512 if self > &Decimal::HALF_PI {
514 return ((Decimal::HALF_PI - self) + Decimal::HALF_PI).checked_tan().map(|x| -x);
517 }
518
519 if self > &Decimal::QUARTER_PI {
522 return match (Decimal::HALF_PI - self).checked_tan() {
523 Some(x) => Decimal::ONE.checked_div(x),
524 None => None,
525 };
526 }
527
528 if self > &EIGHTH_PI {
532 let tan_half = (self / Decimal::TWO).checked_tan()?;
534 let dividend = Decimal::TWO.checked_mul(tan_half)?;
536
537 let squared = tan_half.checked_mul(tan_half)?;
539 let divisor = Decimal::ONE - squared;
540 if divisor.is_zero() {
542 return None;
543 }
544 return dividend.checked_div(divisor);
545 }
546
547 const SERIES: [(Decimal, u64); 6] = [
561 (Decimal::from_parts_raw(89478485, 347537611, 180700362, 1835008), 3),
563 (Decimal::from_parts_raw(894784853, 3574988881, 72280144, 1835008), 5),
565 (Decimal::from_parts_raw(905437054, 3907911371, 2925624, 1769472), 7),
567 (Decimal::from_parts_raw(3191872741, 2108928381, 11855473, 1835008), 9),
569 (Decimal::from_parts_raw(3482645539, 2612995122, 4804769, 1835008), 11),
571 (Decimal::from_parts_raw(4189029078, 2192791200, 1947296, 1835008), 13),
573 ];
574 let mut result = *self;
575 for (fraction, pow) in SERIES {
576 result += fraction * self.powu(pow);
577 }
578 Some(result)
579 }
580}
581
582impl Pow<Decimal> for Decimal {
583 type Output = Decimal;
584
585 fn pow(self, rhs: Decimal) -> Self::Output {
586 MathematicalOps::powd(&self, rhs)
587 }
588}
589
590impl Pow<u64> for Decimal {
591 type Output = Decimal;
592
593 fn pow(self, rhs: u64) -> Self::Output {
594 MathematicalOps::powu(&self, rhs)
595 }
596}
597
598impl Pow<i64> for Decimal {
599 type Output = Decimal;
600
601 fn pow(self, rhs: i64) -> Self::Output {
602 MathematicalOps::powi(&self, rhs)
603 }
604}
605
606impl Pow<f64> for Decimal {
607 type Output = Decimal;
608
609 fn pow(self, rhs: f64) -> Self::Output {
610 MathematicalOps::powf(&self, rhs)
611 }
612}
613
614#[cfg(test)]
615mod test {
616 use super::*;
617
618 #[cfg(not(feature = "std"))]
619 use alloc::string::ToString;
620
621 #[test]
622 fn test_factorials() {
623 assert_eq!("1", FACTORIAL[0].to_string(), "0!");
624 assert_eq!("1", FACTORIAL[1].to_string(), "1!");
625 assert_eq!("2", FACTORIAL[2].to_string(), "2!");
626 assert_eq!("6", FACTORIAL[3].to_string(), "3!");
627 assert_eq!("24", FACTORIAL[4].to_string(), "4!");
628 assert_eq!("120", FACTORIAL[5].to_string(), "5!");
629 assert_eq!("720", FACTORIAL[6].to_string(), "6!");
630 assert_eq!("5040", FACTORIAL[7].to_string(), "7!");
631 assert_eq!("40320", FACTORIAL[8].to_string(), "8!");
632 assert_eq!("362880", FACTORIAL[9].to_string(), "9!");
633 assert_eq!("3628800", FACTORIAL[10].to_string(), "10!");
634 assert_eq!("39916800", FACTORIAL[11].to_string(), "11!");
635 assert_eq!("479001600", FACTORIAL[12].to_string(), "12!");
636 assert_eq!("6227020800", FACTORIAL[13].to_string(), "13!");
637 assert_eq!("87178291200", FACTORIAL[14].to_string(), "14!");
638 assert_eq!("1307674368000", FACTORIAL[15].to_string(), "15!");
639 assert_eq!("20922789888000", FACTORIAL[16].to_string(), "16!");
640 assert_eq!("355687428096000", FACTORIAL[17].to_string(), "17!");
641 assert_eq!("6402373705728000", FACTORIAL[18].to_string(), "18!");
642 assert_eq!("121645100408832000", FACTORIAL[19].to_string(), "19!");
643 assert_eq!("2432902008176640000", FACTORIAL[20].to_string(), "20!");
644 assert_eq!("51090942171709440000", FACTORIAL[21].to_string(), "21!");
645 assert_eq!("1124000727777607680000", FACTORIAL[22].to_string(), "22!");
646 assert_eq!("25852016738884976640000", FACTORIAL[23].to_string(), "23!");
647 assert_eq!("620448401733239439360000", FACTORIAL[24].to_string(), "24!");
648 assert_eq!("15511210043330985984000000", FACTORIAL[25].to_string(), "25!");
649 assert_eq!("403291461126605635584000000", FACTORIAL[26].to_string(), "26!");
650 assert_eq!("10888869450418352160768000000", FACTORIAL[27].to_string(), "27!");
651 }
652}