Skip to content

Commit 88ac275

Browse files
committed
New nodes: 'Greatest Common Divisor' and 'Least Common Multiple'
1 parent 166eb00 commit 88ac275

File tree

1 file changed

+74
-0
lines changed
  • node-graph/gmath-nodes/src

1 file changed

+74
-0
lines changed

node-graph/gmath-nodes/src/lib.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,80 @@ fn clamp<T: std::cmp::PartialOrd>(
462462
}
463463
}
464464

465+
/// The greatest common divisor (GCD) calculates the largest positive integer that divides both of the two input numbers without leaving a remainder.
466+
#[node_macro::node(category("Math: Numeric"))]
467+
fn greatest_common_divisor<T: num_traits::int::PrimInt + std::ops::ShrAssign<i32> + std::ops::SubAssign>(
468+
_: impl Ctx,
469+
/// One of the two numbers for which the GCD will be calculated.
470+
#[implementations(u32, u64, i32)]
471+
value: T,
472+
/// The other of the two numbers for which the GCD will be calculated.
473+
#[implementations(u32, u64, i32)]
474+
other_value: T,
475+
) -> T {
476+
if value == T::zero() {
477+
return other_value;
478+
}
479+
if other_value == T::zero() {
480+
return value;
481+
}
482+
binary_gcd(value, other_value)
483+
}
484+
485+
/// The least common multiple (LCM) calculates the smallest positive integer that is a multiple of both of the two input numbers.
486+
#[node_macro::node(category("Math: Numeric"))]
487+
fn least_common_multiple<T: num_traits::ToPrimitive + num_traits::FromPrimitive + num_traits::identities::Zero>(
488+
_: impl Ctx,
489+
/// One of the two numbers for which the LCM will be calculated.
490+
#[implementations(u32, u64, i32)]
491+
value: T,
492+
/// The other of the two numbers for which the LCM will be calculated.
493+
#[implementations(u32, u64, i32)]
494+
other_value: T,
495+
) -> T {
496+
let value = value.to_i128().unwrap();
497+
let other_value = other_value.to_i128().unwrap();
498+
499+
if value == 0 || other_value == 0 {
500+
return T::zero();
501+
}
502+
let gcd = binary_gcd(value, other_value);
503+
504+
T::from_i128((value * other_value).abs() / gcd).unwrap()
505+
}
506+
507+
fn binary_gcd<T: num_traits::int::PrimInt + std::ops::ShrAssign<i32> + std::ops::SubAssign>(mut a: T, mut b: T) -> T {
508+
if a == T::zero() {
509+
return b;
510+
}
511+
if b == T::zero() {
512+
return a;
513+
}
514+
515+
let mut shift = 0;
516+
while (a | b) & T::one() == T::zero() {
517+
a >>= 1;
518+
b >>= 1;
519+
shift += 1;
520+
}
521+
522+
while a & T::one() == T::zero() {
523+
a >>= 1;
524+
}
525+
526+
while b != T::zero() {
527+
while b & T::one() == T::zero() {
528+
b >>= 1;
529+
}
530+
if a > b {
531+
std::mem::swap(&mut a, &mut b);
532+
}
533+
b -= a;
534+
}
535+
536+
a << shift
537+
}
538+
465539
/// The equality operation (==) compares two values and returns true if they are equal, or false if they are not.
466540
#[node_macro::node(category("Math: Logic"))]
467541
fn equals<U: std::cmp::PartialEq<T>, T>(

0 commit comments

Comments
 (0)