Skip to content

Commit 6f9afad

Browse files
authored
Fix Integer.extended_gcd/2 returning negative GCD for zero base cases (#15163)
When one argument is 0 and the other is negative, `extended_gcd/2` was returning a negative GCD, violating both the @SPEC (which declares `non_neg_integer`) and consistency with `gcd/2`.
1 parent 13024f4 commit 6f9afad

2 files changed

Lines changed: 16 additions & 3 deletions

File tree

lib/elixir/lib/integer.ex

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -532,17 +532,23 @@ defmodule Integer do
532532
533533
iex> Integer.extended_gcd(10, 0)
534534
{10, 1, 0}
535+
iex> Integer.extended_gcd(-10, 0)
536+
{10, -1, 0}
535537
iex> Integer.extended_gcd(0, 10)
536538
{10, 0, 1}
539+
iex> Integer.extended_gcd(0, -10)
540+
{10, 0, -1}
537541
iex> Integer.extended_gcd(0, 0)
538542
{0, 0, 0}
539543
540544
"""
541545
@doc since: "1.12.0"
542546
@spec extended_gcd(integer, integer) :: {non_neg_integer, integer, integer}
543547
def extended_gcd(0, 0), do: {0, 0, 0}
544-
def extended_gcd(0, b), do: {b, 0, 1}
545-
def extended_gcd(a, 0), do: {a, 1, 0}
548+
def extended_gcd(0, b) when b > 0, do: {b, 0, 1}
549+
def extended_gcd(0, b) when b < 0, do: {-b, 0, -1}
550+
def extended_gcd(a, 0) when a > 0, do: {a, 1, 0}
551+
def extended_gcd(a, 0) when a < 0, do: {-a, -1, 0}
546552

547553
def extended_gcd(integer1, integer2) when is_integer(integer1) and is_integer(integer2) do
548554
extended_gcd(integer2, integer1, 0, 1, 1, 0)

lib/elixir/test/elixir/integer_test.exs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,13 +282,20 @@ defmodule IntegerTest do
282282
end
283283

284284
test "extended_gcd" do
285-
# Poor's man properby based testing
285+
# Poor's man property based testing
286286
for _ <- 1..100 do
287287
left = :rand.uniform(1000)
288288
right = :rand.uniform(1000)
289289
{gcd, m, n} = Integer.extended_gcd(left, right)
290290
assert Integer.gcd(left, right) == gcd
291291
assert m * left + n * right == gcd
292292
end
293+
294+
# zero cases
295+
for {left, right} <- [{10, 0}, {0, 10}, {0, -10}, {-10, 0}] do
296+
{gcd, m, n} = Integer.extended_gcd(left, right)
297+
assert Integer.gcd(left, right) == gcd
298+
assert m * left + n * right == gcd
299+
end
293300
end
294301
end

0 commit comments

Comments
 (0)