mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Add calc.norm()
function to compute euclidean norms (#4581)
Co-authored-by: +merlan #flirora <uruwi@protonmail.com> Co-authored-by: Yip Coekjan <69834864+Coekjan@users.noreply.github.com> Co-authored-by: Malo <57839069+MDLC01@users.noreply.github.com> Co-authored-by: Laurenz <laurmaedje@gmail.com>
This commit is contained in:
parent
30427ac842
commit
066e9349f9
@ -50,6 +50,7 @@ pub fn module() -> Module {
|
||||
scope.define_func::<div_euclid>();
|
||||
scope.define_func::<rem_euclid>();
|
||||
scope.define_func::<quo>();
|
||||
scope.define_func::<norm>();
|
||||
scope.define("inf", f64::INFINITY);
|
||||
scope.define("pi", std::f64::consts::PI);
|
||||
scope.define("tau", std::f64::consts::TAU);
|
||||
@ -1056,6 +1057,38 @@ pub fn quo(
|
||||
floor(divided).at(span)
|
||||
}
|
||||
|
||||
/// Calculates the p-norm of a sequence of values.
|
||||
///
|
||||
/// ```example
|
||||
/// #calc.norm(1, 2, -3, 0.5) \
|
||||
/// #calc.norm(p: 3, 1, 2)
|
||||
/// ```
|
||||
#[func(title = "𝑝-Norm")]
|
||||
pub fn norm(
|
||||
/// The p value to calculate the p-norm of.
|
||||
#[named]
|
||||
#[default(Spanned::new(2.0, Span::detached()))]
|
||||
p: Spanned<f64>,
|
||||
/// The sequence of values from which to calculate the p-norm.
|
||||
/// Returns `0.0` if empty.
|
||||
#[variadic]
|
||||
values: Vec<f64>,
|
||||
) -> SourceResult<f64> {
|
||||
if p.v <= 0.0 {
|
||||
bail!(p.span, "p must be greater than zero");
|
||||
}
|
||||
|
||||
// Create an iterator over the absolute values.
|
||||
let abs = values.into_iter().map(f64::abs);
|
||||
|
||||
Ok(if p.v.is_infinite() {
|
||||
// When p is infinity, the p-norm is the maximum of the absolute values.
|
||||
abs.max_by(|a, b| a.total_cmp(b)).unwrap_or(0.0)
|
||||
} else {
|
||||
abs.map(|v| v.powf(p.v)).sum::<f64>().powf(1.0 / p.v)
|
||||
})
|
||||
}
|
||||
|
||||
/// A value which can be passed to functions that work with integers and floats.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Num {
|
||||
|
@ -368,3 +368,19 @@
|
||||
// Error: 2-37 cannot apply this operation to a decimal and a float
|
||||
// Hint: 2-37 if loss of precision is acceptable, explicitly cast the decimal to a float with `float(value)`
|
||||
#calc.clamp(decimal("10"), 5.5, 6.6)
|
||||
|
||||
--- calc-norm ---
|
||||
#test(calc.norm(1, 2, -3, 0.5), calc.sqrt(14.25))
|
||||
#test(calc.norm(3, 4), 5.0)
|
||||
#test(calc.norm(3, 4), 5.0)
|
||||
#test(calc.norm(), 0.0)
|
||||
#test(calc.norm(p: 3, 1, -2), calc.pow(9, 1/3))
|
||||
#test(calc.norm(p: calc.inf, 1, -2), 2.0)
|
||||
|
||||
--- calc-norm-negative-p ---
|
||||
// Error: 15-17 p must be greater than zero
|
||||
#calc.norm(p: -1, 1)
|
||||
|
||||
--- calc-norm-expected-float ---
|
||||
// Error: 12-15 expected float, found ratio
|
||||
#calc.norm(10%)
|
||||
|
Loading…
x
Reference in New Issue
Block a user