diff --git a/core/src/runtime/eval.rs b/core/src/runtime/eval.rs index 61cffd9..ccea756 100644 --- a/core/src/runtime/eval.rs +++ b/core/src/runtime/eval.rs @@ -294,50 +294,77 @@ pub(crate) fn eval_expr(ctx: &Context, expr: &Expr) -> Result ), 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 } 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")), })) } } diff --git a/core/tests/query.rs b/core/tests/query.rs index cb13f51..4b31e03 100644 --- a/core/tests/query.rs +++ b/core/tests/query.rs @@ -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]