Skip to main content

nanvm_lib/vm/number/
pow.rs

1use crate::vm::Number;
2
3impl Number {
4    /// `Math.pow(self, exponent)`, which is `self ** exponent`: the spec's
5    /// `Number::exponentiate`. Diverges from `f64::powf` (and C99's `pow`,
6    /// which `powf` follows) in exactly two spots: a `NaN` exponent is `NaN`
7    /// regardless of the base (C99 special-cases `pow(1, y) = 1` even for a
8    /// `NaN` `y`), and an infinite exponent against a base of magnitude 1 is
9    /// `NaN` (C99 gives `pow(±1, ±∞) = 1`). Every other case — zero/infinite
10    /// base or exponent, the sign and parity rules, a negative base with a
11    /// non-integer exponent giving `NaN` — already matches `powf` exactly, so
12    /// only these two get a special case. Not a `core::ops` trait — Rust has
13    /// no operator for exponentiation — so a plain method, the same as
14    /// `BigInt::pow` and `Any::pow`.
15    pub fn pow(self, exponent: Self) -> Self {
16        if exponent.is_nan() || (!exponent.is_finite() && self.0.abs() == 1.0) {
17            return Self::NAN;
18        }
19        self.0.powf(exponent.0).into()
20    }
21}
22
23#[cfg(test)]
24mod tests {
25    use crate::vm::Number;
26
27    fn n(v: f64) -> Number {
28        v.into()
29    }
30
31    /// The two departures from `powf`, and one case that follows it.
32    #[test]
33    fn departures_from_powf() {
34        assert!(n(1.0).pow(Number::NAN).is_nan());
35        assert!(n(1.0).pow(n(f64::INFINITY)).is_nan());
36        assert!(n(-1.0).pow(n(f64::NEG_INFINITY)).is_nan());
37        assert_eq!(n(2.0).pow(n(10.0)), n(1_024.0));
38    }
39}