use super::cast::*;
use super::num::*;
use super::table::*;
mod private {
use super::*;
#[cfg(not(feature = "correct"))]
pub(crate) trait StablePowerImpl: Float + ExactExponent {
}
#[cfg(feature = "correct")]
pub(crate) trait StablePowerImpl: Float + ExactExponent + TablePower {
}
impl StablePowerImpl for f32 {
}
impl StablePowerImpl for f64 {
}
}
pub(crate) trait StablePower: private::StablePowerImpl {
fn iterative_max<T: Integer>(base: T) -> i32;
fn iterative_step<T: Integer>(base: T) -> i32;
#[inline]
fn iterative_pow<T: Integer>(self, base: T, exponent: i32) -> Self {
let max = Self::iterative_max(base);
if exponent > max {
Self::INFINITY
} else if exponent < -max {
Self::ZERO
} else {
self.iterative_pow_finite(base, exponent)
}
}
#[inline]
fn iterative_pow_finite<T: Integer>(mut self, base: T, mut exponent: i32) -> Self {
let step = Self::iterative_step(base);
let base: Self = as_cast(base);
if exponent < 0 {
while exponent <= -step {
exponent += step;
self /= base.powi(step)
}
if exponent != 0 {
self /= base.powi(-exponent)
}
self
} else {
while exponent >= step {
exponent -= step;
self *= base.powi(step)
}
if exponent != 0 {
self *= base.powi(exponent)
}
self
}
}
#[cfg(all(feature = "radix", not(feature = "correct")))]
#[inline]
fn pow2(self, exponent: i32) -> Self {
let step: i32 = 75;
if exponent > step {
self * Self::TWO.powi(step) * Self::TWO.powi(exponent - step)
} else if exponent < -step {
self * Self::TWO.powi(-step) * Self::TWO.powi(exponent + step)
} else {
self * Self::TWO.powi(exponent)
}
}
#[cfg(all(feature = "radix", feature = "correct"))]
#[inline]
fn pow2(self, exponent: i32) -> Self {
self * Self::table_pow2(exponent)
}
#[cfg(not(feature = "correct"))]
#[inline]
fn pow<T: Integer>(self, base: T, exponent: i32) -> Self {
let (min, max) = Self::exponent_limit(base);
debug_assert!(exponent >= min && exponent <= max);
let base: Self = as_cast(base);
self * base.powi(exponent)
}
#[cfg(feature = "correct")]
#[inline]
fn pow<T: Integer>(self, base: T, exponent: i32) -> Self {
let (min, max) = Self::exponent_limit(base);
debug_assert!(exponent >= min && exponent <= max);
if exponent > 0 {
self * Self::table_pow(base, exponent)
} else {
self / Self::table_pow(base, -exponent)
}
}
}
impl StablePower for f32 {
fn iterative_max<T: Integer>(radix: T) -> i32 {
const MAX: [i32; 35] = [
150, 100, 80, 70, 60, 60, 50, 50, 50, 50, 50, 50,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 30, 30, 30, 30, 30
];
debug_assert_radix!(radix);
let idx: usize = as_cast(radix.as_i32() - 2);
MAX[idx]
}
fn iterative_step<T: Integer>(radix: T) -> i32 {
const STEP: [i32; 35] = [
90, 60, 50, 40, 40, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
];
debug_assert_radix!(radix);
let idx: usize = as_cast(radix.as_i32() - 2);
STEP[idx]
}
}
impl StablePower for f64 {
fn iterative_max<T: Integer>(radix: T) -> i32 {
const MAX: [i32; 35] = [
2200, 1400, 1200, 1000, 900, 800, 750, 700, 650, 625, 625, 600,
575, 575, 550, 550, 525, 525, 500, 500, 500, 500, 475, 475,
475, 475, 450, 450, 450, 450, 450, 450, 425, 425, 425
];
debug_assert_radix!(radix);
MAX[radix.as_usize() - 2]
}
fn iterative_step<T: Integer>(radix: T) -> i32 {
const STEP: [i32; 35] = [
512, 512, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
];
debug_assert_radix!(radix);
STEP[radix.as_usize() - 2]
}
}
#[cfg(test)]
mod tests {
use util::test::*;
use super::*;
#[test]
fn f32_iterative_pow_finite_test() {
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, 38), 1e38, max_relative=1e-6);
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, 30), 1e30, max_relative=1e-6);
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, 25), 1e25, max_relative=1e-6);
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, 20), 1e20, max_relative=1e-6);
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, 15), 1e15, max_relative=1e-6);
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, 10), 1e10, max_relative=1e-6);
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, 5), 1e5, max_relative=1e-6);
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -5), 1e-5, max_relative=1e-6);
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -10), 1e-10, max_relative=1e-6);
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -15), 1e-15, max_relative=1e-6);
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -20), 1e-20, max_relative=1e-6);
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -25), 1e-25, max_relative=1e-6);
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -30), 1e-30, max_relative=1e-6);
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -38), 1e-38, max_relative=1e-6);
assert_relative_eq!(f32::iterative_pow_finite(1.0, 10, -45), 1e-45, max_relative=1e-6);
assert!(f32::iterative_pow_finite(1.0, 10, 39).is_infinite());
assert_eq!(f32::iterative_pow_finite(1.0, 10, -46), 0.0);
}
#[test]
fn f32_iterative_pow_test() {
assert_relative_eq!(f32::iterative_pow(1.0, 10, 10), 1e10, max_relative=1e-15);
assert!(f32::iterative_pow(1.0, 10, 1000).is_infinite());
assert_eq!(f32::iterative_pow(1.0, 10, -1000), 0.0);
assert!(f32::iterative_pow(1.0, 10, 39).is_infinite());
assert_eq!(f32::iterative_pow(1.0, 10, -46), 0.0);
}
#[test]
fn f64_iterative_pow_finite_test() {
assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, 308), 1e308, max_relative=1e-15);
assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, 300), 1e300, max_relative=1e-15);
assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, 200), 1e200, max_relative=1e-15);
assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, 100), 1e100, max_relative=1e-15);
assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, 50), 1e50, max_relative=1e-15);
assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, -50), 1e-50, epsilon=1e-15);
assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, -100), 1e-100, epsilon=1e-15);
assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, -200), 1e-200, epsilon=1e-15);
assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, -300), 1e-300, epsilon=1e-15);
assert_relative_eq!(f64::iterative_pow_finite(1.0, 10, -308), 1e-308, epsilon=1e-15);
#[cfg(not(all(target_arch = "arm", not(target_feature = "v7"))))]
assert_eq!(f64::iterative_pow_finite(5.0, 10, -324), 5e-324);
assert!(f64::iterative_pow_finite(1.0, 10, 309).is_infinite());
assert_eq!(f64::iterative_pow_finite(1.0, 10, -325), 0.0);
}
#[test]
fn f64_iterative_pow_test() {
assert_relative_eq!(f64::iterative_pow(1.0, 10, 50), 1e50, max_relative=1e-15);
assert!(f64::iterative_pow(1.0, 10, 1000).is_infinite());
assert_eq!(f64::iterative_pow(1.0, 10, -1000), 0.0);
assert!(f64::iterative_pow(1.0, 10, 309).is_infinite());
assert_eq!(f64::iterative_pow(1.0, 10, -325), 0.0);
}
#[cfg(feature = "radix")]
#[test]
fn f32_pow2_test() {
let (min, max) = f32::exponent_limit(2);
for i in min+1..max+1 {
assert_eq!(f32::pow2(1.0, i) / f32::pow2(1.0, i-1), 2.0);
}
for i in 1..max+1 {
let f = f32::pow2(1.0, i);
if f < u64::max_value() as f32 {
assert_eq!((f as u64) as f32, f);
}
}
}
#[test]
fn f32_pow_test() {
for b in BASE_POWN.iter().cloned() {
let (_, max) = f32::exponent_limit(b);
for i in 1..max+1 {
let f = f32::pow(1.0, b, i);
let p = f32::pow(1.0, b, i-1);
assert_eq!(f / p, b as f32);
if f < u64::max_value() as f32 {
assert_eq!((f as u64) as f32, f);
}
}
}
}
#[cfg(feature = "radix")]
#[test]
fn f64_pow2_test() {
let (min, max) = f64::exponent_limit(2);
for i in min+1..max+1 {
let curr = f64::pow2(1.0, i);
let prev = f64::pow2(1.0, i-1);
assert_eq!(curr / prev, 2.0);
}
for i in 1..max+1 {
let f = f64::pow2(1.0, i);
if f < u64::max_value() as f64 {
assert_eq!((f as u64) as f64, f);
}
}
}
#[test]
fn f64_pow_test() {
for b in BASE_POWN.iter().cloned() {
let (_, max) = f64::exponent_limit(b);
for i in 1..max+1 {
let f = f64::pow(1.0, b, i);
let p = f64::pow(1.0, b, i-1);
assert_eq!(f / p, b as f64);
if f < u64::max_value() as f64 {
assert_eq!((f as u64) as f64, f);
}
}
}
}
}