Functional Weave
Code in Rust

math.pow@1.0.0

impl/rust.rs

2,053 bytes · the Rust implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::math_exp::exp;  ← from math.exp ^1.0.0 · built alongside by fune
use super::math_ln::ln;  ← from math.ln ^1.0.0 · built alongside by fune

// 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()))
}