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}