devela/num/float/wrapper/
shared_series.rs
1#[allow(unused_imports)]
11use super::super::shared_docs::*;
12use crate::{cfor, iif, paste, Float};
13
14macro_rules! impl_float_shared_series {
22 () => {
23 impl_float_shared_series![
24 (f32:u32, u32):"_float_f32":"_cmp_f32",
25 (f64:u64, u32):"_float_f64":"_cmp_f64"
26 ];
27 };
28
29 ($( ($f:ty:$uf:ty, $ue:ty) : $cap:literal : $cmp:literal ),+) => {
30 $( impl_float_shared_series![@$f:$uf, $ue, $cap:$cmp]; )+
31 };
32 (@$f:ty:$uf:ty, $ue:ty, $cap:literal : $cmp:literal) => {
33 #[doc = crate::doc_availability!(feature = $cap)]
34 #[cfg(feature = $cap )]
38 impl Float<$f> {
40 #[doc = FORMULA_POWF_SERIES!()]
45 pub const fn powf_series(self, y: $f, ln_x_terms: $ue) -> Float<$f> {
51 let xabs = self.abs().0;
52 if xabs == 0.0 {
53 iif![Float(y).abs().0 == 0.0; Self::ONE; Self::ZERO]
54 } else {
55 let ln_x = Float(xabs).ln_series(ln_x_terms).0;
56 let power = Float(y * ln_x);
57 let exp_y_terms = power.exp_series_terms();
58 let result = power.exp_series(exp_y_terms);
59 iif![self.is_sign_negative(); Float(-result.0); result]
60 }
61 }
62
63 #[doc = FORMULA_EXP_SERIES!()]
67 pub const fn exp_series(self, terms: $ue) -> Float<$f> {
70 iif![self.0 < 0.0; return Float(1.0 / Float(-self.0).exp_series(terms).0)];
71 let (mut result, mut term) = (1.0, 1.0);
72 let mut i = 1;
73 while i <= terms {
74 term *= self.0 / i as $f;
75 result += term;
76 i += 1;
77 }
78 Float(result)
79 }
80
81 #[doc = TABLE_EXP_SERIES_TERMS!()]
84 pub const fn exp_series_terms(self) -> $ue { paste! {
85 Self::[<exp_series_terms_ $f>](self.0)
86 }}
87
88 #[doc = FORMULA_EXP_M1_SERIES!()]
92 pub const fn exp_m1_series(self, terms: $ue) -> Float<$f> {
95 if self.0 < 0.0 {
96 Float(1.0 / Float(-self.0).exp_m1_series(terms).0)
97 } else if self.0 > 0.001 {
98 Float(self.exp_series(terms).0 - 1.0)
99 } else {
100 let (mut result, mut term, mut factorial) = (0.0, self.0, 1.0);
101 let mut i = 1;
102 while i <= terms {
103 result += term;
104 factorial *= (i + 1) as $f;
105 term *= self.0 / factorial;
106 i += 1;
107 }
108 Float(result)
109 }
110 }
111
112 #[doc = FORMULA_EXP2_SERIES!()]
116 pub const fn exp2_series(self, terms: $ue) -> Float<$f> {
120 let (mut result, mut term) = (1.0, self.0 * Self::LN_2.0);
121 let mut n = 1;
122 while n < terms {
123 result += term;
124 term *= self.0 * Self::LN_2.0 / (n as $f + 1.0);
125 n += 1;
126 }
127 Float(result)
128 }
129
130 #[doc = TABLE_EXP2_SERIES_TERMS!()]
133 pub const fn exp2_series_terms(self) -> $ue { paste! {
134 Self::[<exp2_series_terms_ $f>](self.0)
135 }}
136
137 #[doc = FORMULA_LN_SERIES!()]
144 pub const fn ln_series(self, terms: $ue) -> Float<$f> {
147 if self.0 < 0.0 {
148 Self::NAN
149 } else if self.0 > 0.0 {
150 let mut sum = 0.0;
151 let y = (self.0 - 1.0) / (self.0 + 1.0);
152 let mut y_pow = y;
153 cfor![i in 0..terms => {
154 sum += y_pow / (2 * i + 1) as $f;
155 y_pow *= y * y;
156 }];
157 Float(2.0 * sum)
158 } else {
159 Self::NEG_INFINITY
160 }
161 }
162
163 pub const fn ln_1p_series(self, terms: $ue) -> Float<$f> {
174 if self.0 < -1.0 {
175 Self::NAN
176 } else if self.0 > -1.0 {
177 let x1 = self.0 + 1.0;
178 let mut sum = 0.0;
179 let y = (x1 - 1.0) / (x1 + 1.0);
180 let mut y_pow = y;
181 cfor![i in 0..terms => {
182 sum += y_pow / (2 * i + 1) as $f;
183 y_pow *= y * y;
184 }];
185 Float(2.0 * sum)
186 } else {
187 Self::NEG_INFINITY
188 }
189 }
190
191 #[doc = FORMULA_LOG_SERIES!()]
195 pub const fn log_series(self, base: $f, terms: $ue) -> Float<$f> {
198 if base <= 0.0 {
199 Self::NAN
200 } else if Float(base - 1.0).abs().0 < Self::MEDIUM_MARGIN.0 { #[expect(clippy::float_cmp, reason = "we've already checked it with a margin")]
204 { iif![self.0 == 1.0; Self::NAN; Self::NEG_INFINITY] }
205 } else {
206 Float(self.ln_series(terms).0 / base).ln_series(terms)
207 }
208 }
209
210 #[doc = FORMULA_LOG2_SERIES!()]
214 pub const fn log2_series(self, terms: $ue) -> Float<$f> {
217 Float(self.ln_series(terms).0 / 2.0).ln_series(terms)
218 }
219
220 #[doc = FORMULA_LOG10_SERIES!()]
224 pub const fn log10_series(self, terms: $ue) -> Float<$f> {
227 Float(self.ln_series(terms).0 / 10.0).ln_series(terms)
228 }
229
230 #[doc = TABLE_LN_SERIES_TERMS!()]
233 #[must_use]
234 pub const fn ln_series_terms(self) -> $ue { paste! {
235 Self::[<ln_series_terms_ $f>](self.0)
236 }}
237
238 #[doc = FORMULA_SIN_SERIES!()]
242 #[doc = TABLE_SIN_SERIES_TERMS!()]
246 pub const fn sin_series(self, terms: $ue) -> Float<$f> {
247 let x = self.clamp_nan(-Self::PI.0, Self::PI.0).0;
248 let (mut sin, mut term, mut factorial) = (x, x, 1.0);
249 let mut i = 1;
250 while i < terms {
251 term *= -x * x;
252 factorial *= ((2 * i + 1) * (2 * i)) as $f;
253 sin += term / factorial;
254 i += 1;
255 }
256 Float(sin)
257 }
258
259 #[doc = FORMULA_COS_SERIES!()]
263 #[doc = TABLE_COS_SERIES_TERMS!()]
267 pub const fn cos_series(self, terms: $ue) -> Float<$f> {
268 let x = self.clamp_nan(-Self::PI.0, Self::PI.0).0;
269 let (mut cos, mut term, mut factorial) = (1.0, 1.0, 1.0);
270 let mut i = 1;
271 while i < terms {
272 term *= -x * x;
273 factorial *= ((2 * i - 1) * (2 * i)) as $f;
274 cos += term / factorial;
275 i += 1;
276 }
277 Float(cos)
278 }
279
280 pub const fn sin_cos_series(self, terms: $ue) -> (Float<$f>, Float<$f>) {
282 (self.sin_series(terms), self.cos_series(terms))
283 }
284
285 #[doc = FORMULA_TAN_SERIES!()]
289 #[doc = TABLE_TAN_SERIES_TERMS!()]
297 pub const fn tan_series(self, terms: $ue) -> Float<$f> {
298 let x = self.clamp_nan(-Self::PI.0 / 2.0 + 0.0001, Self::PI.0 / 2.0 - 0.0001);
299 let (sin, cos) = x.sin_cos_series(terms);
300 iif![cos.abs().0 < 0.0001; return Self::MAX];
301 Float(sin.0 / cos.0)
302 }
303
304 #[doc = FORMULA_ASIN_SERIES!()]
308 pub const fn asin_series(self, terms: $ue) -> Float<$f> {
318 iif![self.abs().0 > 1.0; return Self::NAN];
319 let (mut asin_approx, mut multiplier, mut power_x) = (0.0, 1.0, self.0);
320 let mut i = 0;
321 while i < terms {
322 if i != 0 {
323 multiplier *= (2 * i - 1) as $f / (2 * i) as $f;
324 power_x *= self.0 * self.0;
325 }
326 asin_approx += multiplier * power_x / (2 * i + 1) as $f;
327 i += 1;
328 }
329 Float(asin_approx)
330 }
331
332 #[doc = TABLE_ASIN_SERIES_TERMS!()]
336 #[must_use]
337 pub const fn asin_series_terms(self) -> $ue { paste! {
338 Self::[<asin_acos_series_terms_ $f>](self.0)
339 }}
340
341 #[doc = FORMULA_ACOS_SERIES!()]
345 pub const fn acos_series(self, terms: $ue) -> Float<$f> {
349 iif![self.abs().0 > 1.0; return Self::NAN];
350 Float(Self::FRAC_PI_2.0 - self.asin_series(terms).0)
351 }
352
353 #[must_use]
358 pub const fn acos_series_terms(self) -> $ue { paste! {
359 Self::[<asin_acos_series_terms_ $f>](self.0)
360 }}
361
362 #[doc = FORMULA_ATAN_SERIES!()]
366 pub const fn atan_series(self, terms: $ue) -> Float<$f> {
374 if self.abs().0 > 1.0 {
375 if self.0 > 0.0 {
376 Float(Self::FRAC_PI_2.0 - Float(1.0 / self.0).atan_series(terms).0)
377 } else {
378 Float(-Self::FRAC_PI_2.0 - Float(1.0 / self.0).atan_series(terms).0)
379 }
380 } else {
381 let (mut atan_approx, mut num, mut sign) = (Self::ZERO.0, self.0, Self::ONE.0);
382 let mut i = 0;
383 while i < terms {
384 if i > 0 {
385 num *= self.0 * self.0;
386 sign = -sign;
387 }
388 atan_approx += sign * num / (2.0 * i as $f + 1.0);
389 i += 1;
390 }
391 Float(atan_approx)
392 }
393 }
394
395 #[doc = TABLE_ATAN_SERIES_TERMS!()]
398 #[must_use]
399 pub const fn atan_series_terms(self) -> $ue { paste! {
400 Self::[<atan_series_terms_ $f>](self.0)
401 }}
402
403 pub const fn atan2_series(self, other: $f, terms: $ue) -> Float<$f> {
408 if other > 0.0 {
409 Float(self.0 / other).atan_series(terms)
410 } else if self.0 >= 0.0 && other < 0.0 {
411 Float(Float(self.0 / other).atan_series(terms).0 + Self::PI.0)
412 } else if self.0 < 0.0 && other < 0.0 {
413 Float(Float(self.0 / other).atan_series(terms).0 - Self::PI.0)
414 } else if self.0 > 0.0 && other == 0.0 {
415 Float(Self::PI.0 / 2.0)
416 } else if self.0 < 0.0 && other == 0.0 {
417 Float(-Self::PI.0 / 2.0)
418 } else {
419 Self::NAN
421 }
422 }
423
424 #[doc = FORMULA_SINH_SERIES!()]
429 pub const fn sinh_series(self, terms: $ue) -> Float<$f> {
433 Float((self.exp_series(terms).0 - -self.exp_series(terms).0) / 2.0)
434 }
435
436 #[doc = FORMULA_COSH_SERIES!()]
441 pub const fn cosh_series(self, terms: $ue) -> Float<$f> {
445 Float((self.exp_series(terms).0 + -self.exp_series(terms).0) / 2.0)
446 }
447
448 #[doc = FORMULA_TANH_SERIES!()]
453 pub const fn tanh_series(self, terms: $ue) -> Float<$f> {
457 let sinh_approx = self.sinh_series(terms);
458 let cosh_approx = self.cosh_series(terms);
459 Float(sinh_approx.0 / cosh_approx.0)
460 }
461
462 #[doc = FORMULA_ASINH_SERIES!()]
466 pub const fn asinh_series(self, terms: $ue) -> Float<$f> {
469 let sqrt = Float(self.0 * self.0 + 1.0).sqrt_nr().0;
470 Float(self.0 + sqrt).ln_series(terms)
471 }
472
473 #[doc = FORMULA_ACOSH_SERIES!()]
477 pub const fn acosh_series(self, terms: $ue) -> Float<$f> {
480 if self.0 < 1.0 {
481 Self::NAN
482 } else {
483 let sqrt = Float(self.0 * self.0 - 1.0).sqrt_nr().0;
484 Float(self.0 + sqrt).ln_series(terms)
485 }
486 }
487
488 #[doc = FORMULA_ATANH_SERIES!()]
492 pub const fn atanh_series(self, terms: $ue) -> Float<$f> {
495 if self.0 >= 1.0 {
496 Self::INFINITY
497 } else if self.0 <= -1.0 {
498 Self::NEG_INFINITY
499 } else {
500 Float(Float((self.0 + 1.0) / (1.0 - self.0)).ln_series(terms).0 * 0.5)
501 }
502 }
503 }
504 };
505}
506impl_float_shared_series!();
507
508crate::CONST! { pub(crate),
509TABLE_EXP_SERIES_TERMS = "
510The following table shows the required number of `terms` needed
511to reach the most precise result for both `f32` and `f64`:
512```txt
513 value t_f32 t_f64
514-------------------------
515± 0.001 → 3 5
516± 0.100 → 6 10
517± 1.000 → 11 18
518± 10.000 → 32 46
519± 20.000 → 49 68
520± 50.000 → 92 119
521± 88.722 → 143 177 (max for f32 == f32::MAX.ln())
522± 150.000 → --- 261
523± 300.000 → --- 453
524± 500.000 → --- 692
525± 709.782 → --- 938 (max for f64 == f64:MAX.ln())
526```";
527TABLE_EXP2_SERIES_TERMS = "
528The following table shows the required number of `terms` needed
529to reach the most precise result for both `f32` and `f64`:
530```txt
531 value t_f32 t_f64
532-------------------------
533± 0.3 → 8 13
534± 3.0 → 15 25
535± 7.0 → 22 34
536± 15.0 → 34 49
537± 31.0 → 52 71
538± 63.0 → 84 110
539± 127.999 → 144 178 (max for f32)
540± 255.0 → --- 298
541± 511.0 → --- 520
542± 1023.999 → --- 939 (max for f64)
543```";
544TABLE_LN_SERIES_TERMS = "
545The following table shows the required number of `terms` needed
546to reach the most precise result for both `f32` and `f64`:
547```txt
548 value t_f32 t_f64
549--------------------------
550± 0.00001 → 81181 536609
551± 0.0001 → 12578 59174
552± 0.001 → 1923 6639
553± 0.01. → 245 720
554± 0.1 → 32 80
555± 0.5 → 8 17
556± 1. → 1 1
557± 2. → 8 17
558± 10. → 32 80
559± 100. → 245 720
560± 1000. → 1923 6639
561± 10000. → 12578 59174
562± 100000. → 81181 536609
563/// ```
564```";
565TABLE_SIN_SERIES_TERMS = "
566The following table shows the required number of `terms` needed
567to reach the most precise result for both `f32` and `f64`:
568```txt
569 value t_f32 t_f64
570-------------------------
571± 0.001 → 3 4
572± 0.100 → 4 6
573± 0.300 → 5 7
574± 0.500 → 5 8
575± 0.700 → 6 9
576± 0.900 → 6 10
577± 0.999 → 6 10
578```";
579TABLE_COS_SERIES_TERMS = "
580The following table shows the required number of `terms` needed
581to reach the most precise result for both `f32` and `f64`:
582```txt
583 value t_f32 t_f64
584-------------------------
585± 0.001 → 3 4
586± 0.100 → 4 6
587± 0.300 → 5 8
588± 0.500 → 6 9
589± 0.700 → 6 10
590± 0.900 → 7 10
591± 0.999 → 7 11
592```";
593TABLE_TAN_SERIES_TERMS = "
594The following table shows the required number of `terms` needed
595to reach the most precise result for both `f32` and `f64`:
596```txt
597 value t_f32 t_f64
598-------------------------
599± 0.001 → 3 4
600± 0.100 → 4 6
601± 0.300 → 5 8
602± 0.500 → 6 9
603± 0.700 → 6 10
604± 0.900 → 7 10
605± 0.999 → 7 11
606```";
607TABLE_ASIN_SERIES_TERMS = "
608The following table shows the required number of `terms` needed
609to reach the most precise result for both `f32` and `f64`:
610```txt
611 value t_f32 t_f64
612-------------------------
613± 0.001 → 3 4
614± 0.100 → 5 9
615± 0.300 → 7 15
616± 0.500 → 10 24
617± 0.700 → 18 44
618± 0.900 → 47 134
619± 0.990 → 333 1235
620± 0.999 → 1989 10768
621```";
622TABLE_ATAN_SERIES_TERMS = "
623The following table shows the required number of `terms` needed
624to reach the most precise result for both `f32` and `f64`:
625```txt
626 value t_f32 t_f64
627-------------------------
628± 0.001 → 3 4
629± 0.100 → 5 9
630± 0.300 → 7 15
631± 0.500 → 12 26
632± 0.700 → 20 47
633± 0.900 → 61 152
634± 0.990 → 518 1466
635± 0.999 → 4151 13604
636```";
637}
638
639#[rustfmt::skip]
640#[cfg(feature = "_float_f32")]
641impl Float<f32> {
642 #[must_use]
643 pub(super) const fn asin_acos_series_terms_f32(x: f32) -> u32 {
644 let abs_a = Float(x).abs().0;
645 if abs_a <= 0.1 { 5
646 } else if abs_a <= 0.3 { 7
647 } else if abs_a <= 0.5 { 10
648 } else if abs_a <= 0.7 { 18
649 } else if abs_a <= 0.9 { 47
650 } else if abs_a <= 0.99 { 333
651 } else { 1989 }
653 }
654 #[must_use]
655 pub(super) const fn atan_series_terms_f32(x: f32) -> u32 {
656 let abs_a = Float(x).abs().0;
657 if abs_a <= 0.1 { 5
658 } else if abs_a <= 0.3 { 7
659 } else if abs_a <= 0.5 { 12
660 } else if abs_a <= 0.7 { 20
661 } else if abs_a <= 0.9 { 61
662 } else if abs_a <= 0.99 { 518
663 } else { 4151 }
665 }
666 #[must_use]
667 pub(super) const fn exp_series_terms_f32(x: f32) -> u32 {
668 let abs_a = Float(x).abs().0;
669 if abs_a <= 0.001 { 3
670 } else if abs_a <= 0.1 { 6
671 } else if abs_a <= 1.0 { 11
672 } else if abs_a <= 10.0 { 32
673 } else if abs_a <= 20.0 { 49
674 } else if abs_a <= 50.0 { 92
675 } else { 143 }
677 }
678 #[must_use]
679 pub(super) const fn exp2_series_terms_f32(x: f32) -> u32 {
680 let abs_a = Float(x).abs().0;
681 if abs_a <= 0.3 { 8
682 } else if abs_a <= 3.0 { 15
683 } else if abs_a <= 7.0 { 22
684 } else if abs_a <= 15.0 { 34
685 } else if abs_a <= 31.0 { 52
686 } else if abs_a <= 63.0 { 84
687 } else { 144 }
689 }
690 #[must_use]
691 pub(super) const fn ln_series_terms_f32(x: f32) -> u32 {
692 let x = Float(x).abs().0;
693 let x = if x == 0.0 { return 0;
694 } else if x <= 1. { 1. / x } else { x };
695
696 if x <= 10. { 32
697 } else if x <= 100. { 245
698 } else if x <= 1_000. { 1_923
699 } else if x <= 10_000. { 12_578
700 } else if x <= 100_000. { 81_181
701 } else if x <= 1_000_000. { 405_464
702 } else if x <= 10_000_000. { 2_027_320 } else if x <= 100_000_000. { 10_136_600
704 } else if x <= 1_000_000_000. { 50_683_000
705 } else { 253_415_000 }
706 }
712}
713
714#[rustfmt::skip]
715#[cfg(feature = "_float_f64")]
716impl Float<f64> {
717 #[must_use]
718 pub(super) const fn asin_acos_series_terms_f64(x: f64) -> u32 {
719 let abs_a = Float(x).abs().0;
720 if abs_a <= 0.1 { 9
721 } else if abs_a <= 0.3 { 15
722 } else if abs_a <= 0.5 { 24
723 } else if abs_a <= 0.7 { 44
724 } else if abs_a <= 0.9 { 134
725 } else if abs_a <= 0.99 { 1235
726 } else { 10768 }
728 }
729 #[must_use]
730 pub(super) const fn atan_series_terms_f64(x: f64) -> u32 {
731 let abs_a = Float(x).abs().0;
732 if abs_a <= 0.1 { 9
733 } else if abs_a <= 0.3 { 15
734 } else if abs_a <= 0.5 { 26
735 } else if abs_a <= 0.7 { 47
736 } else if abs_a <= 0.9 { 152
737 } else if abs_a <= 0.99 { 1466
738 } else { 13604 }
740 }
741 #[must_use]
742 pub(super) const fn exp_series_terms_f64(x: f64) -> u32 {
743 let abs_a = Float(x).abs().0;
744 if abs_a <= 0.001 { 5
745 } else if abs_a <= 0.1 { 10
746 } else if abs_a <= 1.0 { 18
747 } else if abs_a <= 10.0 { 46
748 } else if abs_a <= 20.0 { 68
749 } else if abs_a <= 50.0 { 119
750 } else if abs_a <= 89.0 { 177
751 } else if abs_a <= 150.0 { 261
752 } else if abs_a <= 300.0 { 453
753 } else if abs_a <= 500.0 { 692
754 } else { 938 }
756 }
757 #[must_use]
758 pub(super) const fn exp2_series_terms_f64(x: f64) -> u32 {
759 let abs_a = Float(x).abs().0;
760 if abs_a <= 0.3 { 13
761 } else if abs_a <= 3.0 { 25
762 } else if abs_a <= 7.0 { 34
763 } else if abs_a <= 15.0 { 49
764 } else if abs_a <= 31.0 { 71
765 } else if abs_a <= 63.0 { 110
766 } else if abs_a <= 128.0 { 178
767 } else if abs_a <= 255.0 { 298
768 } else if abs_a <= 511.0 { 520
769 } else { 939 }
771 }
772 #[must_use]
773 pub(super) const fn ln_series_terms_f64(x: f64) -> u32 {
774 let x = Float(x).abs().0;
775 let x = if x == 0.0 { return 0;
776 } else if x <= 1. { 1. / x } else { x };
777
778 if x <= 10. { 80
779 } else if x <= 100. { 720
780 } else if x <= 1_000. { 6_639
781 } else if x <= 10_000. { 59_174
782 } else if x <= 100_000. { 536_609
783 } else if x <= 1_000_000. { 4_817_404
784 } else if x <= 10_000_000. { 43_356_636 } else if x <= 100_000_000. { 390_209_724
786 } else { 3_511_887_516 }
787 }
792}