Repository: pyccel/pyccel
Pull request #1986 (2024-09-19 10:44:51)

fix gcd and lcm implementations
This PR addresses the issue of negative values returned by the `gcd` and `lcm` functions when given negative inputs.

jalalium: /bot checklist
jalalium: /bot mark as ready
pyccel-bot[bot]: Unfortunately your PR is not passing the tests so it is not quite ready for review yet. Let me know when it is fixed with `/bot mark as ready`.

pyccel-bot[bot]: Unfortunately your PR is not passing the tests so it is not quite ready for review yet. Let me know when it is fixed with `/bot mark as ready`.

pyccel-bot[bot]: Hey @pyccel/pyccel-dev ! @jalalium has just created this great new pull request! Check it out and let me know what you think!

pyccel-bot[bot]: @jalalium, @EmilyBourne has a few questions/comments about your code. Can you go through and see if you agree with them. If not go ahead and explain why. Once you've adressed all the comments let me know with `/bot mark as ready` and we will see if we can get approval.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6ff40680..a72cb4b2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -62,6 +62,7 @@ All notable changes to this project will be documented in this file.
 -   #1892 : Fix implementation of list function when an iterable is passed as parameter.
 -   #1924 : Fix internal error arising in Duplicate or list comprehensions.
 -   #1970 : Fix missing `TypeError` for wrong type passed as optional argument.
+-   #1985 : Fix implementation of `gcd` and `lcm` for C and Fortran.
 
 ### Changed
 
diff --git a/pyccel/stdlib/math/pyc_math_c.c b/pyccel/stdlib/math/pyc_math_c.c
index 0a5d733f..585d7ee8 100644
--- a/pyccel/stdlib/math/pyc_math_c.c
+++ b/pyccel/stdlib/math/pyc_math_c.c
@@ -20,6 +20,8 @@ int64_t                     pyc_factorial(int64_t n)
 /*---------------------------------------------------------------------------*/
 int64_t                     pyc_gcd (int64_t a, int64_t b)
 {
+    a = a > 0 ? a : - a;
+    b = b > 0 ? b : - b;
     while (b) {
         a %= b;
         /* swap a and b*/
@@ -32,6 +34,8 @@ int64_t                     pyc_gcd (int64_t a, int64_t b)
 /*---------------------------------------------------------------------------*/
 int64_t                     pyc_lcm (int64_t a, int64_t b)
 {
+    a = a > 0 ? a : - a;
+    b = b > 0 ? b : - b;
     return a / pyc_gcd(a, b) * b;
 }
 /*---------------------------------------------------------------------------*/
diff --git a/pyccel/stdlib/math/pyc_math_f90.f90 b/pyccel/stdlib/math/pyc_math_f90.f90
index 88a328b5..991428e7 100644
--- a/pyccel/stdlib/math/pyc_math_f90.f90
+++ b/pyccel/stdlib/math/pyc_math_f90.f90
@@ -94,8 +94,8 @@ pure function pyc_gcd_4(a, b) result(gcd) ! integers with precision 4
     integer(i32)             :: x, y
     integer(i32)             :: gcd
 
-    x = a
-    y = b
+    x = MERGE(a, -a, a > 0)
+    y = MERGE(b, -b, b > 0)
     do while (y > 0)
         x = MOD(x, y)
         x = IEOR(x, y)
@@ -115,8 +115,8 @@ pure function pyc_gcd_8(a, b) result(gcd) ! integers with precision 8
     integer(i64)              :: x, y
     integer(i64)              :: gcd
 
-    x = a
-    y = b
+    x = MERGE(a, -a, a > 0)
+    y = MERGE(b, -b, b > 0)
     do while (y > 0)
         x = MOD(x, y)
         x = IEOR(x, y)
@@ -137,6 +137,8 @@ pure function pyc_lcm_4(a, b) result(lcm)
     integer(i32), value      :: b
     integer(i32)             :: lcm
 
+    a = MERGE(a, -a, a > 0)
+    b = MERGE(b, -b, b > 0)
     lcm = a / pyc_gcd(a, b) * b
     return
 
@@ -150,6 +152,8 @@ pure function pyc_lcm_8(a, b) result(lcm)
     integer(i64), value      :: b
     integer(i64)             :: lcm
 
+    a = MERGE(a, -a, a > 0)
+    b = MERGE(b, -b, b > 0)
     lcm = a / pyc_gcd(a, b) * b
     return
 


Test patch:
diff --git a/tests/epyccel/recognised_functions/test_epyccel_pyc_math.py b/tests/epyccel/recognised_functions/test_epyccel_pyc_math.py
index a73155c0..91687c75 100644
--- a/tests/epyccel/recognised_functions/test_epyccel_pyc_math.py
+++ b/tests/epyccel/recognised_functions/test_epyccel_pyc_math.py
@@ -17,10 +17,13 @@ def test_call_gcd(language):
         return gcd(x, y)
 
     f = epyccel(call_gcd, language=language)
-    x = randint(1e9)
-    y = randint(1e9)
+    x = randint(0, 1e9)
+    y = randint(0, 1e9)
 
-    assert f(x,y) == call_gcd(x, y)
+    assert f(x, y) == call_gcd(x, y)
+    assert f(-x, y) == call_gcd(-x, y)
+    assert f(x, -y) == call_gcd(x, -y)
+    assert f(-x, -y) == call_gcd(-x, -y)
 
 # -----------------------------------------------------------------------------
 
@@ -44,10 +47,13 @@ def test_call_lcm(language):
         return lcm(x, y)
 
     f = epyccel(call_lcm, language=language)
-    x = randint(1e4)
-    y = randint(1e5)
+    x = randint(0, 1e4)
+    y = randint(0, 1e5)
 
-    assert f(x,y) == call_lcm(x, y)
+    assert f(x, y) == call_lcm(x, y)
+    assert f(-x, y) == call_lcm(-x, y)
+    assert f(x, -y) == call_lcm(x, -y)
+    assert f(-x, -y) == call_lcm(-x, -y)
 
 # -----------------------------------------------------------------------------