Skip to content

Commit 6c9ab98

Browse files
committed
Use shift instead division (to support i2) and avoid overflow of temp results.
1 parent 1fd414e commit 6c9ab98

File tree

1 file changed

+24
-3
lines changed

1 file changed

+24
-3
lines changed

lib/std/math/egcd.zig

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,19 @@ pub fn egcd(a: anytype, b: anytype) ExtendedGreatestCommonDivisor(@TypeOf(a, b))
4141
const toinv = @shrExact(other, @intCast(shift));
4242
const ctrl = @shrExact(odd, @intCast(shift)); // Invariant: |s|, |t|, |ctrl| < |MIN_OF(S)|
4343
const half_ctrl = 1 + @shrExact(ctrl - 1, 1);
44+
const abs_ctrl = @abs(ctrl);
4445

4546
var s: S = std.math.sign(toinv);
4647
var t: S = 0;
4748

4849
var x = @abs(toinv);
49-
var y = @abs(ctrl);
50+
var y = abs_ctrl;
5051

5152
{
5253
const xz = @ctz(x);
5354
x = @shrExact(x, @intCast(xz));
5455
for (0..xz) |_| {
55-
const half_s = @divFloor(s, 2);
56+
const half_s = s >> 1;
5657
if (s & 1 == 0)
5758
s = half_s
5859
else
@@ -78,12 +79,14 @@ pub fn egcd(a: anytype, b: anytype) ExtendedGreatestCommonDivisor(@TypeOf(a, b))
7879
}
7980
x = @shrExact(x, @intCast(xz));
8081
for (0..xz) |_| {
81-
const half_s = @divFloor(s, 2);
82+
const half_s = s >> 1;
8283
if (s & 1 == 0)
8384
s = half_s
8485
else
8586
s = half_s + half_ctrl;
8687
}
88+
89+
if (s < 0) s = @intCast(abs_ctrl - @abs(s));
8790
}
8891

8992
// Using integer widening is only a temporary solution.
@@ -98,6 +101,24 @@ pub fn egcd(a: anytype, b: anytype) ExtendedGreatestCommonDivisor(@TypeOf(a, b))
98101
}
99102

100103
test {
104+
{
105+
const a: i2 = 0;
106+
const b: i2 = 1;
107+
const r = egcd(a, b);
108+
const g = r.gcd;
109+
const s: i2 = r.bezout_coeff_1;
110+
const t: i2 = r.bezout_coeff_2;
111+
try std.testing.expect(s * a + t * b == g);
112+
}
113+
{
114+
const a: i8 = -128;
115+
const b: i8 = 127;
116+
const r = egcd(a, b);
117+
const g = r.gcd;
118+
const s: i16 = r.bezout_coeff_1;
119+
const t: i16 = r.bezout_coeff_2;
120+
try std.testing.expect(s * a + t * b == g);
121+
}
101122
{
102123
const a: i16 = -32768;
103124
const b: i16 = -32768;

0 commit comments

Comments
 (0)