From d235de63e2a62a0768e3f1de69282b4244bb29d3 Mon Sep 17 00:00:00 2001 From: Miccah Date: Mon, 16 Aug 2021 03:49:50 -0500 Subject: [PATCH] math: add egcd function implementing the extended Euclidean algorithm (#11203) --- vlib/math/math.v | 15 +++++++++++++++ vlib/math/math_test.v | 13 +++++++++++++ 2 files changed, 28 insertions(+) diff --git a/vlib/math/math.v b/vlib/math/math.v index 5e36425b6a..917998d8c1 100644 --- a/vlib/math/math.v +++ b/vlib/math/math.v @@ -89,6 +89,21 @@ pub fn gcd(a_ i64, b_ i64) i64 { return a } +// egcd returns (gcd(a, b), x, y) such that |a*x + b*y| = gcd(a, b) +pub fn egcd(a i64, b i64) (i64, i64, i64) { + mut old_r, mut r := a, b + mut old_s, mut s := i64(1), i64(0) + mut old_t, mut t := i64(0), i64(1) + + for r != 0 { + quot := old_r / r + old_r, r = r, old_r % r + old_s, s = s, old_s - quot * s + old_t, t = t, old_t - quot * t + } + return if old_r < 0 { -old_r } else { old_r }, old_s, old_t +} + // lcm calculates least common (non-negative) multiple. pub fn lcm(a i64, b i64) i64 { if a == 0 { diff --git a/vlib/math/math_test.v b/vlib/math/math_test.v index 2f99353fa6..5a847278c5 100644 --- a/vlib/math/math_test.v +++ b/vlib/math/math_test.v @@ -764,3 +764,16 @@ fn test_large_tan() { assert soclose(f1, f2, 4e-9) } } + +fn test_egcd() { + helper := fn (a i64, b i64, expected_g i64) { + g, x, y := egcd(a, b) + assert g == expected_g + assert abs(a * x + b * y) == g + } + + helper(6, 9, 3) + helper(6, -9, 3) + helper(-6, -9, 3) + helper(0, 0, 0) +}