Repository: typst/typst
File: crates/typst-library/src/foundations/calc.rs (Rust)

Code before:
    dividend: DecNum,
    /// The divisor of the quotient.
    divisor: Spanned<DecNum>,
) -> SourceResult<i64> {
    if divisor.v.is_zero() {
        bail!(divisor.span, "divisor must not be zero");
    }

    let divided = dividend
        .apply2(
            divisor.v,
            |a, b| {
                let q = a.checked_div(b)?;
                // Round towards negative infinity if the fraction is negative.
                Some(DecNum::Int(if (a < 0) != (b < 0) && a % b != 0 {
                    q - 1
                } else {
                    q
                }))
            },
            |a, b| Some(DecNum::Float(a / b)),
            |a, b| a.checked_div(b).map(DecNum::Decimal),
        )
        .ok_or_else(cant_apply_to_decimal_and_float)
        .at(span)?
        .ok_or_else(too_large)
        .at(span)?;

    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");
    }

Review comment (suggestion):
Maybe this is a bit better?

```suggestion
                Some(DecNum::Int(if q < 0 && a % b != 0 {
```

By the way, this is the official implementation in the currently nightly-only Rust `std` function for this[^1]:

```rs
pub const fn div_floor(self, rhs: Self) -> Self {
    let d = self / rhs;
    let r = self % rhs;

    // If the remainder is non-zero, we need to subtract one if the
    // signs of self and rhs differ, as this means we rounded upwards
    // instead of downwards. We do this branchlessly by creating a mask
    // which is all-ones iff the signs differ, and 0 otherwise. Then by
    // adding this mask (which corresponds to the signed value -1), we
    // get our correction.
    let correction = (self ^ rhs) >> (Self::BITS - 1);
    if r != 0 {
        d + correction
    } else {
        d
    }
}
```

[^1]: https://doc.rust-lang.org/nightly/std/primitive.i64.html#method.div_floor

Code after:
/// integer or smaller than the minimum for that type.
///
/// ```example
/// $ "quo"(a, b) &= floor(a/b) \
///   "quo"(14, 5) &= #calc.quo(14, 5) \
///   "quo"(3.46, 0.5) &= #calc.quo(3.46, 0.5) $
/// ```
#[func(title = "Quotient")]
pub fn quo(
    span: Span,
    /// The dividend of the quotient.
    dividend: DecNum,
    /// The divisor of the quotient.
    divisor: Spanned<DecNum>,
) -> SourceResult<i64> {
    if divisor.v.is_zero() {
        bail!(divisor.span, "divisor must not be zero");
    }

    let divided = dividend
        .apply2(
            divisor.v,
            |a, b| {
                let q = a.checked_div(b)?;
                // Round towards negative infinity if the fraction is negative.
                Some(DecNum::Int(if (a < 0) != (b < 0) && a % b != 0 {
                    q - 1
                } else {
                    q
                }))
            },
            |a, b| Some(DecNum::Float(a / b)),
            |a, b| a.checked_div(b).map(DecNum::Decimal),
        )
        .ok_or_else(cant_apply_to_decimal_and_float)
        .at(span)?
        .ok_or_else(too_large)
        .at(span)?;

    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.