Trig function improvements (#164)

Implements #148.
This commit is contained in:
Tiffany Bennett 2024-04-13 14:48:18 -07:00 committed by GitHub
parent 92c58488d4
commit 1512265d46
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 72 additions and 29 deletions

View file

@ -294,50 +294,77 @@ pub(crate) fn eval_expr(ctx: &Context, expr: &Expr) -> Result<Value, QueryError>
),
Function::Sin => func!(
fn sin(num: Number) {
Ok(Value::Number(Number {
value: Numeric::Float(num.value.to_f64().sin()),
unit: num.unit.clone(),
}))
let radian = Dimensionality::base_unit(BaseUnit::new("radian"));
if !num.unit.is_dimensionless() && num.unit != radian {
Err("sin() accepts only angles or dimensionless inputs".to_owned())
} else {
Ok(Value::Number(Number {
value: Numeric::Float(num.value.to_f64().sin()),
unit: Dimensionality::new(),
}))
}
}
),
Function::Cos => func!(
fn cos(num: Number) {
Ok(Value::Number(Number {
value: Numeric::Float(num.value.to_f64().cos()),
unit: num.unit.clone(),
}))
let radian = Dimensionality::base_unit(BaseUnit::new("radian"));
if !num.unit.is_dimensionless() && num.unit != radian {
Err("cos() accepts only angles or dimensionless inputs".to_owned())
} else {
Ok(Value::Number(Number {
value: Numeric::Float(num.value.to_f64().cos()),
unit: Dimensionality::new(),
}))
}
}
),
Function::Tan => func!(
fn tan(num: Number) {
Ok(Value::Number(Number {
value: Numeric::Float(num.value.to_f64().tan()),
unit: num.unit.clone(),
}))
let radian = Dimensionality::base_unit(BaseUnit::new("radian"));
if !num.unit.is_dimensionless() && num.unit != radian {
Err("tan() accepts only angles or dimensionless inputs".to_owned())
} else {
Ok(Value::Number(Number {
value: Numeric::Float(num.value.to_f64().tan()),
unit: Dimensionality::new(),
}))
}
}
),
Function::Asin => func!(
fn asin(num: Number) {
Ok(Value::Number(Number {
value: Numeric::Float(num.value.to_f64().asin()),
unit: num.unit.clone(),
}))
if !num.unit.is_dimensionless() {
Err("asin() accepts only dimensionless inputs".to_owned())
} else {
Ok(Value::Number(Number {
value: Numeric::Float(num.value.to_f64().asin()),
unit: Dimensionality::base_unit(BaseUnit::new("radian")),
}))
}
}
),
Function::Acos => func!(
fn acos(num: Number) {
Ok(Value::Number(Number {
value: Numeric::Float(num.value.to_f64().acos()),
unit: num.unit.clone(),
}))
if !num.unit.is_dimensionless() {
Err("acos() accepts only dimensionless inputs".to_owned())
} else {
Ok(Value::Number(Number {
value: Numeric::Float(num.value.to_f64().acos()),
unit: Dimensionality::base_unit(BaseUnit::new("radian")),
}))
}
}
),
Function::Atan => func!(
fn atan(num: Number) {
Ok(Value::Number(Number {
value: Numeric::Float(num.value.to_f64().atan()),
unit: num.unit.clone(),
}))
if !num.unit.is_dimensionless() {
Err("atan() accepts only dimensionless inputs".to_owned())
} else {
Ok(Value::Number(Number {
value: Numeric::Float(num.value.to_f64().atan()),
unit: Dimensionality::base_unit(BaseUnit::new("radian")),
}))
}
}
),
Function::Atan2 => func!(
@ -347,7 +374,7 @@ pub(crate) fn eval_expr(ctx: &Context, expr: &Expr) -> Result<Value, QueryError>
} else {
Ok(Value::Number(Number {
value: Numeric::Float(x.value.to_f64().atan2(y.value.to_f64())),
unit: x.unit.clone(),
unit: Dimensionality::base_unit(BaseUnit::new("radian")),
}))
}
}

View file

@ -380,15 +380,31 @@ fn test_functions() {
test("log(27, 3)", "approx. 3 (dimensionless)");
test("sin(pi/2)", "approx. 1 (dimensionless)");
test("cos(asin(0.5) - pi/2)", "approx. 0.5000000 (dimensionless)");
test("atan(tan(0.42))", "approx. 0.4199999 (dimensionless)");
test("acos(1)", "approx. 0 (dimensionless)");
test(
"cos(asin(0.5) - 0.5 pi radian)",
"approx. 0.5000000 (dimensionless)",
);
test("atan(tan(0.42))", "approx. 420 milliradian (angle)");
test("acos(1)", "approx. 0 radian (angle)");
test("acosh(cosh(1))", "approx. 1 (dimensionless)");
// test("asinh(sinh(0.123))", "approx. 0.1230000 (dimensionless)");
// test("atanh(tanh(1.23))", "approx. 1.230000 (dimensionless)");
test("hypot(3 m, 4 m)", "approx. 5 meter (length)");
test("atan2(7, 6)", "approx. 0.8621700 (dimensionless)");
test("atan2(7, 6)", "approx. 862.1700 milliradian (angle)");
test("sin(90deg)", "approx. 1 (dimensionless)");
test("cos(180deg)", "approx. -1 (dimensionless)");
test("tan(45deg)", "approx. 0.9999999 (dimensionless)");
test("asin(1) to deg", "approx. 90 degree (angle)");
test("acos(0) to deg", "approx. 90 degree (angle)");
test("atan(1) to deg", "approx. 45 degree (angle)");
test(
"atan2(6inch, 12foot) to deg",
"approx. 2.385944 degree (angle)",
);
}
#[test]