1use super::exp::exp_inner_common;
2use super::{round_as_i_f, Exp};
3use crate::traits::{Int as _, Like};
4
5pub(crate) trait Exp10<L = Like<Self>>: Exp {
6 fn log2_10() -> Self;
7 fn log10_2_hi() -> Self;
8 fn log10_2_lo() -> Self;
9 fn ln_10() -> Self;
10 fn ln_10_hi() -> Self;
11 fn ln_10_lo() -> Self;
12 fn exp10_lo_th() -> Self;
13 fn exp10_hi_th() -> Self;
14}
15
16pub(crate) fn exp10<F: Exp10>(x: F) -> F {
18 if x >= F::exp10_hi_th() {
19 F::INFINITY
21 } else if x <= F::exp10_lo_th() {
22 F::ZERO
24 } else {
25 let e = x.raw_exp();
26 if e == F::RawExp::ZERO {
27 F::one()
30 } else if e == F::MAX_RAW_EXP {
31 x
33 } else {
34 exp10_inner(x)
35 }
36 }
37}
38
39fn exp10_inner<F: Exp10>(x: F) -> F {
40 let (k, r_hi, r_lo) = exp10_split(x);
45
46 exp_inner_common(k, r_hi, r_lo)
48}
49
50#[inline]
57fn exp10_split<F: Exp10>(x: F) -> (i32, F, F) {
58 let y = x * F::log2_10();
59 let (k, kf) = round_as_i_f(y);
60 let t_hi = x - kf * F::log10_2_hi();
63 let t_lo = -kf * F::log10_2_lo();
64 let (t_hi, t_lo) = F::norm_hi_lo_splitted(t_hi, t_lo);
65
66 let r_hi = t_hi * F::ln_10_hi();
67 let r_lo = t_hi * F::ln_10_lo() + t_lo * F::ln_10();
68
69 (k, r_hi, r_lo)
70}
71
72#[cfg(test)]
73mod tests {
74 use crate::traits::Float;
75 use crate::FloatMath;
76
77 fn test<F: Float + FloatMath>(lo_th: &str, hi_th: &str) {
78 use crate::exp10;
79
80 let f = F::parse;
81
82 let lo_th = f(lo_th);
83 let hi_th = f(hi_th);
84
85 assert_is_nan!(exp10(F::NAN));
86 assert_total_eq!(exp10(F::INFINITY), F::INFINITY);
87 assert_total_eq!(exp10(F::neg_infinity()), F::ZERO);
88 assert_total_eq!(exp10(F::ZERO), F::one());
89 assert_total_eq!(exp10(-F::ZERO), F::one());
90 assert_total_eq!(exp10(F::one()), f("10"));
91 assert_total_eq!(exp10(F::two()), f("100"));
92 assert_total_eq!(exp10(lo_th), F::ZERO);
93 assert_total_eq!(exp10(lo_th - F::one()), F::ZERO);
94 assert_total_eq!(exp10(lo_th - F::two()), F::ZERO);
95 assert_total_eq!(exp10(hi_th), F::INFINITY);
96 assert_total_eq!(exp10(hi_th + F::one()), F::INFINITY);
97 assert_total_eq!(exp10(hi_th + F::two()), F::INFINITY);
98 }
99
100 #[test]
101 fn test_f32() {
102 test::<f32>("-45.9", "38.9");
103 }
104
105 #[cfg(feature = "soft-float")]
106 #[test]
107 fn test_soft_f32() {
108 test::<crate::SoftF32>("-45.9", "38.9");
109 }
110
111 #[test]
112 fn test_f64() {
113 test::<f64>("-323.9", "308.9");
114 }
115
116 #[cfg(feature = "soft-float")]
117 #[test]
118 fn test_soft_f64() {
119 test::<crate::SoftF64>("-323.9", "308.9");
120 }
121}