//! Greatest common divisor (https://mathworld.wolfram.com/GreatestCommonDivisor.html) const std = @import("std"); const expectEqual = std.testing.expectEqual; /// Returns the greatest common divisor (GCD) of two unsigned integers (a and b) which are not both zero. /// For example, the GCD of 8 and 12 is 4, that is, gcd(8, 12) == 4. pub fn gcd(a: anytype, b: anytype) @TypeOf(a, b) { // only unsigned integers are allowed and not both must be zero comptime switch (@typeInfo(@TypeOf(a, b))) { .Int => |int| std.debug.assert(int.signedness == .unsigned), .ComptimeInt => { std.debug.assert(a >= 0); std.debug.assert(b >= 0); }, else => unreachable, }; std.debug.assert(a != 0 or b != 0); // if one of them is zero, the other is returned if (a == 0) return b; if (b == 0) return a; // init vars var x: @TypeOf(a, b) = a; var y: @TypeOf(a, b) = b; var m: @TypeOf(a, b) = a; // using the Euclidean algorithm (https://mathworld.wolfram.com/EuclideanAlgorithm.html) while (y != 0) { m = x % y; x = y; y = m; } return x; } test "gcd" { try expectEqual(gcd(0, 5), 5); try expectEqual(gcd(5, 0), 5); try expectEqual(gcd(8, 12), 4); try expectEqual(gcd(12, 8), 4); try expectEqual(gcd(33, 77), 11); try expectEqual(gcd(77, 33), 11); try expectEqual(gcd(49865, 69811), 9973); try expectEqual(gcd(300_000, 2_300_000), 100_000); try expectEqual(gcd(90000000_000_000_000_000_000, 2), 2); }