1 //! FLoating point power utilities.
2 
3 use super::cast::*;
4 use super::num::*;
5 use super::table::*;
6 
7 // STABLE POWER
8 
9 mod private {
10     use super::*;
11 
12     #[cfg(not(feature = "correct"))]
13     pub(crate) trait StablePowerImpl: Float + ExactExponent {
14     }
15 
16     #[cfg(feature = "correct")]
17     pub(crate) trait StablePowerImpl: Float + ExactExponent + TablePower {
18     }
19 
20     impl StablePowerImpl for f32 {
21     }
22 
23     impl StablePowerImpl for f64 {
24     }
25 }
26 
27 /// Stable power implementations for increased numeric stability.
28 pub(crate) trait StablePower: private::StablePowerImpl {
29 //    /// Calculate pow2 with numeric exponent.
30 //    #[cfg(any(test, not(feature = "imprecise")))]
31 //    fn pow2(self, exponent: i32) -> Self;
32 //
33 //    /// Calculate base^n with numeric exponent and base.
34 //    #[cfg(any(test, not(feature = "imprecise")))]
35 //    fn pow<T: Integer>(self, base: T, exponent: i32) -> Self;
36 
37     // ITERATIVE
38 
39     /// Get max exponent for `iterative_pow`.
iterative_max<T: Integer>(base: T) -> i3240     fn iterative_max<T: Integer>(base: T) -> i32;
41 
42     /// Get exponent step for `iterative_pow`.
iterative_step<T: Integer>(base: T) -> i3243     fn iterative_step<T: Integer>(base: T) -> i32;
44 
45     /// Calculate base^n iteratively for better numeric stability.
46     #[inline]
iterative_pow<T: Integer>(self, base: T, exponent: i32) -> Self47     fn iterative_pow<T: Integer>(self, base: T, exponent: i32) -> Self {
48         let max = Self::iterative_max(base);
49         if exponent > max {
50             // Value is impossibly large, must be infinity.
51             Self::INFINITY
52         } else if exponent < -max {
53             // Value is impossibly small, must be 0.
54             Self::ZERO
55         } else {
56             self.iterative_pow_finite(base, exponent)
57         }
58     }
59 
60     /// Calculate base^n iteratively for a finite result.
61     #[inline]
iterative_pow_finite<T: Integer>(mut self, base: T, mut exponent: i32) -> Self62     fn iterative_pow_finite<T: Integer>(mut self, base: T, mut exponent: i32) -> Self {
63         let step = Self::iterative_step(base);
64         let base: Self = as_cast(base);
65         if exponent < 0 {
66             // negative exponent, use division for numeric stability
67             while exponent <= -step {
68                 exponent += step;
69                 self /= base.powi(step)
70             }
71             if exponent != 0 {
72                 self /= base.powi(-exponent)
73             }
74             self
75         } else {
76             // positive exponent
77             while exponent >= step {
78                 exponent -= step;
79                 self *= base.powi(step)
80             }
81             if exponent != 0 {
82                 self *= base.powi(exponent)
83             }
84             self
85         }
86     }
87 
88     // POW2
89 
90     /// Calculate a stable powi when the value is known to be >= -2*max && <= 2*max
91     ///
92     /// powi is not stable, even with exact values, at high or low exponents.
93     /// However, doing it in 2 shots for exact values is exact.
94     #[cfg(all(feature = "radix", not(feature = "correct")))]
95     #[inline]
pow2(self, exponent: i32) -> Self96     fn pow2(self, exponent: i32) -> Self {
97         let step: i32 = 75;
98         if exponent > step {
99             self * Self::TWO.powi(step) * Self::TWO.powi(exponent - step)
100         } else if exponent < -step {
101             self * Self::TWO.powi(-step) * Self::TWO.powi(exponent + step)
102         } else {
103             self * Self::TWO.powi(exponent)
104         }
105     }
106 
107     /// Calculate power of 2 using precalculated table.
108     #[cfg(all(feature = "radix", feature = "correct"))]
109     #[inline]
pow2(self, exponent: i32) -> Self110     fn pow2(self, exponent: i32) -> Self {
111         self * Self::table_pow2(exponent)
112     }
113 
114     // POW
115 
116     /// Calculate power of n using powi.
117     #[cfg(not(feature = "correct"))]
118     #[inline]
pow<T: Integer>(self, base: T, exponent: i32) -> Self119     fn pow<T: Integer>(self, base: T, exponent: i32) -> Self {
120         // Check the exponent is within bounds in debug builds.
121         debug_assert!({
122             let (min, max) = Self::exponent_limit(base);
123             exponent >= min && exponent <= max
124         });
125 
126         let base: Self = as_cast(base);
127         self * base.powi(exponent)
128     }
129 
130     /// Calculate power of n using precalculated table.
131     #[cfg(feature = "correct")]
132     #[inline]
pow<T: Integer>(self, base: T, exponent: i32) -> Self133     fn pow<T: Integer>(self, base: T, exponent: i32) -> Self {
134         // Check the exponent is within bounds in debug builds.
135         debug_assert!({
136             let (min, max) = Self::exponent_limit(base);
137             exponent >= min && exponent <= max
138         });
139 
140         if exponent > 0 {
141             self * Self::table_pow(base, exponent)
142         } else {
143             self / Self::table_pow(base, -exponent)
144         }
145     }
146 }
147 
148 // F32
149 
150 impl StablePower for f32 {
iterative_max<T: Integer>(radix: T) -> i32151     fn iterative_max<T: Integer>(radix: T) -> i32 {
152         // Cached max exponents.
153         // Make sure the value is >= 2*log(1e45, radix), which guarantees the
154         // value overflows or underflows.
155         const MAX: [i32; 35] = [
156             150, 100, 80, 70, 60, 60, 50, 50, 50, 50, 50, 50,
157             40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
158             40, 40, 40, 40, 40, 40, 30, 30, 30, 30, 30
159         ];
160 
161         debug_assert_radix!(radix);
162         let idx: usize = as_cast(radix.as_i32() - 2);
163         MAX[idx]
164     }
165 
iterative_step<T: Integer>(radix: T) -> i32166     fn iterative_step<T: Integer>(radix: T) -> i32 {
167         // Cached powers to get the desired exponent.
168         // Make sure all values are < 1e25.
169         const STEP: [i32; 35] = [
170             90, 60, 50, 40, 40, 30, 30, 30, 30, 30, 30, 30,
171             30, 30, 30, 30, 20, 20, 20, 20, 20, 20, 20, 20,
172             20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
173         ];
174 
175         debug_assert_radix!(radix);
176         let idx: usize = as_cast(radix.as_i32() - 2);
177         STEP[idx]
178     }
179 }
180 
181 // F64
182 
183 impl StablePower for f64 {
iterative_max<T: Integer>(radix: T) -> i32184     fn iterative_max<T: Integer>(radix: T) -> i32 {
185         // Cached max exponents.
186         // Make sure the value is >= 2*log(5e324, radix), which guarantees the
187         // value overflows or underflows.
188         const MAX: [i32; 35] = [
189             2200, 1400, 1200, 1000, 900, 800, 750, 700, 650, 625, 625, 600,
190             575, 575, 550, 550, 525, 525, 500, 500, 500, 500, 475, 475,
191             475, 475, 450, 450, 450, 450, 450, 450, 425, 425, 425
192         ];
193 
194         debug_assert_radix!(radix);
195         MAX[radix.as_usize() - 2]
196     }
197 
iterative_step<T: Integer>(radix: T) -> i32198     fn iterative_step<T: Integer>(radix: T) -> i32 {
199         // Cached powers to get the desired exponent.
200         // Make sure all values are < 1e300.
201         const STEP: [i32; 35] = [
202             512, 512, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
203             256, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
204             128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
205         ];
206 
207         debug_assert_radix!(radix);
208         STEP[radix.as_usize() - 2]
209     }
210 }
211 
212 // TEST
213 // ----
214 
215 #[cfg(test)]
216 mod tests {
217     use crate::util::test::*;
218     use super::*;
219 
220     use approx::assert_relative_eq;
221 
222     #[test]
f32_iterative_pow_finite_test()223     fn f32_iterative_pow_finite_test() {
224         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, 38), 1e38, max_relative=1e-6);
225         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, 30), 1e30, max_relative=1e-6);
226         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, 25), 1e25, max_relative=1e-6);
227         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, 20), 1e20, max_relative=1e-6);
228         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, 15), 1e15, max_relative=1e-6);
229         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, 10), 1e10, max_relative=1e-6);
230         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, 5), 1e5, max_relative=1e-6);
231         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -5), 1e-5, max_relative=1e-6);
232         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -10), 1e-10, max_relative=1e-6);
233         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -15), 1e-15, max_relative=1e-6);
234         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -20), 1e-20, max_relative=1e-6);
235         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -25), 1e-25, max_relative=1e-6);
236         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -30), 1e-30, max_relative=1e-6);
237         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -38), 1e-38, max_relative=1e-6);
238         assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -45), 1e-45, max_relative=1e-6);
239 
240         // overflow
241         assert!(f32::iterative_pow_finite(1.0, 10, 39).is_infinite());
242 
243         // underflow
244         assert_eq!(f32::iterative_pow_finite(1.0, 10, -46), 0.0);
245     }
246 
247     #[test]
f32_iterative_pow_test()248     fn f32_iterative_pow_test() {
249         assert_relative_eq!(f32::iterative_pow(1.0, 10, 10), 1e10, max_relative=1e-15);
250         assert!(f32::iterative_pow(1.0, 10, 1000).is_infinite());
251         assert_eq!(f32::iterative_pow(1.0, 10, -1000), 0.0);
252 
253         // overflow
254         assert!(f32::iterative_pow(1.0, 10, 39).is_infinite());
255 
256         // underflow
257         assert_eq!(f32::iterative_pow(1.0, 10, -46), 0.0);
258     }
259 
260     #[test]
f64_iterative_pow_finite_test()261     fn f64_iterative_pow_finite_test() {
262         assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, 308), 1e308, max_relative=1e-15);
263         assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, 300), 1e300, max_relative=1e-15);
264         assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, 200), 1e200, max_relative=1e-15);
265         assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, 100), 1e100, max_relative=1e-15);
266         assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, 50), 1e50, max_relative=1e-15);
267         assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, -50), 1e-50, epsilon=1e-15);
268         assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, -100), 1e-100, epsilon=1e-15);
269         assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, -200), 1e-200, epsilon=1e-15);
270         assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, -300), 1e-300, epsilon=1e-15);
271         assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, -308), 1e-308, epsilon=1e-15);
272 
273         // This only affects armv6 and not armv7, but we'll skip this test
274         // both, since `target_arch` does not differentiate between
275         // the two.
276         #[cfg(not(all(target_arch = "arm", not(target_feature = "v7"))))]
277         assert_eq!(f64::iterative_pow_finite(5.0, 10, -324), 5e-324);
278 
279         // overflow
280         assert!(f64::iterative_pow_finite(1.0, 10, 309).is_infinite());
281 
282         // underflow
283         assert_eq!(f64::iterative_pow_finite(1.0, 10, -325), 0.0);
284     }
285 
286     #[test]
f64_iterative_pow_test()287     fn f64_iterative_pow_test() {
288         assert_relative_eq!(f64::iterative_pow(1.0, 10, 50), 1e50, max_relative=1e-15);
289         assert!(f64::iterative_pow(1.0, 10, 1000).is_infinite());
290         assert_eq!(f64::iterative_pow(1.0, 10, -1000), 0.0);
291 
292         // overflow
293         assert!(f64::iterative_pow(1.0, 10, 309).is_infinite());
294 
295         // underflow
296         assert_eq!(f64::iterative_pow(1.0, 10, -325), 0.0);
297     }
298 
299     #[cfg(feature = "radix")]
300     #[test]
f32_pow2_test()301     fn f32_pow2_test() {
302         let (min, max) = f32::exponent_limit(2);
303         for i in min+1..max+1 {
304             assert_eq!(f32::pow2(1.0, i) / f32::pow2(1.0, i-1), 2.0);
305         }
306         for i in 1..max+1 {
307             let f = f32::pow2(1.0, i);
308             if f < u64::max_value() as f32 {
309                 assert_eq!((f as u64) as f32, f);
310             }
311         }
312     }
313 
314     #[test]
f32_pow_test()315     fn f32_pow_test() {
316         // Only check positive, since negative values round during division.
317         for b in BASE_POWN.iter().cloned() {
318             let (_, max) = f32::exponent_limit(b);
319             for i in 1..max+1 {
320                 let f = f32::pow(1.0, b, i);
321                 let p = f32::pow(1.0, b, i-1);
322                 assert_eq!(f / p, b as f32);
323                 if f < u64::max_value() as f32 {
324                     assert_eq!((f as u64) as f32, f);
325                 }
326             }
327         }
328     }
329 
330     #[cfg(feature = "radix")]
331     #[test]
f64_pow2_test()332     fn f64_pow2_test() {
333         let (min, max) = f64::exponent_limit(2);
334         for i in min+1..max+1 {
335             let curr = f64::pow2(1.0, i);
336             let prev = f64::pow2(1.0, i-1);
337             assert_eq!(curr / prev, 2.0);
338         }
339         for i in 1..max+1 {
340             let f = f64::pow2(1.0, i);
341             if f < u64::max_value() as f64 {
342                 assert_eq!((f as u64) as f64, f);
343             }
344         }
345     }
346 
347     #[test]
f64_pow_test()348     fn f64_pow_test() {
349         // Only check positive, since negative values round during division.
350         for b in BASE_POWN.iter().cloned() {
351             let (_, max) = f64::exponent_limit(b);
352             for i in 1..max+1 {
353                 let f = f64::pow(1.0, b, i);
354                 let p = f64::pow(1.0, b, i-1);
355                 assert_eq!(f / p, b as f64);
356                 if f < u64::max_value() as f64 {
357                     assert_eq!((f as u64) as f64, f);
358                 }
359             }
360         }
361     }
362 }
363