summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorfrozolotl <44589151+frozolotl@users.noreply.github.com>2023-11-17 19:55:57 +0100
committerGitHub <noreply@github.com>2023-11-17 19:55:57 +0100
commit43f90b21592f5ab4885d63a351e7caa3b5bdb225 (patch)
treee922134ea942de7e2ce52f9b6d0921f7752be8a3 /crates
parentf5b3af3c1ba4eabef1630afa1c7d496af0b72557 (diff)
Implement euclidean division and remainder (#2678)
Diffstat (limited to 'crates')
-rw-r--r--crates/typst-library/src/compute/calc.rs58
1 files changed, 57 insertions, 1 deletions
diff --git a/crates/typst-library/src/compute/calc.rs b/crates/typst-library/src/compute/calc.rs
index 83bf924e..6276905c 100644
--- a/crates/typst-library/src/compute/calc.rs
+++ b/crates/typst-library/src/compute/calc.rs
@@ -50,6 +50,8 @@ fn module() -> Module {
scope.define_func::<even>();
scope.define_func::<odd>();
scope.define_func::<rem>();
+ scope.define_func::<div_euclid>();
+ scope.define_func::<rem_euclid>();
scope.define_func::<quo>();
scope.define("inf", f64::INFINITY);
scope.define("nan", f64::NAN);
@@ -790,7 +792,10 @@ pub fn odd(
/// in magnitude than `y`.
///
/// ```example
-/// #calc.rem(20, 6) \
+/// #calc.rem(7, 3) \
+/// #calc.rem(7, -3) \
+/// #calc.rem(-7, 3) \
+/// #calc.rem(-7, -3) \
/// #calc.rem(1.75, 0.5)
/// ```
#[func(title = "Remainder")]
@@ -806,6 +811,57 @@ pub fn rem(
Ok(dividend.apply2(divisor.v, Rem::rem, Rem::rem))
}
+/// Performs euclidean division of two numbers.
+///
+/// The result of this computation is that of a division rounded to the integer
+/// `{n}` such that the dividend is greater than or equal to `{n}` times the divisor.
+///
+/// ```example
+/// #calc.div-euclid(7, 3) \
+/// #calc.div-euclid(7, -3) \
+/// #calc.div-euclid(-7, 3) \
+/// #calc.div-euclid(-7, -3) \
+/// #calc.div-euclid(1.75, 0.5)
+/// ```
+#[func(title = "Euclidean Division")]
+pub fn div_euclid(
+ /// The dividend of the division.
+ dividend: Num,
+ /// The divisor of the division.
+ divisor: Spanned<Num>,
+) -> SourceResult<Num> {
+ if divisor.v.float() == 0.0 {
+ bail!(divisor.span, "divisor must not be zero");
+ }
+ Ok(dividend.apply2(divisor.v, i64::div_euclid, f64::div_euclid))
+}
+
+/// This calculates the least nonnegative remainder of a division.
+///
+/// Warning: Due to a floating point round-off error, the remainder may equal the absolute
+/// value of the divisor if the dividend is much smaller in magnitude than the divisor
+/// and the dividend is negative. This only applies for floating point inputs.
+///
+/// ```example
+/// #calc.rem-euclid(7, 3) \
+/// #calc.rem-euclid(7, -3) \
+/// #calc.rem-euclid(-7, 3) \
+/// #calc.rem-euclid(-7, -3) \
+/// #calc.rem(1.75, 0.5)
+/// ```
+#[func(title = "Euclidean Remainder")]
+pub fn rem_euclid(
+ /// The dividend of the remainder.
+ dividend: Num,
+ /// The divisor of the remainder.
+ divisor: Spanned<Num>,
+) -> SourceResult<Num> {
+ if divisor.v.float() == 0.0 {
+ bail!(divisor.span, "divisor must not be zero");
+ }
+ Ok(dividend.apply2(divisor.v, i64::rem_euclid, f64::rem_euclid))
+}
+
/// Calculates the quotient (floored division) of two numbers.
///
/// ```example