diff --git a/boa/src/builtins/math.rs b/boa/src/builtins/math/mod.rs similarity index 64% rename from boa/src/builtins/math.rs rename to boa/src/builtins/math/mod.rs index b8e337c1e4..77b1a96274 100644 --- a/boa/src/builtins/math.rs +++ b/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::(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::(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::(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::(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::(args.get(0).expect("Could not get argument").clone()) - .expect("Could not convert argument to f64") - .log(f64::consts::E) + let value = from_value::(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::(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::(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::(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::(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::(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::(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 } diff --git a/boa/src/builtins/math/tests.rs b/boa/src/builtins/math/tests.rs new file mode 100644 index 0000000000..8049e35991 --- /dev/null +++ b/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)); +}