use super::funejson::Value; use super::math_exp::exp; use super::math_ln::ln; // Below this exponent of e the result is smaller than any normal double. const SMALLEST: f64 = -708.0; const LARGEST: f64 = 709.0; /// base^exponent with the same bits in TypeScript, Python and Rust. /// /// A whole-number exponent is done by repeated squaring, so 10^3 is exactly /// 1000; any other is exp(exponent * ln(base)) from math.exp and math.ln. /// `f64::powf` calls the platform's maths library, whose last bit may differ. /// /// # Panics /// Panics on a non-finite argument, zero to a negative power, a negative base /// with a fractional exponent, or a result too large for a double. pub fn pow(base: f64, exponent: f64) -> f64 { if !base.is_finite() { panic!("pow needs a finite base, received {}", base); } if !exponent.is_finite() { panic!("pow needs a finite exponent, received {}", exponent); } if base == 0.0 { if exponent < 0.0 { panic!("zero cannot be raised to a negative power"); } return if exponent == 0.0 { 1.0 } else { 0.0 }; } if exponent.floor() == exponent { let mut n = exponent.abs(); let mut b = base; let mut result = 1.0; while n > 0.0 { if n % 2.0 == 1.0 { result *= b; } n = (n / 2.0).floor(); if n > 0.0 { b *= b; } } if exponent < 0.0 { result = 1.0 / result; } if !result.is_finite() { panic!("pow result is too large to represent"); } return result + 0.0; } if base < 0.0 { panic!("a negative base needs a whole-number exponent"); } let power = exponent * ln(base); if power > LARGEST { panic!("pow result is too large to represent"); } if power < SMALLEST { return 0.0; } exp(power) } pub fn fune_vector(args: &[Value]) -> Value { Value::Float(pow(args[0].as_f64(), args[1].as_f64())) }