From 4aa5e0a4a3d005c25cbd12c843e464a791340c1a Mon Sep 17 00:00:00 2001 From: HarmoGlace <23212967+HarmoGlace@users.noreply.github.com> Date: Tue, 4 Apr 2023 14:33:26 +0200 Subject: [PATCH] Make behavior of calculation functions consistent (#515) --- library/src/compute/calc.rs | 45 +++++++++++++++++++++++++++++-------- tests/typ/compute/calc.typ | 20 +++++++++++++++++ 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/library/src/compute/calc.rs b/library/src/compute/calc.rs index ccc6e7b1d..c48c6816f 100644 --- a/library/src/compute/calc.rs +++ b/library/src/compute/calc.rs @@ -104,11 +104,23 @@ pub fn pow( _ => {} }; - match (base, exp) { + let return_value = match (base, exp) { (Num::Int(a), Num::Int(b)) if b >= 0 => Value::Int(a.pow(b as u32)), (a, Num::Int(b)) => Value::Float(a.float().powi(b as i32)), (a, b) => Value::Float(a.float().powf(b.float())), + }; + + let is_nan = match return_value { + Value::Float(f) => f.is_nan(), + Value::Int(i) => (i as f64).is_nan(), + _ => false, + }; + + if is_nan { + bail!(span, "the return value is not a real number") } + + return_value } /// Calculate the square root of a number. @@ -367,20 +379,35 @@ pub fn tanh( /// Returns: float #[func] pub fn log( - /// The number whose logarithm to calculate. - value: f64, - /// The base of the logarithm. + /// The number whose logarithm to calculate. It must be strictly positive. + value: Spanned, + /// The base of the logarithm. It can't be null. #[named] #[default(10.0)] base: f64, ) -> Value { - Value::Float(if base == 2.0 { - value.log2() + let number = value.v.float(); + + if number <= 0 as f64 { + bail!(value.span, "a logarithm parameter must be strictly positive") + } + if !base.is_normal() { + bail!(value.span, "a logarithm base should be normal (not NaN, not infinite, non-null, not subnormal)") + } + + let return_value = if base == 2.0 { + number.log2() } else if base == 10.0 { - value.log10() + number.log10() } else { - value.log(base) - }) + number.log(base) + }; + + if return_value.is_infinite() || return_value.is_nan() { + bail!(value.span, "this logarithm doesn't return a real value") + } + + Value::Float(return_value) } /// Round a number down to the nearest integer. diff --git a/tests/typ/compute/calc.typ b/tests/typ/compute/calc.typ index 51569f7ae..b7c6df02f 100644 --- a/tests/typ/compute/calc.typ +++ b/tests/typ/compute/calc.typ @@ -93,6 +93,26 @@ // Error: 14-36 exponent may not be NaN, infinite, or subnormal #calc.pow(2, calc.pow(2.0, 10000.0)) +--- +// Error: 15-18 the return value is not a real number +#calc.pow(-1, 0.5) + +--- +// Error: 12-14 cannot take square root of negative number +#calc.sqrt(-1) + +--- +// Error: 11-13 a logarithm parameter must be strictly positive +#calc.log(-1) + +--- +// Error: 11-12 a logarithm base should be normal (not NaN, not infinite, non-null, not subnormal) +#calc.log(1, base: 0) + +--- +// Error: 11-13 this logarithm doesn't return a real value +#calc.log(10, base: -1) + --- // Error: 10-12 expected at least one value #calc.min()