From 9e333e5058f54703fa9be0f34914061be6c8a272 Mon Sep 17 00:00:00 2001 From: Emanuel Date: Wed, 6 Dec 2023 14:32:56 +0100 Subject: [PATCH] Add calc.root function (#2736) Fixes #2522 --- crates/typst/src/foundations/calc.rs | 32 ++++++++++++++++++++++++++++ tests/typ/compute/calc.typ | 16 ++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/crates/typst/src/foundations/calc.rs b/crates/typst/src/foundations/calc.rs index 597bf156b..c65102ced 100644 --- a/crates/typst/src/foundations/calc.rs +++ b/crates/typst/src/foundations/calc.rs @@ -17,6 +17,7 @@ pub fn module() -> Module { scope.define_func::(); scope.define_func::(); scope.define_func::(); + scope.define_func::(); scope.define_func::(); scope.define_func::(); scope.define_func::(); @@ -183,6 +184,37 @@ pub fn sqrt( Ok(value.v.float().sqrt()) } +/// Calculates the real nth root of a number. +/// +/// If the number is negative, then n must be odd. +/// +/// ```example +/// #calc.root(16.0, 4) \ +/// #calc.root(27.0, 3) +/// ``` +#[func] +pub fn root( + /// The expression to take the root of + radicand: f64, + /// Which root of the radicand to take + index: Spanned, +) -> SourceResult { + if index.v == 0 { + bail!(index.span, "cannot take the 0th root of a number"); + } else if radicand < 0.0 { + if index.v % 2 == 0 { + bail!( + index.span, + "negative numbers do not have a real nth root when n is even" + ); + } else { + Ok(-(-radicand).powf(1.0 / index.v as f64)) + } + } else { + Ok(radicand.powf(1.0 / index.v as f64)) + } +} + /// Calculates the sine of an angle. /// /// When called with an integer or a float, they will be interpreted as diff --git a/tests/typ/compute/calc.typ b/tests/typ/compute/calc.typ index 86dcafcdb..e61e15d47 100644 --- a/tests/typ/compute/calc.typ +++ b/tests/typ/compute/calc.typ @@ -162,6 +162,22 @@ // Error: 12-14 cannot take square root of negative number #calc.sqrt(-1) +--- +#test(calc.root(12.0, 1), 12.0) +#test(calc.root(9.0, 2), 3.0) +#test(calc.root(27.0, 3), 3.0) +#test(calc.root(-27.0, 3), -3.0) +// 100^(-1/2) = (100^(1/2))^-1 = 1/sqrt(100) +#test(calc.root(100.0, -2), 0.1) + +--- +// Error: 17-18 cannot take the 0th root of a number +#calc.root(1.0, 0) + +--- +// Error: 24-25 negative numbers do not have a real nth root when n is even +#test(calc.root(-27.0, 4), -3.0) + --- // Error: 11-13 value must be strictly positive #calc.log(-1)