mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Add gcd
and lcm
calculation methods (#789)
This commit is contained in:
parent
dc3017955a
commit
1e934def56
@ -27,6 +27,8 @@ pub fn module() -> Module {
|
||||
scope.define("fact", fact);
|
||||
scope.define("perm", perm);
|
||||
scope.define("binom", binom);
|
||||
scope.define("gcd", gcd);
|
||||
scope.define("lcm", lcm);
|
||||
scope.define("floor", floor);
|
||||
scope.define("ceil", ceil);
|
||||
scope.define("round", round);
|
||||
@ -522,6 +524,72 @@ fn binomial(n: u64, k: u64) -> Option<i64> {
|
||||
i64::try_from(result).ok()
|
||||
}
|
||||
|
||||
/// Calculate the greatest common divisor of two integers.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```example
|
||||
/// #calc.gcd(7, 42)
|
||||
/// ```
|
||||
///
|
||||
/// Display: Greatest Common Divisor
|
||||
/// Category: calculate
|
||||
/// Returns: integer
|
||||
#[func]
|
||||
pub fn gcd(
|
||||
/// The first integer.
|
||||
a: i64,
|
||||
/// The second integer.
|
||||
b: i64,
|
||||
) -> Value {
|
||||
Value::Int(calculate_gcd(a, b).into())
|
||||
}
|
||||
|
||||
/// Calculates the greatest common divisor of two integers
|
||||
/// It is always non-negative.
|
||||
fn calculate_gcd(mut a: i64, mut b: i64) -> i64 {
|
||||
while b != 0 {
|
||||
let temp = b;
|
||||
b = a % b;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
a.abs()
|
||||
}
|
||||
|
||||
/// Calculate the least common multiple of two integers.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```example
|
||||
/// #calc.lcm(96, 13)
|
||||
/// ```
|
||||
///
|
||||
/// Display: Least Common Multiple
|
||||
/// Category: calculate
|
||||
/// Returns: integer
|
||||
#[func]
|
||||
pub fn lcm(
|
||||
/// The first integer.
|
||||
a: i64,
|
||||
/// The second integer.
|
||||
b: i64,
|
||||
) -> Value {
|
||||
calculate_lcm(a, b)
|
||||
.map(Value::Int)
|
||||
.ok_or("the return value is too large")
|
||||
.at(args.span)?
|
||||
}
|
||||
|
||||
/// Calculates the least common multiple between two non-zero integers
|
||||
/// Returns None if the value cannot be computed.
|
||||
/// It is always non-negative.
|
||||
fn calculate_lcm(a: i64, b: i64) -> Option<i64> {
|
||||
if a == b {
|
||||
return Some(a.abs());
|
||||
}
|
||||
|
||||
a.checked_div(calculate_gcd(a, b))?.checked_mul(b).map(|v| v.abs())
|
||||
}
|
||||
|
||||
/// Round a number down to the nearest integer.
|
||||
///
|
||||
/// If the number is already an integer, it is returned unchanged.
|
||||
|
@ -146,6 +146,30 @@
|
||||
#test(calc.binom(5, 6), 0)
|
||||
#test(calc.binom(6, 2), 15)
|
||||
|
||||
---
|
||||
// Test the `gcd` function.
|
||||
#test(calc.gcd(112, 77), 7)
|
||||
#test(calc.gcd(12, 96), 12)
|
||||
#test(calc.gcd(13, 9), 1)
|
||||
#test(calc.gcd(13, -9), 1)
|
||||
#test(calc.gcd(272557, 272557), 272557)
|
||||
#test(calc.gcd(0, 0), 0)
|
||||
#test(calc.gcd(7, 0), 7)
|
||||
|
||||
---
|
||||
// Test the `lcm` function.
|
||||
#test(calc.lcm(112, 77), 1232)
|
||||
#test(calc.lcm(12, 96), 96)
|
||||
#test(calc.lcm(13, 9), 117)
|
||||
#test(calc.lcm(13, -9), 117)
|
||||
#test(calc.lcm(272557, 272557), 272557)
|
||||
#test(calc.lcm(0, 0), 0)
|
||||
#test(calc.lcm(8, 0), 0)
|
||||
|
||||
---
|
||||
// Error: 10-41 the return value is too large
|
||||
#calc.lcm(15486487489457, 4874879896543)
|
||||
|
||||
---
|
||||
// Error: 10-12 expected at least one value
|
||||
#calc.min()
|
||||
|
Loading…
x
Reference in New Issue
Block a user