Skip to content

Commit 50ba48f

Browse files
committed
Microptimization.
Fix range obscurity and compile error.
1 parent 493ad58 commit 50ba48f

File tree

1 file changed

+20
-16
lines changed

1 file changed

+20
-16
lines changed

lib/std/math/gcd.zig

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@ const std = @import("std");
66
pub fn gcd(a: anytype, b: anytype) @TypeOf(a, b) {
77
const N = switch (@TypeOf(a, b)) {
88
// convert comptime_int to some sized int type for @ctz
9-
comptime_int => std.math.IntFittingRange(@min(a, b), @max(a, b)),
9+
comptime_int => std.math.IntFittingRange(0, @max(a, b)),
1010
else => |T| T,
1111
};
12+
1213
if (@typeInfo(N) != .int or @typeInfo(N).int.signedness != .unsigned) {
13-
@compileError("`a` and `b` must be usigned integers");
14+
@compileError("`a` and `b` must be unsigned integers");
1415
}
1516

1617
// using an optimised form of Stein's algorithm:
1718
// https://en.wikipedia.org/wiki/Binary_GCD_algorithm
19+
1820
std.debug.assert(a != 0 or b != 0);
1921

2022
if (a == 0) return b;
@@ -26,25 +28,27 @@ pub fn gcd(a: anytype, b: anytype) @TypeOf(a, b) {
2628
const xz = @ctz(x);
2729
const yz = @ctz(y);
2830
const shift = @min(xz, yz);
29-
x >>= @intCast(xz);
30-
y >>= @intCast(yz);
31-
32-
var diff = y -% x;
33-
while (diff != 0) : (diff = y -% x) {
34-
// ctz is invariant under negation, we
35-
// put it here to ease data dependencies,
36-
// makes the CPU happy.
37-
const zeros = @ctz(diff);
38-
if (x > y) diff = -%diff;
39-
y = @min(x, y);
40-
x = diff >> @intCast(zeros);
31+
x = @shrExact(x, @intCast(xz));
32+
y = @shrExact(y, @intCast(yz));
33+
34+
var y_minus_x = y -% x;
35+
while (y_minus_x != 0) : (y_minus_x = y -% x) {
36+
const copy_x = x;
37+
const zeros = @ctz(y_minus_x);
38+
const carry = x < y;
39+
x -%= y;
40+
if (carry) {
41+
x = y_minus_x;
42+
y = copy_x;
43+
}
44+
x = @shrExact(x, @intCast(zeros));
4145
}
42-
return y << @intCast(shift);
46+
47+
return @shlExact(y, @intCast(shift));
4348
}
4449

4550
test gcd {
4651
const expectEqual = std.testing.expectEqual;
47-
4852
try expectEqual(gcd(0, 5), 5);
4953
try expectEqual(gcd(5, 0), 5);
5054
try expectEqual(gcd(8, 12), 4);

0 commit comments

Comments
 (0)