From 419f409db8a4195a58354a6e3d0c1aac26d2984f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Te-j=C3=A9=20Rodgers?= Date: Thu, 25 Jun 2020 19:06:21 +0200 Subject: [PATCH] [#524] add implementation for `Math.expm1()` --- boa/src/builtins/math/mod.rs | 18 ++++++++++++++++++ boa/src/builtins/math/tests.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/boa/src/builtins/math/mod.rs b/boa/src/builtins/math/mod.rs index 9379318bb64..0bb3bd848f0 100644 --- a/boa/src/builtins/math/mod.rs +++ b/boa/src/builtins/math/mod.rs @@ -223,6 +223,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: @@ -511,6 +528,7 @@ impl Math { 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::log, "log", &math, 1); make_builtin_fn(Self::log10, "log10", &math, 1); diff --git a/boa/src/builtins/math/tests.rs b/boa/src/builtins/math/tests.rs index e661148135d..6b68c3046d7 100644 --- a/boa/src/builtins/math/tests.rs +++ b/boa/src/builtins/math/tests.rs @@ -279,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();