Skip to content

Commit aade743

Browse files
authored
Euclidean extended gcd (#59)
* extended gcd * nits * fix code cov * add tests with big numbers * rename * fix cargo test --------- Co-authored-by: Luke Videckis <lukevideckis@gmail.com>
1 parent e9b122f commit aade743

File tree

4 files changed

+77
-0
lines changed

4 files changed

+77
-0
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,7 @@ path = "examples/graphs/hld_jump_on_tree_nodes.rs"
133133
[[example]]
134134
name = "hld_jump_on_tree_edges"
135135
path = "examples/graphs/hld_jump_on_tree_edges.rs"
136+
137+
[[example]]
138+
name = "ext_gcd"
139+
path = "examples/numbers/ext_gcd.rs"

examples/numbers/ext_gcd.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// verification-helper: PROBLEM https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_1_B
2+
3+
use proconio::input;
4+
use programming_team_code_rust::numbers::ext_gcd::ext_gcd;
5+
6+
fn do_asserts(a: i64, b: i64) {
7+
let (gcd, x, y) = ext_gcd(a, b);
8+
assert_eq!(a as i128 * x as i128 + b as i128 * y as i128, gcd as i128);
9+
if gcd != 0 {
10+
assert_eq!(a % gcd, 0);
11+
assert_eq!(b % gcd, 0);
12+
}
13+
if b != 0 {
14+
assert!(-(b / gcd).abs() < x);
15+
assert!(x < (b / gcd).abs());
16+
}
17+
}
18+
19+
fn main() {
20+
input! {
21+
a: i64,
22+
b: i64,
23+
}
24+
25+
let vals = [
26+
a,
27+
b,
28+
-a,
29+
-b,
30+
0_i64,
31+
1_000_000_000_000_000_000_i64,
32+
i64::MAX / 2,
33+
i64::MIN / 2,
34+
];
35+
for &val_one in &vals {
36+
for &val_two in &vals {
37+
do_asserts(val_one, val_two);
38+
}
39+
}
40+
41+
println!("{}", ext_gcd(a, b).0);
42+
}

src/numbers/ext_gcd.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//! # Extended GCD
2+
3+
/// See <https://nor-blog.codeberg.page/posts/2023-11-27-std-exchange-cpp/>
4+
///
5+
/// ext_gcd(a, b) returns (gcd, x, y) such that a * x + b * y == gcd
6+
/// if a and b are coprime, then x is the inverse of a (mod b)
7+
///
8+
/// # Example
9+
/// ```
10+
/// use programming_team_code_rust::numbers::ext_gcd::ext_gcd;
11+
///
12+
/// let (a, b) = (4, -6);
13+
/// let (gcd, x, y) = ext_gcd(a, b);
14+
/// assert_eq!(gcd, -2);
15+
/// assert_eq!(a * x + b * y, gcd);
16+
/// assert_eq!(ext_gcd(0, 0), (0, 1, 0));
17+
/// ```
18+
///
19+
/// - Time: O(log(min(a, b)))
20+
/// - Space: O(1)
21+
pub fn ext_gcd(mut a: i64, mut b: i64) -> (i64, i64, i64) {
22+
let (mut x, mut y, mut i, mut j) = (1, 0, 0, 1);
23+
while b != 0 {
24+
let quot = a / b;
25+
(a, b) = (b, a - quot * b);
26+
(x, i) = (i, x - quot * i);
27+
(y, j) = (j, y - quot * j);
28+
}
29+
(a, x, y)
30+
}

src/numbers/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! # Number Theory and Combinatorics
22
pub mod binom;
3+
pub mod ext_gcd;
34
pub mod fft;
45
pub mod primes;

0 commit comments

Comments
 (0)