GCD and LCM — Euclidean Algorithm
Tutorial Video
Text description (accessibility)
This video demonstrates the "GCD and LCM — Euclidean Algorithm" functional Rust example. Difficulty level: Intermediate. Key concepts covered: Functional Programming. The greatest common divisor (GCD) and least common multiple (LCM) are foundational operations in arithmetic: reducing fractions, synchronizing periodic events, solving linear Diophantine equations, and implementing modular arithmetic all depend on them. Key difference from OCaml: | Aspect | Rust | OCaml |
Tutorial
The Problem
The greatest common divisor (GCD) and least common multiple (LCM) are foundational operations in arithmetic: reducing fractions, synchronizing periodic events, solving linear Diophantine equations, and implementing modular arithmetic all depend on them. The Euclidean algorithm computes GCD in O(log min(a,b)) — exponentially faster than trial factorization. Extended Euclidean finds Bezout coefficients (x, y such that ax + by = gcd(a,b)), enabling modular inverse computation essential for RSA and other cryptographic operations. These functions appear in virtually every number theory library.
🎯 Learning Outcomes
gcd(a, b) = gcd(b, a % b), base case gcd(a, 0) = alcm(a, b) = (a / gcd(a, b)) * b (divide before multiply to avoid overflow)gcd(a,b) = 1 implies a has a modular inverse mod bCode Example
#![allow(clippy::all)]
//! # GCD and LCM (Euclidean Algorithm)
pub fn gcd(a: u64, b: u64) -> u64 {
if b == 0 {
a
} else {
gcd(b, a % b)
}
}
pub fn lcm(a: u64, b: u64) -> u64 {
a / gcd(a, b) * b
}
pub fn extended_gcd(a: i64, b: i64) -> (i64, i64, i64) {
if b == 0 {
(a, 1, 0)
} else {
let (g, x, y) = extended_gcd(b, a % b);
(g, y, x - (a / b) * y)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gcd() {
assert_eq!(gcd(48, 18), 6);
}
#[test]
fn test_lcm() {
assert_eq!(lcm(4, 6), 12);
}
}Key Differences
| Aspect | Rust | OCaml |
|---|---|---|
| Recursion | Tail-recursive, TCO not guaranteed | TCO guaranteed |
| Signed integers | Use i64 with abs() | Int.abs or abs |
| Standard library | num::integer::gcd (crate) | Int.gcd (recent OCaml) |
| Return type | Single u64 | Single int |
| Extended GCD | Returns (i64, i64, i64) | (int * int * int) |
| Overflow prevention | Divide before multiply | Same idiom |
OCaml Approach
OCaml's recursive GCD is identical in structure: let rec gcd a b = if b = 0 then a else gcd b (a mod b). OCaml's optimizer performs tail call elimination, so deep recursion is stack-safe. The Int.abs handles negative inputs for signed int. OCaml's standard library includes Int.gcd in recent versions. The Zarith library provides GCD for arbitrary-precision integers. OCaml's let lcm a b = (a / gcd a b) * b mirrors Rust exactly. The extended Euclidean algorithm uses a pair return type (int * int * int) for (gcd, x, y).
Full Source
#![allow(clippy::all)]
//! # GCD and LCM (Euclidean Algorithm)
pub fn gcd(a: u64, b: u64) -> u64 {
if b == 0 {
a
} else {
gcd(b, a % b)
}
}
pub fn lcm(a: u64, b: u64) -> u64 {
a / gcd(a, b) * b
}
pub fn extended_gcd(a: i64, b: i64) -> (i64, i64, i64) {
if b == 0 {
(a, 1, 0)
} else {
let (g, x, y) = extended_gcd(b, a % b);
(g, y, x - (a / b) * y)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gcd() {
assert_eq!(gcd(48, 18), 6);
}
#[test]
fn test_lcm() {
assert_eq!(lcm(4, 6), 12);
}
}#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gcd() {
assert_eq!(gcd(48, 18), 6);
}
#[test]
fn test_lcm() {
assert_eq!(lcm(4, 6), 12);
}
}
Deep Comparison
OCaml vs Rust: Gcd Lcm Euclid
Overview
See the example.rs and example.ml files for detailed implementations.
Key Differences
| Aspect | OCaml | Rust |
|---|---|---|
| Type system | Hindley-Milner | Ownership + traits |
| Memory | GC | Zero-cost abstractions |
| Mutability | Explicit ref | mut keyword |
| Error handling | Option/Result | Result<T, E> |
See README.md for detailed comparison.
Exercises
(gcd, x, y) such that a*x + b*y = gcd(a,b).gcd(a, b, c) = gcd(gcd(a, b), c).Fraction type with automatic reduction using GCD on construction.