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}