Browse Source

add remaining math methods (#524) (#525)

* add `Math.clz32` method (#524)

* fix doc urls for clz32

* [#524] optimize impl for `Math.clz32`

* [#524] add implementation for `Math.expm1()`

* [#524] add implementation for `Math.fround()`

* [#524] implement `Math.hypot()`

* [#524] implement `Math.log1p()`

* [#524] implement `Math.imul()`

* improve `Math.clz32()` implementation

* [#524] add tests for more states
pull/538/head
Te-jé Rodgers 4 years ago committed by GitHub
parent
commit
d9ef1fb426
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 94
      boa/src/builtins/math/mod.rs
  2. 201
      boa/src/builtins/math/tests.rs

94
boa/src/builtins/math/mod.rs

@ -165,6 +165,21 @@ impl Math {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).ceil()).into())
}
/// Get the number of leading zeros in the 32 bit representation of a number
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-math.clz32
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
pub(crate) fn clz32(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(args
.get(0)
.map_or(32i32, |x| (f64::from(x) as u32).leading_zeros() as i32)
.into())
}
/// Get the cosine of a number.
///
/// More information:
@ -201,6 +216,23 @@ impl Math {
Ok(args.get(0).map_or(f64::NAN, |x| f64::from(x).exp()).into())
}
/// The Math.expm1() function returns e^x - 1, where x is the argument, and e the base of
/// the natural logarithms. The result is computed in a way that is accurate even when the
/// value of x is close 0
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-math.expm1
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/expm1
pub(crate) fn expm1(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(args
.get(0)
.map_or(f64::NAN, |x| f64::from(x).exp_m1())
.into())
}
/// Get the highest integer below a number.
///
/// More information:
@ -216,6 +248,47 @@ impl Math {
.into())
}
/// Get the nearest 32-bit single precision float representation of a number.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-math.fround
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround
pub(crate) fn fround(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(args
.get(0)
.map_or(f64::NAN, |x| (f64::from(x) as f32) as f64)
.into())
}
/// Get an approximation of the square root of the sum of squares of all arguments.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-math.hypot
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/hypot
pub(crate) fn hypot(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(args.iter().fold(0f64, |x, v| f64::from(v).hypot(x)).into())
}
/// Get the result of the C-like 32-bit multiplication of the two parameters.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-math.imul
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
pub(crate) fn imul(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
let a = args.get(0).map_or(0f64, f64::from);
let b = args.get(1).map_or(0f64, f64::from);
Ok(((a as u32).wrapping_mul(b as u32) as i32).into())
}
/// Get the natural logarithm of a number.
///
/// More information:
@ -238,6 +311,21 @@ impl Math {
.into())
}
/// Get approximation to the natural logarithm of 1 + x.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-math.log1p
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log1p
pub(crate) fn log1p(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(args
.get(0)
.map_or(f64::NAN, |x| f64::from(x).ln_1p())
.into())
}
/// Get the base 10 logarithm of the number.
///
/// More information:
@ -485,11 +573,17 @@ impl Math {
make_builtin_fn(Self::atan2, "atan2", &math, 2);
make_builtin_fn(Self::cbrt, "cbrt", &math, 1);
make_builtin_fn(Self::ceil, "ceil", &math, 1);
make_builtin_fn(Self::clz32, "clz32", &math, 1);
make_builtin_fn(Self::cos, "cos", &math, 1);
make_builtin_fn(Self::cosh, "cosh", &math, 1);
make_builtin_fn(Self::exp, "exp", &math, 1);
make_builtin_fn(Self::expm1, "expm1", &math, 1);
make_builtin_fn(Self::floor, "floor", &math, 1);
make_builtin_fn(Self::fround, "fround", &math, 1);
make_builtin_fn(Self::hypot, "hypot", &math, 1);
make_builtin_fn(Self::imul, "imul", &math, 1);
make_builtin_fn(Self::log, "log", &math, 1);
make_builtin_fn(Self::log1p, "log1p", &math, 1);
make_builtin_fn(Self::log10, "log10", &math, 1);
make_builtin_fn(Self::log2, "log2", &math, 1);
make_builtin_fn(Self::max, "max", &math, 2);

201
boa/src/builtins/math/tests.rs

@ -183,6 +183,42 @@ fn ceil() {
assert_eq!(c.to_number(), -7_f64);
}
#[test]
fn clz32() {
let realm = Realm::create();
let mut engine = Interpreter::new(realm);
let init = r#"
var a = Math.clz32();
var b = Math.clz32({});
var c = Math.clz32(-173);
var d = Math.clz32("1");
var e = Math.clz32(2147483647);
var f = Math.clz32(Infinity);
var g = Math.clz32(true);
var h = Math.clz32(0);
"#;
eprintln!("{}", forward(&mut engine, init));
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
let c = forward_val(&mut engine, "c").unwrap();
let d = forward_val(&mut engine, "d").unwrap();
let e = forward_val(&mut engine, "e").unwrap();
let f = forward_val(&mut engine, "f").unwrap();
let g = forward_val(&mut engine, "g").unwrap();
let h = forward_val(&mut engine, "h").unwrap();
assert_eq!(a.to_number(), 32_f64);
assert_eq!(b.to_number(), 32_f64);
assert_eq!(c.to_number(), 0_f64);
assert_eq!(d.to_number(), 31_f64);
assert_eq!(e.to_number(), 1_f64);
assert_eq!(f.to_number(), 32_f64);
assert_eq!(g.to_number(), 31_f64);
assert_eq!(h.to_number(), 32_f64);
}
#[test]
fn cos() {
let realm = Realm::create();
@ -243,6 +279,36 @@ fn exp() {
assert_eq!(c.to_number(), 7.389_056_098_930_65);
}
#[test]
fn expm1() {
let realm = Realm::create();
let mut engine = Interpreter::new(realm);
let init = r#"
var a = Math.expm1();
var b = Math.expm1({});
var c = Math.expm1(1);
var d = Math.expm1(-1);
var e = Math.expm1(0);
var f = Math.expm1(2);
"#;
eprintln!("{}", forward(&mut engine, init));
let a = forward(&mut engine, "a");
let b = forward(&mut engine, "b");
let c = forward_val(&mut engine, "c").unwrap();
let d = forward_val(&mut engine, "d").unwrap();
let e = forward_val(&mut engine, "e").unwrap();
let f = forward_val(&mut engine, "f").unwrap();
assert_eq!(a, String::from("NaN"));
assert_eq!(b, String::from("NaN"));
assert_eq!(c.to_number(), 1.718_281_828_459_045);
assert_eq!(d.to_number(), -0.632_120_558_828_557_7);
assert_eq!(e.to_number(), 0_f64);
assert_eq!(f.to_number(), 6.389_056_098_930_65);
}
#[test]
fn floor() {
let realm = Realm::create();
@ -264,6 +330,102 @@ fn floor() {
assert_eq!(c.to_number(), 3_f64);
}
#[test]
fn fround() {
let realm = Realm::create();
let mut engine = Interpreter::new(realm);
let init = r#"
var a = Math.fround(NaN);
var b = Math.fround(Infinity);
var c = Math.fround(5);
var d = Math.fround(5.5);
var e = Math.fround(5.05);
var f = Math.fround(-5.05);
var g = Math.fround();
"#;
eprintln!("{}", forward(&mut engine, init));
let a = forward(&mut engine, "a");
let b = forward(&mut engine, "b");
let c = forward_val(&mut engine, "c").unwrap();
let d = forward_val(&mut engine, "d").unwrap();
let e = forward_val(&mut engine, "e").unwrap();
let f = forward_val(&mut engine, "f").unwrap();
let g = forward(&mut engine, "g");
assert_eq!(a, String::from("NaN"));
assert_eq!(b, String::from("Infinity"));
assert_eq!(c.to_number(), 5f64);
assert_eq!(d.to_number(), 5.5f64);
assert_eq!(e.to_number(), 5.050_000_190_734_863);
assert_eq!(f.to_number(), -5.050_000_190_734_863);
assert_eq!(g, String::from("NaN"));
}
#[test]
fn hypot() {
let realm = Realm::create();
let mut engine = Interpreter::new(realm);
let init = r#"
var a = Math.hypot();
var b = Math.hypot(3, 4);
var c = Math.hypot(5, 12);
var d = Math.hypot(3, 4, -5);
var e = Math.hypot(4, [5], 6);
var f = Math.hypot(3, -Infinity);
var g = Math.hypot(12);
"#;
eprintln!("{}", forward(&mut engine, init));
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
let c = forward_val(&mut engine, "c").unwrap();
let d = forward_val(&mut engine, "d").unwrap();
let e = forward(&mut engine, "e");
let f = forward(&mut engine, "f");
let g = forward_val(&mut engine, "g").unwrap();
assert_eq!(a.to_number(), 0f64);
assert_eq!(b.to_number(), 5f64);
assert_eq!(c.to_number(), 13f64);
assert_eq!(d.to_number(), 7.071_067_811_865_475_5);
assert_eq!(e, String::from("NaN"));
assert_eq!(f, String::from("Infinity"));
assert_eq!(g.to_number(), 12f64);
}
#[test]
fn imul() {
let realm = Realm::create();
let mut engine = Interpreter::new(realm);
let init = r#"
var a = Math.imul(3, 4);
var b = Math.imul(-5, 12);
var c = Math.imul(0xffffffff, 5);
var d = Math.imul(0xfffffffe, 5);
var e = Math.imul(12);
var f = Math.imul();
"#;
eprintln!("{}", forward(&mut engine, init));
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
let c = forward_val(&mut engine, "c").unwrap();
let d = forward_val(&mut engine, "d").unwrap();
let e = forward_val(&mut engine, "e").unwrap();
let f = forward_val(&mut engine, "f").unwrap();
assert_eq!(a.to_number(), 12f64);
assert_eq!(b.to_number(), -60f64);
assert_eq!(c.to_number(), -5f64);
assert_eq!(d.to_number(), -10f64);
assert_eq!(e.to_number(), 0f64);
assert_eq!(f.to_number(), 0f64);
}
#[test]
fn log() {
let realm = Realm::create();
@ -285,6 +447,39 @@ fn log() {
assert_eq!(c, String::from("NaN"));
}
#[test]
fn log1p() {
let realm = Realm::create();
let mut engine = Interpreter::new(realm);
let init = r#"
var a = Math.log1p(1);
var b = Math.log1p(0);
var c = Math.log1p(-0.9999999999999999);
var d = Math.log1p(-1);
var e = Math.log1p(-1.000000000000001);
var f = Math.log1p(-2);
var g = Math.log1p();
"#;
eprintln!("{}", forward(&mut engine, init));
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
let c = forward_val(&mut engine, "c").unwrap();
let d = forward(&mut engine, "d");
let e = forward(&mut engine, "e");
let f = forward(&mut engine, "f");
let g = forward(&mut engine, "g");
assert_eq!(a.to_number(), f64::consts::LN_2);
assert_eq!(b.to_number(), 0f64);
assert_eq!(c.to_number(), -36.736_800_569_677_1);
assert_eq!(d, "-Infinity");
assert_eq!(e, String::from("NaN"));
assert_eq!(f, String::from("NaN"));
assert_eq!(g, String::from("NaN"));
}
#[test]
fn log10() {
let realm = Realm::create();
@ -334,7 +529,7 @@ fn max() {
let init = r#"
var a = Math.max(10, 20);
var b = Math.max(-10, -20);
var c = Math.max(-10, 20);
var c = Math.max(-10, 20);
"#;
eprintln!("{}", forward(&mut engine, init));
@ -355,7 +550,7 @@ fn min() {
let init = r#"
var a = Math.min(10, 20);
var b = Math.min(-10, -20);
var c = Math.min(-10, 20);
var c = Math.min(-10, 20);
"#;
eprintln!("{}", forward(&mut engine, init));
@ -418,7 +613,7 @@ fn sign() {
let init = r#"
var a = Math.sign(3);
var b = Math.sign(-3);
var c = Math.sign(0);
var c = Math.sign(0);
"#;
eprintln!("{}", forward(&mut engine, init));

Loading…
Cancel
Save