Skip to main content

typst_library/foundations/
calc.rs

1//! Calculations and processing of numeric values.
2
3use std::cmp;
4use std::cmp::Ordering;
5
6use az::SaturatingAs;
7use typst_syntax::{Span, Spanned};
8use typst_utils::{Scalar, round_int_with_precision, round_with_precision};
9
10use crate::diag::{At, HintedString, SourceResult, StrResult, bail};
11use crate::foundations::{Decimal, IntoValue, Module, Scope, Value, cast, func, ops};
12use crate::layout::{Angle, Fr, Length, Ratio};
13
14/// A module with calculation definitions.
15pub fn module() -> Module {
16    let mut scope = Scope::new();
17    scope.define_func::<abs>();
18    scope.define_func::<pow>();
19    scope.define_func::<exp>();
20    scope.define_func::<sqrt>();
21    scope.define_func::<root>();
22    scope.define_func::<sin>();
23    scope.define_func::<cos>();
24    scope.define_func::<tan>();
25    scope.define_func::<asin>();
26    scope.define_func::<acos>();
27    scope.define_func::<atan>();
28    scope.define_func::<atan2>();
29    scope.define_func::<sinh>();
30    scope.define_func::<cosh>();
31    scope.define_func::<tanh>();
32    scope.define_func::<asinh>();
33    scope.define_func::<acosh>();
34    scope.define_func::<atanh>();
35    scope.define_func::<log>();
36    scope.define_func::<ln>();
37    scope.define_func::<erf>();
38    scope.define_func::<fact>();
39    scope.define_func::<perm>();
40    scope.define_func::<binom>();
41    scope.define_func::<gcd>();
42    scope.define_func::<lcm>();
43    scope.define_func::<floor>();
44    scope.define_func::<ceil>();
45    scope.define_func::<trunc>();
46    scope.define_func::<fract>();
47    scope.define_func::<round>();
48    scope.define_func::<clamp>();
49    scope.define_func::<min>();
50    scope.define_func::<max>();
51    scope.define_func::<even>();
52    scope.define_func::<odd>();
53    scope.define_func::<rem>();
54    scope.define_func::<div_euclid>();
55    scope.define_func::<rem_euclid>();
56    scope.define_func::<quo>();
57    scope.define_func::<norm>();
58    scope.define("inf", f64::INFINITY);
59    scope.define("pi", std::f64::consts::PI);
60    scope.define("tau", std::f64::consts::TAU);
61    scope.define("e", std::f64::consts::E);
62    Module::new("calc", scope)
63}
64
65/// Calculates the absolute value of a numeric value.
66///
67/// ```example
68/// #calc.abs(-5) \
69/// #calc.abs(5pt - 2cm) \
70/// #calc.abs(2fr) \
71/// #calc.abs(decimal("-342.440"))
72/// ```
73#[func(title = "Absolute")]
74pub fn abs(
75    /// The value whose absolute value to calculate.
76    value: ToAbs,
77) -> Value {
78    value.0
79}
80
81/// A value of which the absolute value can be taken.
82pub struct ToAbs(Value);
83
84cast! {
85    ToAbs,
86    v: i64 => Self(v.checked_abs().ok_or_else(too_large)?.into_value()),
87    v: f64 => Self(v.abs().into_value()),
88    v: Length => Self(Value::Length(v.try_abs()
89        .ok_or("cannot take absolute value of this length")?)),
90    v: Angle => Self(Value::Angle(v.abs())),
91    v: Ratio => Self(Value::Ratio(v.abs())),
92    v: Fr => Self(Value::Fraction(v.abs())),
93    v: Decimal => Self(Value::Decimal(v.abs()))
94}
95
96/// Raises a value to some exponent.
97///
98/// ```example
99/// #calc.pow(2, 3) \
100/// #calc.pow(decimal("2.5"), 2)
101/// ```
102#[func(title = "Power")]
103pub fn pow(
104    span: Span,
105    /// The base of the power.
106    ///
107    /// If this is a @decimal, the exponent can only be an @int[integer].
108    base: DecNum,
109    /// The exponent of the power.
110    exponent: Spanned<Num>,
111) -> SourceResult<DecNum> {
112    match exponent.v {
113        _ if exponent.v.float() == 0.0 && base.is_zero() => {
114            bail!(span, "zero to the power of zero is undefined")
115        }
116        Num::Int(i) if i32::try_from(i).is_err() => {
117            bail!(exponent.span, "exponent is too large")
118        }
119        Num::Float(f) if !f.is_normal() && f != 0.0 => {
120            bail!(exponent.span, "exponent may not be infinite, subnormal, or NaN")
121        }
122        _ => {}
123    };
124
125    match (base, exponent.v) {
126        (DecNum::Int(a), Num::Int(b)) if b >= 0 => a
127            .checked_pow(b as u32)
128            .map(DecNum::Int)
129            .ok_or_else(too_large)
130            .at(span),
131        (DecNum::Decimal(a), Num::Int(b)) => {
132            a.checked_powi(b).map(DecNum::Decimal).ok_or_else(too_large).at(span)
133        }
134        (a, b) => {
135            let Some(a) = a.float() else {
136                return Err(cant_apply_to_decimal_and_float()).at(span);
137            };
138
139            let result = if a == std::f64::consts::E {
140                libm::exp(b.float())
141            } else if a == 2.0 {
142                libm::exp2(b.float())
143            } else if let Num::Int(b) = b {
144                Scalar::new(a).powi(b as i32).get()
145            } else {
146                libm::pow(a, b.float())
147            };
148
149            if result.is_nan() {
150                bail!(span, "the result is not a real number")
151            }
152
153            Ok(DecNum::Float(result))
154        }
155    }
156}
157
158/// Raises a value to some exponent of $e$.
159///
160/// ```example
161/// #calc.exp(1)
162/// ```
163#[func(title = "Exponential")]
164pub fn exp(
165    span: Span,
166    /// The exponent of the power.
167    exponent: Spanned<Num>,
168) -> SourceResult<f64> {
169    match exponent.v {
170        Num::Int(i) if i32::try_from(i).is_err() => {
171            bail!(exponent.span, "exponent is too large")
172        }
173        Num::Float(f) if !f.is_normal() && f != 0.0 => {
174            bail!(exponent.span, "exponent may not be infinite, subnormal, or NaN")
175        }
176        _ => {}
177    }
178
179    let result = libm::exp(exponent.v.float());
180    if result.is_nan() {
181        bail!(span, "the result is not a real number")
182    }
183
184    Ok(result)
185}
186
187/// Calculates the square root of a number.
188///
189/// ```example
190/// #calc.sqrt(16) \
191/// #calc.sqrt(2.5)
192/// ```
193#[func(title = "Square Root")]
194pub fn sqrt(
195    /// The number whose square root to calculate. Must be non-negative.
196    value: Spanned<Num>,
197) -> SourceResult<f64> {
198    if value.v.float() < 0.0 {
199        bail!(value.span, "cannot take square root of negative number");
200    }
201    Ok(value.v.float().sqrt())
202}
203
204/// Calculates the real $n$#super[th] root of a number.
205///
206/// If the number is negative, then $n$ must be odd.
207///
208/// ```example
209/// #calc.root(16.0, 4) \
210/// #calc.root(27.0, 3)
211/// ```
212#[func]
213pub fn root(
214    /// The expression to take the root of.
215    radicand: f64,
216    /// The value of $n$.
217    index: Spanned<i64>,
218) -> SourceResult<f64> {
219    if index.v == 0 {
220        bail!(index.span, "cannot take the 0th root of a number");
221    } else if radicand < 0.0 {
222        if index.v % 2 == 0 {
223            bail!(
224                index.span,
225                "negative numbers do not have a real nth root when n is even",
226            );
227        } else {
228            Ok(-libm::pow(-radicand, 1.0 / index.v as f64))
229        }
230    } else {
231        Ok(libm::pow(radicand, 1.0 / index.v as f64))
232    }
233}
234
235/// Calculates the sine of an angle.
236///
237/// When called with an integer or a float, they will be interpreted as radians.
238///
239/// ```example
240/// #calc.sin(1.5) \
241/// #calc.sin(90deg)
242/// ```
243#[func(title = "Sine")]
244pub fn sin(
245    /// The angle whose sine to calculate.
246    angle: AngleLike,
247) -> f64 {
248    match angle {
249        AngleLike::Angle(a) => a.sin(),
250        AngleLike::Int(n) => libm::sin(n as f64),
251        AngleLike::Float(n) => libm::sin(n),
252    }
253}
254
255/// Calculates the cosine of an angle.
256///
257/// When called with an integer or a float, they will be interpreted as radians.
258///
259/// ```example
260/// #calc.cos(1.5) \
261/// #calc.cos(90deg)
262/// ```
263#[func(title = "Cosine")]
264pub fn cos(
265    /// The angle whose cosine to calculate.
266    angle: AngleLike,
267) -> f64 {
268    match angle {
269        AngleLike::Angle(a) => a.cos(),
270        AngleLike::Int(n) => libm::cos(n as f64),
271        AngleLike::Float(n) => libm::cos(n),
272    }
273}
274
275/// Calculates the tangent of an angle.
276///
277/// When called with an integer or a float, they will be interpreted as radians.
278///
279/// ```example
280/// #calc.tan(1.5) \
281/// #calc.tan(90deg)
282/// ```
283#[func(title = "Tangent")]
284pub fn tan(
285    /// The angle whose tangent to calculate.
286    angle: AngleLike,
287) -> f64 {
288    match angle {
289        AngleLike::Angle(a) => a.tan(),
290        AngleLike::Int(n) => libm::tan(n as f64),
291        AngleLike::Float(n) => libm::tan(n),
292    }
293}
294
295/// Calculates the arcsine of a number.
296///
297/// ```example
298/// #calc.asin(0) \
299/// #calc.asin(1)
300/// ```
301#[func(title = "Arcsine")]
302pub fn asin(
303    /// The number whose arcsine to calculate. Must be between $-1$ and $1$.
304    value: Spanned<Num>,
305) -> SourceResult<Angle> {
306    let val = value.v.float();
307    if val < -1.0 || val > 1.0 {
308        bail!(value.span, "value must be between -1 and 1");
309    }
310    Ok(Angle::asin(val))
311}
312
313/// Calculates the arccosine of a number.
314///
315/// ```example
316/// #calc.acos(0) \
317/// #calc.acos(1)
318/// ```
319#[func(title = "Arccosine")]
320pub fn acos(
321    /// The number whose arccosine to calculate. Must be between $-1$ and $1$.
322    value: Spanned<Num>,
323) -> SourceResult<Angle> {
324    let val = value.v.float();
325    if val < -1.0 || val > 1.0 {
326        bail!(value.span, "value must be between -1 and 1");
327    }
328    Ok(Angle::acos(val))
329}
330
331/// Calculates the arctangent of a number.
332///
333/// ```example
334/// #calc.atan(0) \
335/// #calc.atan(1)
336/// ```
337#[func(title = "Arctangent")]
338pub fn atan(
339    /// The number whose arctangent to calculate.
340    value: Num,
341) -> Angle {
342    Angle::atan(value.float())
343}
344
345/// Calculates the four-quadrant arctangent of a coordinate.
346///
347/// The four-quadrant arctangent of $(x, y)$ is defined as the argument of the
348/// complex number $x + i y$.
349///
350/// Returns an @angle between `{-180deg}` and `{180deg}`.
351///
352/// Note that this function accepts $(x, y)$, not $(y, x)$.
353///
354/// ```example
355/// #calc.atan2(1, 1) \
356/// #calc.atan2(-2, -3)
357/// ```
358#[func(title = "Four-quadrant Arctangent")]
359pub fn atan2(
360    /// The $x$ coordinate.
361    x: Num,
362    /// The $y$ coordinate.
363    y: Num,
364) -> Angle {
365    Angle::atan2(y.float(), x.float())
366}
367
368/// Calculates the hyperbolic sine of a hyperbolic angle.
369///
370/// The hyperbolic sine of $x$ is defined as follows:
371/// $ (e^x - e^(-x)) / 2 $
372///
373/// ```example
374/// #calc.sinh(0) \
375/// #calc.sinh(1.5)
376/// ```
377#[func(title = "Hyperbolic Sine")]
378pub fn sinh(
379    /// The hyperbolic angle whose hyperbolic sine to calculate.
380    value: f64,
381) -> f64 {
382    libm::sinh(value)
383}
384
385/// Calculates the hyperbolic cosine of a hyperbolic angle.
386///
387/// The hyperbolic cosine of $x$ is defined as follows:
388/// $ (e^x + e^(-x)) / 2 $
389///
390/// ```example
391/// #calc.cosh(0) \
392/// #calc.cosh(1.5)
393/// ```
394#[func(title = "Hyperbolic Cosine")]
395pub fn cosh(
396    /// The hyperbolic angle whose hyperbolic cosine to calculate.
397    value: f64,
398) -> f64 {
399    libm::cosh(value)
400}
401
402/// Calculates the hyperbolic tangent of a hyperbolic angle.
403///
404/// The hyperbolic tangent of $x$ is defined as follows:
405/// $ (e^x - e^(-x)) / (e^x + e^(-x)) $
406///
407/// ```example
408/// #calc.tanh(0) \
409/// #calc.tanh(1.5)
410/// ```
411#[func(title = "Hyperbolic Tangent")]
412pub fn tanh(
413    /// The hyperbolic angle whose hyperbolic tangent to calculate.
414    value: f64,
415) -> f64 {
416    libm::tanh(value)
417}
418
419/// Calculates the inverse hyperbolic sine of a number.
420///
421/// The inverse hyperbolic sine of $x$ is defined as follows:
422/// $ ln(x + sqrt(x^2 + 1)) $
423///
424/// ```example
425/// #calc.asinh(0) \
426/// #calc.asinh(1)
427/// ```
428#[func(title = "Inverse Hyperbolic Sine")]
429pub fn asinh(
430    /// The number whose inverse hyperbolic sine to calculate.
431    value: f64,
432) -> f64 {
433    libm::asinh(value)
434}
435
436/// Calculates the inverse hyperbolic cosine of a number.
437///
438/// The inverse hyperbolic cosine of $x$ is defined as follows:
439/// $ ln(x + sqrt(x^2 - 1)) $
440///
441/// ```example
442/// #calc.acosh(1) \
443/// #calc.acosh(2.5)
444/// ```
445#[func(title = "Inverse Hyperbolic Cosine")]
446pub fn acosh(
447    /// The number whose inverse hyperbolic cosine to calculate. Must be greater
448    /// than or equal to $1$.
449    value: Spanned<f64>,
450) -> SourceResult<f64> {
451    let val = value.v;
452    if val < 1.0 {
453        bail!(value.span, "value must be greater than or equal to 1");
454    }
455    Ok(libm::acosh(val))
456}
457
458/// Calculates the inverse hyperbolic tangent of a number.
459///
460/// The inverse hyperbolic tangent of $x$ is defined as follows:
461/// $ 1/2 ln((1 + x) / (1 - x)) $
462///
463/// ```example
464/// #calc.atanh(0) \
465/// #calc.atanh(0.5)
466/// ```
467#[func(title = "Inverse Hyperbolic Tangent")]
468pub fn atanh(
469    /// The number whose inverse hyperbolic tangent to calculate. Must be
470    /// between $-1$ and $1$ (exclusive).
471    value: Spanned<f64>,
472) -> SourceResult<f64> {
473    let val = value.v;
474    if val <= -1.0 || val >= 1.0 {
475        bail!(value.span, "value must be between -1 and 1 (exclusive)");
476    }
477    Ok(libm::atanh(val))
478}
479
480/// Calculates the logarithm of a number.
481///
482/// If the base is not specified, the logarithm is calculated in base ten.
483///
484/// ```example
485/// #calc.log(100)
486/// ```
487#[func(title = "Logarithm")]
488pub fn log(
489    span: Span,
490    /// The number whose logarithm to calculate. Must be strictly positive.
491    value: Spanned<Num>,
492    /// The base of the logarithm. May not be zero.
493    #[named]
494    #[default(Spanned::detached(10.0))]
495    base: Spanned<f64>,
496) -> SourceResult<f64> {
497    let number = value.v.float();
498    if number <= 0.0 {
499        bail!(value.span, "value must be strictly positive")
500    }
501
502    if !base.v.is_normal() {
503        bail!(base.span, "base may not be zero, NaN, infinite, or subnormal")
504    }
505
506    let result = if base.v == std::f64::consts::E {
507        libm::log(number)
508    } else if base.v == 2.0 {
509        libm::log2(number)
510    } else if base.v == 10.0 {
511        libm::log10(number)
512    } else {
513        libm::log(number) / libm::log(base.v)
514    };
515
516    if result.is_infinite() || result.is_nan() {
517        bail!(span, "the result is not a real number")
518    }
519
520    Ok(result)
521}
522
523/// Calculates the natural logarithm of a number.
524///
525/// ```example
526/// #calc.ln(calc.e)
527/// ```
528#[func(title = "Natural Logarithm")]
529pub fn ln(
530    span: Span,
531    /// The number whose logarithm to calculate. Must be strictly positive.
532    value: Spanned<Num>,
533) -> SourceResult<f64> {
534    let number = value.v.float();
535    if number <= 0.0 {
536        bail!(value.span, "value must be strictly positive")
537    }
538
539    let result = libm::log(number);
540    if result.is_infinite() {
541        bail!(span, "result close to -inf")
542    }
543
544    Ok(result)
545}
546
547/// Applies the error function to a number.
548///
549/// The value of the error function at $x$ is defined as follows:
550/// $ 2 / sqrt(pi) integral_0^x e^(-t^2) dif t $
551///
552/// ```example
553/// #calc.erf(0.2)
554/// ```
555#[func(title = "Error Function")]
556pub fn erf(
557    /// The number at which to calculate the error function.
558    value: f64,
559) -> f64 {
560    libm::erf(value)
561}
562
563/// Calculates the factorial of a number.
564///
565/// ```example
566/// #calc.fact(5)
567/// ```
568#[func(title = "Factorial")]
569pub fn fact(
570    /// The number whose factorial to calculate. Must be non-negative.
571    number: u64,
572) -> StrResult<i64> {
573    Ok(fact_impl(1, number).ok_or_else(too_large)?)
574}
575
576/// Calculates a permutation.
577///
578/// Returns the $k$-permutation of $n$, or the number of ways to choose $k$
579/// items from a set of $n$ with regard to order, defined as follows:
580/// $
581///   cases(
582///     0 quad &"if" k > n,
583///     (n!) / ((n - k)!) quad &"if" k <= n,
584///   )
585/// $
586///
587/// ```example
588/// #calc.perm(5, 3)
589/// ```
590#[func(title = "Permutation")]
591pub fn perm(
592    /// The value of $n$: The number of items to choose from. Must be
593    /// non-negative.
594    base: u64,
595    /// The value of $k$: The number of items to choose. Must be non-negative.
596    numbers: u64,
597) -> StrResult<i64> {
598    // By convention.
599    if base < numbers {
600        return Ok(0);
601    }
602
603    Ok(fact_impl(base - numbers + 1, base).ok_or_else(too_large)?)
604}
605
606/// Calculates the product of a range of numbers. Used to calculate
607/// permutations. Returns None if the result is larger than `i64::MAX`
608fn fact_impl(start: u64, end: u64) -> Option<i64> {
609    // By convention
610    if end + 1 < start {
611        return Some(0);
612    }
613
614    let real_start: u64 = cmp::max(1, start);
615    let mut count: u64 = 1;
616    for i in real_start..=end {
617        count = count.checked_mul(i)?;
618    }
619
620    count.try_into().ok()
621}
622
623/// Calculates a binomial coefficient.
624///
625/// Returns the $k$-combination of $n$, or the number of ways to choose $k$
626/// items from a set of $n$ without regard to order, defined as follows:
627/// $
628///   cases(
629///     (n!) / (k! (n - k)!) quad &"if" 0 <= k <= n,
630///     0 quad &"otherwise",
631///   )
632/// $
633///
634/// ```example
635/// #calc.binom(10, 5)
636/// ```
637#[func(title = "Binomial")]
638pub fn binom(
639    /// The value of $n$: The numbers of items to choose from. Must be
640    /// non-negative.
641    n: u64,
642    /// The value of $k$: The number of items to choose. Must be non-negative.
643    k: u64,
644) -> StrResult<i64> {
645    Ok(binom_impl(n, k).ok_or_else(too_large)?)
646}
647
648/// Calculates a binomial coefficient, with `n` the upper coefficient and `k`
649/// the lower coefficient. Returns `None` if the result is larger than
650/// `i64::MAX`
651fn binom_impl(n: u64, k: u64) -> Option<i64> {
652    if k > n {
653        return Some(0);
654    }
655
656    // By symmetry
657    let real_k = cmp::min(n - k, k);
658    if real_k == 0 {
659        return Some(1);
660    }
661
662    let mut result: u64 = 1;
663    for i in 0..real_k {
664        result = result.checked_mul(n - i)?.checked_div(i + 1)?;
665    }
666
667    result.try_into().ok()
668}
669
670/// Calculates the greatest common divisor of two integers.
671///
672/// This will error if the result of integer division would be larger than the
673/// maximum 64-bit signed integer.
674///
675/// ```example
676/// #calc.gcd(7, 42)
677/// ```
678#[func(title = "Greatest Common Divisor")]
679pub fn gcd(
680    /// The first integer.
681    a: i64,
682    /// The second integer.
683    b: i64,
684) -> StrResult<i64> {
685    let (mut a, mut b) = (a, b);
686    while b != 0 {
687        let temp = b;
688        b = a.checked_rem(b).ok_or_else(too_large)?;
689        a = temp;
690    }
691
692    Ok(a.checked_abs().ok_or_else(too_large)?)
693}
694
695/// Calculates the least common multiple of two integers.
696///
697/// ```example
698/// #calc.lcm(96, 13)
699/// ```
700#[func(title = "Least Common Multiple")]
701pub fn lcm(
702    /// The first integer.
703    a: i64,
704    /// The second integer.
705    b: i64,
706) -> StrResult<i64> {
707    if a == b {
708        return Ok(a.checked_abs().ok_or_else(too_large)?);
709    }
710
711    Ok(a.checked_div(gcd(a, b)?)
712        .and_then(|gcd| gcd.checked_mul(b))
713        .and_then(|v| v.checked_abs())
714        .ok_or_else(too_large)?)
715}
716
717/// Rounds a number down to the nearest integer.
718///
719/// If the number is already an integer, it is returned unchanged.
720///
721/// Note that this function will always return an @int[integer], and will error
722/// if the resulting @float or @decimal is larger than the maximum 64-bit signed
723/// integer or smaller than the minimum for that type.
724///
725/// ```example
726/// #calc.floor(500.1)
727/// #assert(calc.floor(3) == 3)
728/// #assert(calc.floor(3.14) == 3)
729/// #assert(calc.floor(decimal("-3.14")) == -4)
730/// ```
731#[func]
732pub fn floor(
733    /// The number to round down.
734    value: DecNum,
735) -> StrResult<i64> {
736    match value {
737        DecNum::Int(n) => Ok(n),
738        DecNum::Float(n) => Ok(crate::foundations::convert_float_to_int(n.floor())
739            .map_err(|_| too_large())?),
740        DecNum::Decimal(n) => Ok(i64::try_from(n.floor()).map_err(|_| too_large())?),
741    }
742}
743
744/// Rounds a number up to the nearest integer.
745///
746/// If the number is already an integer, it is returned unchanged.
747///
748/// Note that this function will always return an @int[integer], and will error
749/// if the resulting @float or @decimal is larger than the maximum 64-bit signed
750/// integer or smaller than the minimum for that type.
751///
752/// ```example
753/// #calc.ceil(500.1)
754/// #assert(calc.ceil(3) == 3)
755/// #assert(calc.ceil(3.14) == 4)
756/// #assert(calc.ceil(decimal("-3.14")) == -3)
757/// ```
758#[func]
759pub fn ceil(
760    /// The number to round up.
761    value: DecNum,
762) -> StrResult<i64> {
763    match value {
764        DecNum::Int(n) => Ok(n),
765        DecNum::Float(n) => Ok(crate::foundations::convert_float_to_int(n.ceil())
766            .map_err(|_| too_large())?),
767        DecNum::Decimal(n) => Ok(i64::try_from(n.ceil()).map_err(|_| too_large())?),
768    }
769}
770
771/// Returns the integer part of a number.
772///
773/// If the number is already an integer, it is returned unchanged.
774///
775/// Note that this function will always return an @int[integer], and will error
776/// if the resulting @float or @decimal is larger than the maximum 64-bit signed
777/// integer or smaller than the minimum for that type.
778///
779/// ```example
780/// #calc.trunc(15.9)
781/// #assert(calc.trunc(3) == 3)
782/// #assert(calc.trunc(-3.7) == -3)
783/// #assert(calc.trunc(decimal("8493.12949582390")) == 8493)
784/// ```
785#[func(title = "Truncate")]
786pub fn trunc(
787    /// The number to truncate.
788    value: DecNum,
789) -> StrResult<i64> {
790    match value {
791        DecNum::Int(n) => Ok(n),
792        DecNum::Float(n) => Ok(crate::foundations::convert_float_to_int(n.trunc())
793            .map_err(|_| too_large())?),
794        DecNum::Decimal(n) => Ok(i64::try_from(n.trunc()).map_err(|_| too_large())?),
795    }
796}
797
798/// Returns the fractional part of a number.
799///
800/// If the number is an integer, returns `0`.
801///
802/// ```example
803/// #calc.fract(-3.1)
804/// #assert(calc.fract(3) == 0)
805/// #assert(calc.fract(decimal("234.23949211")) == decimal("0.23949211"))
806/// ```
807#[func(title = "Fractional")]
808pub fn fract(
809    /// The number to truncate.
810    value: DecNum,
811) -> DecNum {
812    match value {
813        DecNum::Int(_) => DecNum::Int(0),
814        DecNum::Float(n) => DecNum::Float(n.fract()),
815        DecNum::Decimal(n) => DecNum::Decimal(n.fract()),
816    }
817}
818
819/// Rounds a number to the nearest integer.
820///
821/// Half-integers are rounded away from zero.
822///
823/// Optionally, a number of decimal places can be specified. If negative, its
824/// absolute value will indicate the amount of significant integer digits to
825/// remove before the decimal point.
826///
827/// Note that this function will return the same type as the operand. That is,
828/// applying `round` to a @float will return a `float`, and to a @decimal,
829/// another `decimal`. You may explicitly convert the output of this function to
830/// an integer with @int, but note that such a conversion will error if the
831/// `float` or `decimal` is larger than the maximum 64-bit signed integer or
832/// smaller than the minimum integer.
833///
834/// In addition, this function can error if there is an attempt to round beyond
835/// the maximum or minimum integer or `decimal`. If the number is a `float`,
836/// such an attempt will cause `{float.inf}` or `{-float.inf}` to be returned
837/// for maximum and minimum respectively.
838///
839/// ```example
840/// #calc.round(3.1415, digits: 2)
841/// #assert(calc.round(3) == 3)
842/// #assert(calc.round(3.14) == 3)
843/// #assert(calc.round(3.5) == 4.0)
844/// #assert(calc.round(3333.45, digits: -2) == 3300.0)
845/// #assert(calc.round(-48953.45, digits: -3) == -49000.0)
846/// #assert(calc.round(3333, digits: -2) == 3300)
847/// #assert(calc.round(-48953, digits: -3) == -49000)
848/// #assert(calc.round(decimal("-6.5")) == decimal("-7"))
849/// #assert(calc.round(decimal("7.123456789"), digits: 6) == decimal("7.123457"))
850/// #assert(calc.round(decimal("3333.45"), digits: -2) == decimal("3300"))
851/// #assert(calc.round(decimal("-48953.45"), digits: -3) == decimal("-49000"))
852/// ```
853#[func]
854pub fn round(
855    /// The number to round.
856    value: DecNum,
857    /// If positive, the number of decimal places.
858    ///
859    /// If negative, the number of significant integer digits that should be
860    /// removed before the decimal point.
861    #[named]
862    #[default(0)]
863    digits: i64,
864) -> StrResult<DecNum> {
865    match value {
866        DecNum::Int(n) => Ok(DecNum::Int(
867            round_int_with_precision(n, digits.saturating_as::<i16>())
868                .ok_or_else(too_large)?,
869        )),
870        DecNum::Float(n) => {
871            Ok(DecNum::Float(round_with_precision(n, digits.saturating_as::<i16>())))
872        }
873        DecNum::Decimal(n) => Ok(DecNum::Decimal(
874            n.round(digits.saturating_as::<i32>()).ok_or_else(too_large)?,
875        )),
876    }
877}
878
879/// Clamps a number between a minimum and maximum value.
880///
881/// ```example
882/// #calc.clamp(5, 0, 4)
883/// #assert(calc.clamp(5, 0, 10) == 5)
884/// #assert(calc.clamp(5, 6, 10) == 6)
885/// #assert(calc.clamp(decimal("5.45"), 2, decimal("45.9")) == decimal("5.45"))
886/// #assert(calc.clamp(decimal("5.45"), decimal("6.75"), 12) == decimal("6.75"))
887/// ```
888#[func]
889pub fn clamp(
890    span: Span,
891    /// The number to clamp.
892    value: DecNum,
893    /// The inclusive minimum value.
894    min: DecNum,
895    /// The inclusive maximum value.
896    max: Spanned<DecNum>,
897) -> SourceResult<DecNum> {
898    // Ignore if there are incompatible types (decimal and float) since that
899    // will cause `apply3` below to error before calling clamp, avoiding a
900    // panic.
901    if min
902        .apply2(max.v, |min, max| max < min, |min, max| max < min, |min, max| max < min)
903        .unwrap_or(false)
904    {
905        bail!(max.span, "max must be greater than or equal to min")
906    }
907
908    value
909        .apply3(min, max.v, i64::clamp, f64::clamp, Decimal::clamp)
910        .ok_or_else(cant_apply_to_decimal_and_float)
911        .at(span)
912}
913
914/// Determines the minimum of a sequence of values.
915///
916/// ```example
917/// #calc.min(1, -3, -5, 20, 3, 6) \
918/// #calc.min("typst", "is", "cool")
919/// ```
920#[func(title = "Minimum")]
921pub fn min(
922    span: Span,
923    /// The sequence of values from which to extract the minimum. Must not be
924    /// empty.
925    #[variadic]
926    values: Vec<Spanned<Value>>,
927) -> SourceResult<Value> {
928    minmax(span, values, Ordering::Less)
929}
930
931/// Determines the maximum of a sequence of values.
932///
933/// ```example
934/// #calc.max(1, -3, -5, 20, 3, 6) \
935/// #calc.max("typst", "is", "cool")
936/// ```
937#[func(title = "Maximum")]
938pub fn max(
939    span: Span,
940    /// The sequence of values from which to extract the maximum. Must not be
941    /// empty.
942    #[variadic]
943    values: Vec<Spanned<Value>>,
944) -> SourceResult<Value> {
945    minmax(span, values, Ordering::Greater)
946}
947
948/// Find the minimum or maximum of a sequence of values.
949fn minmax(
950    span: Span,
951    values: Vec<Spanned<Value>>,
952    goal: Ordering,
953) -> SourceResult<Value> {
954    let mut iter = values.into_iter();
955    let Some(Spanned { v: mut extremum, .. }) = iter.next() else {
956        bail!(span, "expected at least one value");
957    };
958
959    for Spanned { v, span } in iter {
960        let ordering = ops::compare(&v, &extremum).at(span)?;
961        if ordering == goal {
962            extremum = v;
963        }
964    }
965
966    Ok(extremum)
967}
968
969/// Determines whether an integer is even.
970///
971/// ```example
972/// #calc.even(4) \
973/// #calc.even(5) \
974/// #range(10).filter(calc.even)
975/// ```
976#[func]
977pub fn even(
978    /// The number to check for evenness.
979    value: i64,
980) -> bool {
981    value % 2 == 0
982}
983
984/// Determines whether an integer is odd.
985///
986/// ```example
987/// #calc.odd(4) \
988/// #calc.odd(5) \
989/// #range(10).filter(calc.odd)
990/// ```
991#[func]
992pub fn odd(
993    /// The number to check for oddness.
994    value: i64,
995) -> bool {
996    value % 2 != 0
997}
998
999/// Calculates the remainder of two numbers.
1000///
1001/// The value `calc.rem(x, y)` always has the same sign as `x`, and is smaller
1002/// in magnitude than `y`.
1003///
1004/// This can error if given a @decimal input and the dividend is too small in
1005/// magnitude compared to the divisor.
1006///
1007/// ```example
1008/// #calc.rem(7, 3) \
1009/// #calc.rem(7, -3) \
1010/// #calc.rem(-7, 3) \
1011/// #calc.rem(-7, -3) \
1012/// #calc.rem(1.75, 0.5)
1013/// ```
1014#[func(title = "Remainder")]
1015pub fn rem(
1016    span: Span,
1017    /// The dividend of the remainder.
1018    dividend: DecNum,
1019    /// The divisor of the remainder.
1020    divisor: Spanned<DecNum>,
1021) -> SourceResult<DecNum> {
1022    if divisor.v.is_zero() {
1023        bail!(divisor.span, "divisor must not be zero");
1024    }
1025
1026    dividend
1027        .apply2(
1028            divisor.v,
1029            // `checked_rem` can only overflow on `i64::MIN % -1` which is
1030            // mathematically zero.
1031            |a, b| Some(DecNum::Int(a.checked_rem(b).unwrap_or(0))),
1032            |a, b| Some(DecNum::Float(a % b)),
1033            |a, b| a.checked_rem(b).map(DecNum::Decimal),
1034        )
1035        .ok_or_else(cant_apply_to_decimal_and_float)
1036        .at(span)?
1037        .ok_or("dividend too small compared to divisor")
1038        .at(span)
1039}
1040
1041/// Performs euclidean division of two numbers.
1042///
1043/// The result of this computation is that of a division rounded to the integer
1044/// `{n}` such that the dividend is greater than or equal to `{n}` times the
1045/// divisor.
1046///
1047/// This can error if the resulting number is larger than the maximum value or
1048/// smaller than the minimum value for its type.
1049///
1050/// ```example
1051/// #calc.div-euclid(7, 3) \
1052/// #calc.div-euclid(7, -3) \
1053/// #calc.div-euclid(-7, 3) \
1054/// #calc.div-euclid(-7, -3) \
1055/// #calc.div-euclid(1.75, 0.5) \
1056/// #calc.div-euclid(decimal("1.75"), decimal("0.5"))
1057/// ```
1058#[func(title = "Euclidean Division")]
1059pub fn div_euclid(
1060    span: Span,
1061    /// The dividend of the division.
1062    dividend: DecNum,
1063    /// The divisor of the division.
1064    divisor: Spanned<DecNum>,
1065) -> SourceResult<DecNum> {
1066    if divisor.v.is_zero() {
1067        bail!(divisor.span, "divisor must not be zero");
1068    }
1069
1070    dividend
1071        .apply2(
1072            divisor.v,
1073            |a, b| a.checked_div_euclid(b).map(DecNum::Int),
1074            |a, b| Some(DecNum::Float(a.div_euclid(b))),
1075            |a, b| a.checked_div_euclid(b).map(DecNum::Decimal),
1076        )
1077        .ok_or_else(cant_apply_to_decimal_and_float)
1078        .at(span)?
1079        .ok_or_else(too_large)
1080        .at(span)
1081}
1082
1083/// This calculates the least nonnegative remainder of a division.
1084///
1085/// Warning: Due to a floating point round-off error, the remainder may equal
1086/// the absolute value of the divisor if the dividend is much smaller in
1087/// magnitude than the divisor and the dividend is negative. This only applies
1088/// for floating point inputs.
1089///
1090/// In addition, this can error if given a @decimal input and the dividend is
1091/// too small in magnitude compared to the divisor.
1092///
1093/// ```example
1094/// #calc.rem-euclid(7, 3) \
1095/// #calc.rem-euclid(7, -3) \
1096/// #calc.rem-euclid(-7, 3) \
1097/// #calc.rem-euclid(-7, -3) \
1098/// #calc.rem-euclid(1.75, 0.5) \
1099/// #calc.rem-euclid(decimal("1.75"), decimal("0.5"))
1100/// ```
1101#[func(title = "Euclidean Remainder", keywords = ["modulo", "modulus"])]
1102pub fn rem_euclid(
1103    span: Span,
1104    /// The dividend of the remainder.
1105    dividend: DecNum,
1106    /// The divisor of the remainder.
1107    divisor: Spanned<DecNum>,
1108) -> SourceResult<DecNum> {
1109    if divisor.v.is_zero() {
1110        bail!(divisor.span, "divisor must not be zero");
1111    }
1112
1113    dividend
1114        .apply2(
1115            divisor.v,
1116            // `checked_rem_euclid` can only overflow on `i64::MIN % -1` which
1117            // is mathematically zero.
1118            |a, b| Some(DecNum::Int(a.checked_rem_euclid(b).unwrap_or(0))),
1119            |a, b| Some(DecNum::Float(a.rem_euclid(b))),
1120            |a, b| a.checked_rem_euclid(b).map(DecNum::Decimal),
1121        )
1122        .ok_or_else(cant_apply_to_decimal_and_float)
1123        .at(span)?
1124        .ok_or("dividend too small compared to divisor")
1125        .at(span)
1126}
1127
1128/// Calculates the quotient (floored division) of two numbers.
1129///
1130/// Note that this function will always return an @int[integer], and will error
1131/// if the resulting number is larger than the maximum 64-bit signed integer or
1132/// smaller than the minimum for that type.
1133///
1134/// ```example
1135/// $ "quo"(a, b) &= floor(a/b) \
1136///   "quo"(14, 5) &= #calc.quo(14, 5) \
1137///   "quo"(3.46, 0.5) &= #calc.quo(3.46, 0.5) $
1138/// ```
1139#[func(title = "Quotient")]
1140pub fn quo(
1141    span: Span,
1142    /// The dividend of the quotient.
1143    dividend: DecNum,
1144    /// The divisor of the quotient.
1145    divisor: Spanned<DecNum>,
1146) -> SourceResult<i64> {
1147    if divisor.v.is_zero() {
1148        bail!(divisor.span, "divisor must not be zero");
1149    }
1150
1151    let divided = dividend
1152        .apply2(
1153            divisor.v,
1154            |a, b| {
1155                let q = a.checked_div(b)?;
1156                // Round towards negative infinity if the fraction is negative.
1157                Some(DecNum::Int(if (a < 0) != (b < 0) && a % b != 0 {
1158                    q - 1
1159                } else {
1160                    q
1161                }))
1162            },
1163            |a, b| Some(DecNum::Float(a / b)),
1164            |a, b| a.checked_div(b).map(DecNum::Decimal),
1165        )
1166        .ok_or_else(cant_apply_to_decimal_and_float)
1167        .at(span)?
1168        .ok_or_else(too_large)
1169        .at(span)?;
1170
1171    floor(divided).at(span)
1172}
1173
1174/// Calculates the $p$-norm of a sequence of values.
1175///
1176/// The $p$-norm of $x_1, ..., x_n$ is defined as follows:
1177/// $
1178///   cases(
1179///     (sum_(i=1)^n abs(x_i)^p)^frac(style: "horizontal", 1, p)
1180///       quad &"if" 0 < p < +oo,
1181///     max_(i=1)^n abs(x_i) quad &"if" p = +oo,
1182///   )
1183/// $
1184///
1185/// ```example
1186/// #calc.norm(1, 2, -3, 0.5) \
1187/// #calc.norm(p: 3, 1, 2)
1188/// ```
1189#[func(title = "𝑝-Norm")]
1190pub fn norm(
1191    /// The value of $p$. Must be greater than zero.
1192    ///
1193    /// The default value of `{2.0}` corresponds to the Euclidean norm:
1194    /// $ sqrt(sum_(i=1)^n x_i^2) $
1195    #[named]
1196    #[default(Spanned::detached(2.0))]
1197    p: Spanned<f64>,
1198    /// The sequence of values to calculate the $p$-norm of. Returns `{0.0}`
1199    /// if empty.
1200    #[variadic]
1201    values: Vec<f64>,
1202) -> SourceResult<f64> {
1203    if p.v <= 0.0 {
1204        bail!(p.span, "p must be greater than zero");
1205    }
1206
1207    let abs = values.iter().map(|v| f64::abs(*v));
1208    let max = abs.clone().max_by(|a, b| a.total_cmp(b)).unwrap_or(0.0);
1209
1210    Ok(if p.v.is_infinite() {
1211        // When p is infinity, the p-norm is the maximum of the absolute values.
1212        max
1213    } else if max == 0.0 {
1214        // When the maximum absolute value is 0, the norm is just 0.
1215        // This is a special case to avoid division by zero in the trick below.
1216        0.0
1217    } else {
1218        // Compute `max * (sum_i (x_i / max)^p)^(1 / p)` instead of raising
1219        // `x_i^p` directly, to avoid overflowing. This is described further in
1220        // <https://timvieira.github.io/blog/numerically-stable-p-norms/>.
1221        max * libm::pow(abs.map(|v| libm::pow(v / max, p.v)).sum::<f64>(), 1.0 / p.v)
1222    })
1223}
1224
1225/// A value which can be passed to functions that work with integers and floats.
1226#[derive(Debug, Copy, Clone)]
1227pub enum Num {
1228    Int(i64),
1229    Float(f64),
1230}
1231
1232impl Num {
1233    fn float(self) -> f64 {
1234        match self {
1235            Self::Int(v) => v as f64,
1236            Self::Float(v) => v,
1237        }
1238    }
1239}
1240
1241cast! {
1242    Num,
1243    self => match self {
1244        Self::Int(v) => v.into_value(),
1245        Self::Float(v) => v.into_value(),
1246    },
1247    v: i64 => Self::Int(v),
1248    v: f64 => Self::Float(v),
1249}
1250
1251/// A value which can be passed to functions that work with integers, floats,
1252/// and decimals.
1253#[derive(Debug, Copy, Clone)]
1254pub enum DecNum {
1255    Int(i64),
1256    Float(f64),
1257    Decimal(Decimal),
1258}
1259
1260impl DecNum {
1261    /// Checks if this number is equivalent to zero.
1262    fn is_zero(self) -> bool {
1263        match self {
1264            Self::Int(i) => i == 0,
1265            Self::Float(f) => f == 0.0,
1266            Self::Decimal(d) => d.is_zero(),
1267        }
1268    }
1269
1270    /// If this `DecNum` holds an integer or float, returns a float.
1271    /// Otherwise, returns `None`.
1272    fn float(self) -> Option<f64> {
1273        match self {
1274            Self::Int(i) => Some(i as f64),
1275            Self::Float(f) => Some(f),
1276            Self::Decimal(_) => None,
1277        }
1278    }
1279
1280    /// If this `DecNum` holds an integer or decimal, returns a decimal.
1281    /// Otherwise, returns `None`.
1282    fn decimal(self) -> Option<Decimal> {
1283        match self {
1284            Self::Int(i) => Some(Decimal::from(i)),
1285            Self::Float(_) => None,
1286            Self::Decimal(d) => Some(d),
1287        }
1288    }
1289
1290    /// Tries to apply a function to two decimal or numeric arguments.
1291    ///
1292    /// Fails with `None` if one is a float and the other is a decimal.
1293    fn apply2<T>(
1294        self,
1295        other: Self,
1296        int: impl FnOnce(i64, i64) -> T,
1297        float: impl FnOnce(f64, f64) -> T,
1298        decimal: impl FnOnce(Decimal, Decimal) -> T,
1299    ) -> Option<T> {
1300        match (self, other) {
1301            (Self::Int(a), Self::Int(b)) => Some(int(a, b)),
1302            (Self::Decimal(a), Self::Decimal(b)) => Some(decimal(a, b)),
1303            (Self::Decimal(a), Self::Int(b)) => Some(decimal(a, Decimal::from(b))),
1304            (Self::Int(a), Self::Decimal(b)) => Some(decimal(Decimal::from(a), b)),
1305            (a, b) => Some(float(a.float()?, b.float()?)),
1306        }
1307    }
1308
1309    /// Tries to apply a function to three decimal or numeric arguments.
1310    ///
1311    /// Fails with `None` if one is a float and the other is a decimal.
1312    fn apply3(
1313        self,
1314        other: Self,
1315        third: Self,
1316        int: impl FnOnce(i64, i64, i64) -> i64,
1317        float: impl FnOnce(f64, f64, f64) -> f64,
1318        decimal: impl FnOnce(Decimal, Decimal, Decimal) -> Decimal,
1319    ) -> Option<Self> {
1320        match (self, other, third) {
1321            (Self::Int(a), Self::Int(b), Self::Int(c)) => Some(Self::Int(int(a, b, c))),
1322            (Self::Decimal(a), b, c) => {
1323                Some(Self::Decimal(decimal(a, b.decimal()?, c.decimal()?)))
1324            }
1325            (a, Self::Decimal(b), c) => {
1326                Some(Self::Decimal(decimal(a.decimal()?, b, c.decimal()?)))
1327            }
1328            (a, b, Self::Decimal(c)) => {
1329                Some(Self::Decimal(decimal(a.decimal()?, b.decimal()?, c)))
1330            }
1331            (a, b, c) => Some(Self::Float(float(a.float()?, b.float()?, c.float()?))),
1332        }
1333    }
1334}
1335
1336cast! {
1337    DecNum,
1338    self => match self {
1339        Self::Int(v) => v.into_value(),
1340        Self::Float(v) => v.into_value(),
1341        Self::Decimal(v) => v.into_value(),
1342    },
1343    v: i64 => Self::Int(v),
1344    v: f64 => Self::Float(v),
1345    v: Decimal => Self::Decimal(v),
1346}
1347
1348/// A value that can be passed to a trigonometric function.
1349pub enum AngleLike {
1350    Int(i64),
1351    Float(f64),
1352    Angle(Angle),
1353}
1354
1355cast! {
1356    AngleLike,
1357    v: i64 => Self::Int(v),
1358    v: f64 => Self::Float(v),
1359    v: Angle => Self::Angle(v),
1360}
1361
1362/// The error message when the result is too large to be represented.
1363#[cold]
1364fn too_large() -> &'static str {
1365    "the result is too large"
1366}
1367
1368/// The hinted error message when trying to apply an operation to decimal and
1369/// float operands.
1370#[cold]
1371fn cant_apply_to_decimal_and_float() -> HintedString {
1372    HintedString::new("cannot apply this operation to a decimal and a float".into())
1373        .with_hint(
1374            "if loss of precision is acceptable, explicitly cast the \
1375             decimal to a float with `float(value)`",
1376        )
1377}