Browse Source

Add methods with f64 std equivelant to Math object (#260)

* Add methods with f64 std equivelant to Math object
* Add testS for Math static methods
pull/280/head
Nick Vernij 5 years ago committed by GitHub
parent
commit
9b8c803bbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 139
      boa/src/builtins/math/mod.rs
  2. 541
      boa/src/builtins/math/tests.rs

139
boa/src/builtins/math.rs → boa/src/builtins/math/mod.rs

@ -8,6 +8,9 @@ use crate::{
use rand::random;
use std::f64;
#[cfg(test)]
mod tests;
/// Get the absolute value of a number
pub fn abs(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
@ -28,6 +31,16 @@ pub fn acos(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
.acos()
}))
}
/// Get the hyperbolic arccos of a number
pub fn acosh(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
f64::NAN
} else {
from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.expect("Could not convert argument to f64")
.acosh()
}))
}
/// Get the arcsine of a number
pub fn asin(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
@ -38,6 +51,16 @@ pub fn asin(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
.asin()
}))
}
/// Get the hyperbolic arcsine of a number
pub fn asinh(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
f64::NAN
} else {
from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.expect("Could not convert argument to f64")
.asinh()
}))
}
/// Get the arctangent of a number
pub fn atan(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
@ -48,6 +71,16 @@ pub fn atan(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
.atan()
}))
}
/// Get the hyperbolic arctangent of a number
pub fn atanh(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
f64::NAN
} else {
from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.expect("Could not convert argument to f64")
.atanh()
}))
}
/// Get the arctangent of a numbers
pub fn atan2(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
@ -88,6 +121,16 @@ pub fn cos(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
.cos()
}))
}
/// Get the hyperbolic cosine of a number
pub fn cosh(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
f64::NAN
} else {
from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.expect("Could not convert argument to f64")
.cosh()
}))
}
/// Get the power to raise the natural logarithm to get the number
pub fn exp(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
@ -113,9 +156,44 @@ pub fn log(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
f64::NAN
} else {
from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.expect("Could not convert argument to f64")
.log(f64::consts::E)
let value = from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.expect("Could not convert argument to f64");
if value <= 0.0 {
f64::NAN
} else {
value.log(f64::consts::E)
}
}))
}
/// Get the base 10 logarithm of the number
pub fn log10(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
f64::NAN
} else {
let value = from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.expect("Could not convert argument to f64");
if value <= 0.0 {
f64::NAN
} else {
value.log10()
}
}))
}
/// Get the base 2 logarithm of the number
pub fn log2(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
f64::NAN
} else {
let value = from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.expect("Could not convert argument to f64");
if value <= 0.0 {
f64::NAN
} else {
value.log2()
}
}))
}
/// Get the maximum of several numbers
@ -162,6 +240,21 @@ pub fn round(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
.round()
}))
}
/// Get the sign of a number
pub fn sign(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
f64::NAN
} else {
let value = from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.expect("Could not convert argument to f64");
if value == 0.0 || value == -0.0 {
value
} else {
value.signum()
}
}))
}
/// Get the sine of a number
pub fn sin(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
@ -172,6 +265,16 @@ pub fn sin(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
.sin()
}))
}
/// Get the hyperbolic sine of a number
pub fn sinh(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
f64::NAN
} else {
from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.expect("Could not convert argument to f64")
.sinh()
}))
}
/// Get the square root of a number
pub fn sqrt(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
@ -192,6 +295,26 @@ pub fn tan(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
.tan()
}))
}
/// Get the hyperbolic tangent of a number
pub fn tanh(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
f64::NAN
} else {
from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.expect("Could not convert argument to f64")
.tanh()
}))
}
/// Get the integer part of a number
pub fn trunc(_: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(to_value(if args.is_empty() {
f64::NAN
} else {
from_value::<f64>(args.get(0).expect("Could not get argument").clone())
.expect("Could not convert argument to f64")
.trunc()
}))
}
/// Create a new `Math` object
pub fn create_constructor(global: &Value) -> Value {
let math = ValueData::new_obj(Some(global));
@ -205,22 +328,32 @@ pub fn create_constructor(global: &Value) -> Value {
math.set_field_slice("PI", to_value(f64::consts::PI));
make_builtin_fn!(abs, named "abs", with length 1, of math);
make_builtin_fn!(acos, named "acos", with length 1, of math);
make_builtin_fn!(acosh, named "acosh", with length 1, of math);
make_builtin_fn!(asin, named "asin", with length 1, of math);
make_builtin_fn!(asinh, named "asinh", with length 1, of math);
make_builtin_fn!(atan, named "atan", with length 1, of math);
make_builtin_fn!(atanh, named "atanh", with length 1, of math);
make_builtin_fn!(atan2, named "atan2", with length 2, of math);
make_builtin_fn!(cbrt, named "cbrt", with length 1, of math);
make_builtin_fn!(ceil, named "ceil", with length 1, of math);
make_builtin_fn!(cos, named "cos", with length 1, of math);
make_builtin_fn!(cosh, named "cosh", with length 1, of math);
make_builtin_fn!(exp, named "exp", with length 1, of math);
make_builtin_fn!(floor, named "floor", with length 1, of math);
make_builtin_fn!(log, named "log", with length 1, of math);
make_builtin_fn!(log10, named "log10", with length 1, of math);
make_builtin_fn!(log2, named "log2", with length 1, of math);
make_builtin_fn!(max, named "max", with length 2, of math);
make_builtin_fn!(min, named "min", with length 2, of math);
make_builtin_fn!(pow, named "pow", with length 2, of math);
make_builtin_fn!(_random, named "random", of math);
make_builtin_fn!(round, named "round", with length 1, of math);
make_builtin_fn!(sign, named "sign", with length 1, of math);
make_builtin_fn!(sin, named "sin", with length 1, of math);
make_builtin_fn!(sinh, named "sinh", with length 1, of math);
make_builtin_fn!(sqrt, named "sqrt", with length 1, of math);
make_builtin_fn!(tan, named "tan", with length 1, of math);
make_builtin_fn!(tanh, named "tanh", with length 1, of math);
make_builtin_fn!(trunc, named "trunc", with length 1, of math);
math
}

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

@ -0,0 +1,541 @@
use crate::{exec::Executor, forward, forward_val, realm::Realm};
use std::f64;
#[test]
fn abs() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.abs(3 - 5);
var b = Math.abs(1.23456 - 7.89012);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
assert_eq!(a.to_num(), f64::from(2.0));
assert_eq!(b.to_num(), f64::from(6.655_559_999_999_999_5));
}
#[test]
fn acos() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.acos(8 / 10);
var b = Math.acos(5 / 3);
var c = Math.acos(1);
var d = Math.acos(2);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward(&mut engine, "b");
let c = forward_val(&mut engine, "c").unwrap();
let d = forward(&mut engine, "d");
assert_eq!(a.to_num(), f64::from(0.643_501_108_793_284_3));
assert_eq!(b, String::from("NaN"));
assert_eq!(c.to_num(), f64::from(0));
assert_eq!(d, String::from("NaN"));
}
#[test]
fn acosh() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.acosh(2);
var b = Math.acosh(-1);
var c = Math.acosh(0.5);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward(&mut engine, "b");
let c = forward(&mut engine, "c");
assert_eq!(a.to_num(), f64::from(1.316_957_896_924_816_6));
assert_eq!(b, String::from("NaN"));
assert_eq!(c, String::from("NaN"));
}
#[test]
fn asin() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.asin(6 / 10);
var b = Math.asin(5 / 3);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward(&mut engine, "b");
assert_eq!(a.to_num(), f64::from(0.643_501_108_793_284_4));
assert_eq!(b, String::from("NaN"));
}
#[test]
fn asinh() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.asinh(1);
var b = Math.asinh(0);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
assert_eq!(a.to_num(), f64::from(0.881_373_587_019_542_9));
assert_eq!(b.to_num(), f64::from(0));
}
#[test]
fn atan() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.atan(1);
var b = Math.atan(0);
var c = Math.atan(-0);
"#;
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();
assert_eq!(a.to_num(), f64::from(0.785_398_163_397_448_3));
assert_eq!(b.to_num(), f64::from(0));
assert_eq!(c.to_num(), f64::from(-0));
}
#[test]
fn atan2() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.atan2(90, 15);
var b = Math.atan2(15, 90);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
assert_eq!(a.to_num(), f64::from(1.405_647_649_380_269_9));
assert_eq!(b.to_num(), f64::from(0.165_148_677_414_626_83));
}
#[test]
fn cbrt() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.cbrt(64);
var b = Math.cbrt(-1);
var c = Math.cbrt(1);
"#;
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();
assert_eq!(a.to_num(), f64::from(4));
assert_eq!(b.to_num(), f64::from(-1));
assert_eq!(c.to_num(), f64::from(1));
}
#[test]
fn ceil() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.ceil(1.95);
var b = Math.ceil(4);
var c = Math.ceil(-7.004);
"#;
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();
assert_eq!(a.to_num(), f64::from(2));
assert_eq!(b.to_num(), f64::from(4));
assert_eq!(c.to_num(), f64::from(-7));
}
#[test]
fn cos() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.cos(0);
var b = Math.cos(1);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
assert_eq!(a.to_num(), f64::from(1));
assert_eq!(b.to_num(), f64::from(0.540_302_305_868_139_8));
}
#[test]
fn cosh() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.cosh(0);
var b = Math.cosh(1);
var c = Math.cosh(-1);
"#;
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();
assert_eq!(a.to_num(), f64::from(1));
assert_eq!(b.to_num(), f64::from(1.543_080_634_815_243_7));
assert_eq!(c.to_num(), f64::from(1.543_080_634_815_243_7));
}
#[test]
fn exp() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.exp(0);
var b = Math.exp(-1);
var c = Math.exp(2);
"#;
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();
assert_eq!(a.to_num(), f64::from(1));
assert_eq!(b.to_num(), f64::from(0.367_879_441_171_442_33));
assert_eq!(c.to_num(), f64::from(7.389_056_098_930_65));
}
#[test]
fn floor() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.floor(1.95);
var b = Math.floor(-3.01);
var c = Math.floor(3.01);
"#;
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();
assert_eq!(a.to_num(), f64::from(1));
assert_eq!(b.to_num(), f64::from(-4));
assert_eq!(c.to_num(), f64::from(3));
}
#[test]
fn log() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.log(1);
var b = Math.log(10);
var c = Math.log(-1);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
let c = forward(&mut engine, "c");
assert_eq!(a.to_num(), f64::from(0));
assert_eq!(b.to_num(), f64::from(2.302_585_092_994_046));
assert_eq!(c, String::from("NaN"));
}
#[test]
fn log10() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.log10(2);
var b = Math.log10(1);
var c = Math.log10(-2);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
let c = forward(&mut engine, "c");
assert_eq!(a.to_num(), f64::from(0.301_029_995_663_981_2));
assert_eq!(b.to_num(), f64::from(0));
assert_eq!(c, String::from("NaN"));
}
#[test]
fn log2() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.log2(3);
var b = Math.log2(1);
var c = Math.log2(-2);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
let c = forward(&mut engine, "c");
assert_eq!(a.to_num(), f64::from(1.584_962_500_721_156));
assert_eq!(b.to_num(), f64::from(0));
assert_eq!(c, String::from("NaN"));
}
#[test]
fn max() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.max(10, 20);
var b = Math.max(-10, -20);
var c = Math.max(-10, 20);
"#;
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();
assert_eq!(a.to_num(), f64::from(20));
assert_eq!(b.to_num(), f64::from(-10));
assert_eq!(c.to_num(), f64::from(20));
}
#[test]
fn min() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.min(10, 20);
var b = Math.min(-10, -20);
var c = Math.min(-10, 20);
"#;
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();
assert_eq!(a.to_num(), f64::from(10));
assert_eq!(b.to_num(), f64::from(-20));
assert_eq!(c.to_num(), f64::from(-10));
}
#[test]
fn pow() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.pow(2, 10);
var b = Math.pow(-7, 2);
var c = Math.pow(4, 0.5);
var d = Math.pow(7, -2);
"#;
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();
assert_eq!(a.to_num(), f64::from(1024));
assert_eq!(b.to_num(), f64::from(49));
assert_eq!(c.to_num(), f64::from(2.0));
assert_eq!(d.to_num(), f64::from(0.020_408_163_265_306_12));
}
#[test]
fn round() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.round(20.5);
var b = Math.round(-20.3);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
assert_eq!(a.to_num(), f64::from(21.0));
assert_eq!(b.to_num(), f64::from(-20.0));
}
#[test]
fn sign() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.sign(3);
var b = Math.sign(-3);
var c = Math.sign(0);
"#;
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();
assert_eq!(a.to_num(), f64::from(1));
assert_eq!(b.to_num(), f64::from(-1));
assert_eq!(c.to_num(), f64::from(0));
}
#[test]
fn sin() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.sin(0);
var b = Math.sin(1);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
assert_eq!(a.to_num(), f64::from(0));
assert_eq!(b.to_num(), f64::from(0.841_470_984_807_896_5));
}
#[test]
fn sinh() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.sinh(0);
var b = Math.sinh(1);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
assert_eq!(a.to_num(), f64::from(0));
assert_eq!(b.to_num(), f64::from(1.175_201_193_643_801_4));
}
#[test]
fn sqrt() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.sqrt(0);
var b = Math.sqrt(2);
var c = Math.sqrt(9);
"#;
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();
assert_eq!(a.to_num(), f64::from(0));
assert_eq!(b.to_num(), f64::from(1.414_213_562_373_095_1));
assert_eq!(c.to_num(), f64::from(3));
}
// TODO: Precision is always off between ci and local. We proably need a better way to compare floats anyways
// #[test]
// fn tan() {
// let realm = Realm::create();
// let mut engine = Executor::new(realm);
// let init = r#"
// var a = Math.tan(1.1);
// "#;
// forward(&mut engine, init);
// let a = forward_val(&mut engine, "a").unwrap();
// assert_eq!(a.to_num(), f64::from(1.964_759_657_248_652_5));
// }
#[test]
fn tanh() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.tanh(1);
var b = Math.tanh(0);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
assert_eq!(a.to_num(), f64::from(0.761_594_155_955_764_9));
assert_eq!(b.to_num(), f64::from(0));
}
#[test]
fn trunc() {
let realm = Realm::create();
let mut engine = Executor::new(realm);
let init = r#"
var a = Math.trunc(13.37);
var b = Math.trunc(0.123);
"#;
forward(&mut engine, init);
let a = forward_val(&mut engine, "a").unwrap();
let b = forward_val(&mut engine, "b").unwrap();
assert_eq!(a.to_num(), f64::from(13));
assert_eq!(b.to_num(), f64::from(0));
}
Loading…
Cancel
Save