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