From 8260ef1bfc470a567a5132d1485d89cd910ae163 Mon Sep 17 00:00:00 2001 From: Nandini Raja Date: Sat, 16 Oct 2021 02:24:20 +0530 Subject: [PATCH 01/31] Issue #983 | Add Round function and implement the conversion to C and Fortran --- pyccel/ast/builtins.py | 23 +++++++++++++++++++++++ pyccel/codegen/printing/ccode.py | 5 +++++ pyccel/codegen/printing/fcode.py | 6 ++++++ pyccel/codegen/printing/pycode.py | 3 +++ tests/epyccel/test_epyccel_round.py | 15 +++++++++++++++ 5 files changed, 52 insertions(+) create mode 100644 tests/epyccel/test_epyccel_round.py diff --git a/pyccel/ast/builtins.py b/pyccel/ast/builtins.py index a08916fb98..b1150f0c00 100644 --- a/pyccel/ast/builtins.py +++ b/pyccel/ast/builtins.py @@ -42,6 +42,7 @@ 'PythonZip', 'PythonMax', 'PythonMin', + 'PythonRound', 'python_builtin_datatype' ) @@ -319,6 +320,27 @@ def arg(self): def __str__(self): return 'float({0})'.format(str(self.arg)) +# =========================================================================== +class PythonRound(PyccelAstNode): + """ Represents a call to Python's native round() function. + """ + __slots__ = ('_arg') + name = 'round' + _dtype = NativeReal() + _precision = default_precision['real'] + _rank = 0 + _shape = () + _order = None + _attribute_nodes = ('_arg',) + + def __init__(self, arg): + self._arg = arg + super().__init__() + + @property + def arg(self): + return self._arg + #============================================================================== class PythonInt(PyccelAstNode): """ Represents a call to Python's native int() function. @@ -861,4 +883,5 @@ def python_builtin_datatype(name): 'not' : PyccelNot, 'map' : PythonMap, 'type' : PythonType, + 'round' : PythonRound, } diff --git a/pyccel/codegen/printing/ccode.py b/pyccel/codegen/printing/ccode.py index 212d29f717..9a529f3302 100644 --- a/pyccel/codegen/printing/ccode.py +++ b/pyccel/codegen/printing/ccode.py @@ -419,6 +419,11 @@ def _print_PythonAbs(self, expr): func = "labs" return "{}({})".format(func, self._print(expr.arg)) + def _print_PythonRound(self, expr): + self._additional_imports.add("math") + func = "round" + return "{}({})".format(func, self._print(expr.arg)) + def _print_PythonMin(self, expr): arg = expr.args[0] if arg.dtype is NativeReal() and len(arg) == 2: diff --git a/pyccel/codegen/printing/fcode.py b/pyccel/codegen/printing/fcode.py index c1df2bc1e9..dadf445574 100644 --- a/pyccel/codegen/printing/fcode.py +++ b/pyccel/codegen/printing/fcode.py @@ -543,6 +543,12 @@ def _print_PythonAbs(self, expr): """ return "abs({})".format(self._print(expr.arg)) + def _print_PythonRound(self, expr): + """ print the python builtin function round + args : variable + """ + return "nint({})".format(self._print(expr.arg)) + def _print_PythonTuple(self, expr): shape = tuple(reversed(expr.shape)) if len(shape)>1: diff --git a/pyccel/codegen/printing/pycode.py b/pyccel/codegen/printing/pycode.py index 6c73b86b7a..533fcc0648 100644 --- a/pyccel/codegen/printing/pycode.py +++ b/pyccel/codegen/printing/pycode.py @@ -372,6 +372,9 @@ def _print_PythonImag(self, expr): def _print_PythonPrint(self, expr): return 'print({})\n'.format(', '.join(self._print(a) for a in expr.expr)) + def _print_PythonRound(self, expr): + return 'round({})'.format(self._print(expr.arg)) + def _print_PyccelArraySize(self, expr): arg = self._print(expr.arg) index = self._print(expr.index) diff --git a/tests/epyccel/test_epyccel_round.py b/tests/epyccel/test_epyccel_round.py new file mode 100644 index 0000000000..938c4f476c --- /dev/null +++ b/tests/epyccel/test_epyccel_round.py @@ -0,0 +1,15 @@ +# pylint: disable=missing-function-docstring, missing-module-docstring/ +from pyccel.decorators import types +from pyccel.epyccel import epyccel + +def test_round_int(language): + @types('real') + def round_int(x): + return round(x) + + f = epyccel(round_int, language=language) + x = randint(100) / 10 + + f_output = f(x) + round_int_output = round_int(x) + assert round_int_output == f_output From d02c02a66e03bfb309aa8bf0126191967339701a Mon Sep 17 00:00:00 2001 From: Nandini Raja Date: Sat, 16 Oct 2021 12:33:31 +0530 Subject: [PATCH 02/31] Issue #983 | Add an import for randint in tests --- tests/epyccel/test_epyccel_round.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/epyccel/test_epyccel_round.py b/tests/epyccel/test_epyccel_round.py index 938c4f476c..09b4902a94 100644 --- a/tests/epyccel/test_epyccel_round.py +++ b/tests/epyccel/test_epyccel_round.py @@ -1,4 +1,6 @@ # pylint: disable=missing-function-docstring, missing-module-docstring/ +from numpy.random import randint + from pyccel.decorators import types from pyccel.epyccel import epyccel From c65cf403c3d71afa563e95700581efd5694ddcdb Mon Sep 17 00:00:00 2001 From: Nandini Raja Date: Sat, 16 Oct 2021 12:47:24 +0530 Subject: [PATCH 03/31] Remove slots --- pyccel/ast/builtins.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyccel/ast/builtins.py b/pyccel/ast/builtins.py index b1150f0c00..c321e93878 100644 --- a/pyccel/ast/builtins.py +++ b/pyccel/ast/builtins.py @@ -324,7 +324,6 @@ def __str__(self): class PythonRound(PyccelAstNode): """ Represents a call to Python's native round() function. """ - __slots__ = ('_arg') name = 'round' _dtype = NativeReal() _precision = default_precision['real'] From 85085bd139c77ed63307780071d4b42dc08c60d3 Mon Sep 17 00:00:00 2001 From: "Emily.Bourne" Date: Mon, 2 May 2022 11:05:58 +0200 Subject: [PATCH 04/31] Put back slots. Fix merge --- pyccel/ast/builtins.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyccel/ast/builtins.py b/pyccel/ast/builtins.py index 2a078f220e..702a6a06c8 100644 --- a/pyccel/ast/builtins.py +++ b/pyccel/ast/builtins.py @@ -328,9 +328,10 @@ def __str__(self): class PythonRound(PyccelAstNode): """ Represents a call to Python's native round() function. """ + __slots__ = ('_arg',) name = 'round' - _dtype = NativeReal() - _precision = default_precision['real'] + _dtype = NativeFloat() + _precision = default_precision['float'] _rank = 0 _shape = () _order = None From bf79ca94a4e9b93de19292579fad22bce819ced1 Mon Sep 17 00:00:00 2001 From: "Emily.Bourne" Date: Mon, 2 May 2022 11:08:08 +0200 Subject: [PATCH 05/31] Add type check --- tests/epyccel/test_epyccel_round.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/epyccel/test_epyccel_round.py b/tests/epyccel/test_epyccel_round.py index 09b4902a94..df24e12af1 100644 --- a/tests/epyccel/test_epyccel_round.py +++ b/tests/epyccel/test_epyccel_round.py @@ -15,3 +15,4 @@ def round_int(x): f_output = f(x) round_int_output = round_int(x) assert round_int_output == f_output + assert isinstance(round_int_output, type(f_output)) From 1c9640d883de5ca1d3bb06f25caafbfd9265003d Mon Sep 17 00:00:00 2001 From: "Emily.Bourne" Date: Mon, 2 May 2022 11:08:58 +0200 Subject: [PATCH 06/31] Correct merge --- pyccel/codegen/printing/ccode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyccel/codegen/printing/ccode.py b/pyccel/codegen/printing/ccode.py index cd9b688ce8..32cc8eda38 100644 --- a/pyccel/codegen/printing/ccode.py +++ b/pyccel/codegen/printing/ccode.py @@ -516,7 +516,7 @@ def _print_PythonAbs(self, expr): return "{}({})".format(func, self._print(expr.arg)) def _print_PythonRound(self, expr): - self._additional_imports.add("math") + self.add_import(c_imports['math']) func = "round" return "{}({})".format(func, self._print(expr.arg)) From 25a7c95bf7715968bd18a4f6b404a4d11b7ca580 Mon Sep 17 00:00:00 2001 From: "Emily.Bourne" Date: Mon, 2 May 2022 11:14:47 +0200 Subject: [PATCH 07/31] Add ndigits argument to class --- pyccel/ast/builtins.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/pyccel/ast/builtins.py b/pyccel/ast/builtins.py index 702a6a06c8..e7ef2b3aa6 100644 --- a/pyccel/ast/builtins.py +++ b/pyccel/ast/builtins.py @@ -330,21 +330,33 @@ class PythonRound(PyccelAstNode): """ __slots__ = ('_arg',) name = 'round' - _dtype = NativeFloat() - _precision = default_precision['float'] _rank = 0 _shape = () _order = None - _attribute_nodes = ('_arg',) + _attribute_nodes = ('_arg','_ndigits') - def __init__(self, arg): - self._arg = arg + def __init__(self, number, ndigits = None): + self._arg = number + if ndigits is None: + self._dtype = NativeInteger() + self._precision = default_precision['int'] + else: + self._dtype = NativeFloat() + self._precision = default_precision['float'] super().__init__() @property def arg(self): + """ Number to be rounded + """ return self._arg + @property + def ndigits(self): + """ Number of digits to which the argument is rounded + """ + return self._ndigits + #============================================================================== class PythonInt(PyccelAstNode): """ Represents a call to Python's native int() function. From ddef46d7b878959cb52d86cdb82b5ab9f422f4cc Mon Sep 17 00:00:00 2001 From: "Emily.Bourne" Date: Mon, 2 May 2022 11:20:25 +0200 Subject: [PATCH 08/31] Add missing slots --- pyccel/ast/builtins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyccel/ast/builtins.py b/pyccel/ast/builtins.py index e7ef2b3aa6..107e543cda 100644 --- a/pyccel/ast/builtins.py +++ b/pyccel/ast/builtins.py @@ -328,7 +328,7 @@ def __str__(self): class PythonRound(PyccelAstNode): """ Represents a call to Python's native round() function. """ - __slots__ = ('_arg',) + __slots__ = ('_arg', '_ndigits', '_dtype', '_precision') name = 'round' _rank = 0 _shape = () From 37000295c3705b79bb8f5aae2def0b3c96eedd0a Mon Sep 17 00:00:00 2001 From: "Emily.Bourne" Date: Mon, 2 May 2022 11:24:17 +0200 Subject: [PATCH 09/31] Save ndigits. Use default python precision (instead of numpy precision) --- pyccel/ast/builtins.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyccel/ast/builtins.py b/pyccel/ast/builtins.py index 107e543cda..c1d5c524b7 100644 --- a/pyccel/ast/builtins.py +++ b/pyccel/ast/builtins.py @@ -339,10 +339,11 @@ def __init__(self, number, ndigits = None): self._arg = number if ndigits is None: self._dtype = NativeInteger() - self._precision = default_precision['int'] + self._ndigits = None else: self._dtype = NativeFloat() - self._precision = default_precision['float'] + self._ndigits = ndigits + self._precision = -1 super().__init__() @property From 0d9e30dd6b8019e125f5e868c7d43d56abbec69a Mon Sep 17 00:00:00 2001 From: "Emily.Bourne" Date: Mon, 2 May 2022 11:26:05 +0200 Subject: [PATCH 10/31] Add more tests --- tests/epyccel/test_epyccel_round.py | 51 +++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/tests/epyccel/test_epyccel_round.py b/tests/epyccel/test_epyccel_round.py index df24e12af1..a9a0614d9c 100644 --- a/tests/epyccel/test_epyccel_round.py +++ b/tests/epyccel/test_epyccel_round.py @@ -9,10 +9,57 @@ def test_round_int(language): def round_int(x): return round(x) - f = epyccel(round_int, language=language) + f = epyccel(round_int, language=language, developer_mode=True) x = randint(100) / 10 f_output = f(x) round_int_output = round_int(x) assert round_int_output == f_output - assert isinstance(round_int_output, type(f_output)) + assert isinstance(f_output, type(round_int_output)) + + # Round down + x = 3.345 + + f_output = f(x) + round_int_output = round_int(x) + assert round_int_output == f_output + assert isinstance(f_output, type(round_int_output)) + + # Round up + x = 3.845 + + f_output = f(x) + round_int_output = round_int(x) + assert round_int_output == f_output + assert isinstance(f_output, type(round_int_output)) + +def test_negative_round_int(language): + @types('real') + def round_int(x): + return round(x) + + f = epyccel(round_int, language=language, developer_mode=True) + x = -randint(100) / 10 + + f_output = f(x) + round_int_output = round_int(x) + assert round_int_output == f_output + assert isinstance(f_output, type(round_int_output)) + + # Round up + x = -3.345 + + f_output = f(x) + round_int_output = round_int(x) + assert round_int_output == f_output + assert isinstance(f_output, type(round_int_output)) + + # Round down + x = -3.845 + + f_output = f(x) + round_int_output = round_int(x) + assert round_int_output == f_output + assert isinstance(f_output, type(round_int_output)) + +#TODO: Add float tests From 86a4ed891902040d4367370b607ee39590bb1cde Mon Sep 17 00:00:00 2001 From: "Emily.Bourne" Date: Mon, 2 May 2022 11:27:55 +0200 Subject: [PATCH 11/31] Test middle case --- tests/epyccel/test_epyccel_round.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/epyccel/test_epyccel_round.py b/tests/epyccel/test_epyccel_round.py index a9a0614d9c..9c10c6eea8 100644 --- a/tests/epyccel/test_epyccel_round.py +++ b/tests/epyccel/test_epyccel_round.py @@ -33,6 +33,14 @@ def round_int(x): assert round_int_output == f_output assert isinstance(f_output, type(round_int_output)) + # Round half + x = 6.5 + + f_output = f(x) + round_int_output = round_int(x) + assert round_int_output == f_output + assert isinstance(f_output, type(round_int_output)) + def test_negative_round_int(language): @types('real') def round_int(x): @@ -62,4 +70,12 @@ def round_int(x): assert round_int_output == f_output assert isinstance(f_output, type(round_int_output)) + # Round half + x = -6.5 + + f_output = f(x) + round_int_output = round_int(x) + assert round_int_output == f_output + assert isinstance(f_output, type(round_int_output)) + #TODO: Add float tests From 99e73ee8e1112025052b64da7bd6a64817f23890 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 16 Jul 2022 08:44:13 +0000 Subject: [PATCH 12/31] Update performance comparison --- performance.md | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/performance.md b/performance.md index 3a666bec9c..5b7f7eae87 100644 --- a/performance.md +++ b/performance.md @@ -1,32 +1,32 @@ -# Performance Comparison (as of Tue Jun 14 13:19:45 UTC 2022) +# Performance Comparison (as of Sat Jul 16 08:44:11 UTC 2022) ## Compilation time Algorithm | python | pythran | numba | pyccel | pyccel_c ------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- -Ackermann | - | 3.70 | 0.48 | 1.53 | 1.37 -Bellman Ford | - | 5.05 | 1.00 | 2.21 | 2.16 -Dijkstra | - | 6.25 | 1.30 | 2.34 | - -Euler | - | 7.64 | 1.52 | 2.29 | 2.27 -Midpoint Explicit | - | 8.69 | 2.21 | 2.79 | 2.69 -Midpoint Fixed | - | 9.61 | 2.65 | 2.77 | 2.70 -RK4 | - | 9.16 | 2.62 | 3.18 | - -FD - L Convection | - | 3.95 | 0.43 | 2.04 | 2.03 -FD - NL Convection | - | 4.15 | 0.44 | 2.11 | 2.34 -FD - Poisson | - | 10.87 | 1.00 | 2.35 | 2.21 -FD - Laplace | - | 18.45 | 2.12 | 2.90 | - -M-D | - | 15.12 | 5.81 | 3.69 | 3.29 +Ackermann | - | 3.32 | 0.39 | 1.39 | 1.29 +Bellman Ford | - | 4.43 | 0.86 | 1.99 | 2.02 +Dijkstra | - | 5.71 | 1.23 | 2.07 | - +Euler | - | 6.60 | 1.36 | 2.00 | 1.98 +Midpoint Explicit | - | 7.59 | 1.94 | 2.39 | 2.44 +Midpoint Fixed | - | 9.13 | 2.28 | 2.55 | 2.46 +RK4 | - | 8.26 | 2.36 | 3.12 | - +FD - L Convection | - | 3.54 | 0.39 | 1.96 | 1.86 +FD - NL Convection | - | 3.50 | 0.39 | 1.88 | 1.86 +FD - Poisson | - | 9.20 | 0.86 | 2.14 | 1.98 +FD - Laplace | - | 16.55 | 1.89 | 2.59 | - +M-D | - | 11.96 | 5.13 | 2.88 | 2.58 ## Execution time Algorithm | python | pythran | numba | pyccel | pyccel_c ------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- -Ackermann (ms) | 528.00 $\pm$ 16.00 | 18.10 $\pm$ 1.20 | 34.60 $\pm$ 1.70 | 3.65 $\pm$ 0.12 | 4.15 $\pm$ 0.14 -Bellman Ford (ns) | 77200.00 $\pm$ 3900.00 | 470.00 $\pm$ 18.00 | 639.00 $\pm$ 22.00 | 282.00 $\pm$ 11.00 | 603.00 $\pm$ 53.00 -Dijkstra (ns) | 40600.00 $\pm$ 1200.00 | 418.00 $\pm$ 21.00 | 418.00 $\pm$ 27.00 | 350.00 $\pm$ 12.00 | - -Euler (ms) | 72.20 $\pm$ 5.10 | 0.75 $\pm$ 0.03 | 1.02 $\pm$ 0.04 | 0.24 $\pm$ 0.02 | 3.62 $\pm$ 0.13 -Midpoint Explicit (ms) | 147.00 $\pm$ 9.00 | 1.66 $\pm$ 0.05 | 2.69 $\pm$ 0.08 | 0.31 $\pm$ 0.01 | 6.54 $\pm$ 0.58 -Midpoint Fixed (ms) | 721.00 $\pm$ 45.00 | 9.49 $\pm$ 0.32 | 14.90 $\pm$ 0.60 | 1.09 $\pm$ 0.03 | 26.50 $\pm$ 0.90 -RK4 (ms) | 324.00 $\pm$ 17.00 | 2.48 $\pm$ 0.08 | 5.21 $\pm$ 0.21 | 0.94 $\pm$ 0.03 | - -FD - L Convection (ms) | 2560.00 $\pm$ 50.00 | 2.09 $\pm$ 0.04 | 11.60 $\pm$ 0.60 | 2.35 $\pm$ 0.09 | 2.25 $\pm$ 0.06 -FD - NL Convection (ms) | 3760.00 $\pm$ 130.00 | 2.05 $\pm$ 0.06 | 11.70 $\pm$ 0.60 | 2.05 $\pm$ 0.13 | 2.33 $\pm$ 0.07 -FD - Poisson (ms) | 5670.00 $\pm$ 180.00 | 3.78 $\pm$ 0.11 | 14.40 $\pm$ 0.80 | 5.06 $\pm$ 0.12 | 3.61 $\pm$ 0.12 -FD - Laplace (\textmu s) | 112.00 $\pm$ 8.00 | 3.15 $\pm$ 0.14 | 12.20 $\pm$ 0.30 | 2.79 $\pm$ 0.14 | - -M-D (ms) | 66800.00 $\pm$ 1700.00 | 77.80 $\pm$ 2.60 | 280.00 $\pm$ 16.00 | 69.50 $\pm$ 1.80 | 82.40 $\pm$ 4.50 +Ackermann (ms) | 478.00 $\pm$ 15.00 | 18.70 $\pm$ 0.10 | 31.20 $\pm$ 0.40 | 10.60 $\pm$ 0.00 | 10.20 $\pm$ 0.10 +Bellman Ford (ns) | 66400.00 $\pm$ 3100.00 | 379.00 $\pm$ 1.00 | 563.00 $\pm$ 14.00 | 239.00 $\pm$ 7.00 | 487.00 $\pm$ 6.00 +Dijkstra (ns) | 34100.00 $\pm$ 500.00 | 360.00 $\pm$ 6.00 | 344.00 $\pm$ 3.00 | 274.00 $\pm$ 0.00 | - +Euler (ms) | 57.60 $\pm$ 0.80 | 0.59 $\pm$ 0.01 | 1.11 $\pm$ 0.02 | 0.14 $\pm$ 0.00 | 3.12 $\pm$ 0.07 +Midpoint Explicit (ms) | 118.00 $\pm$ 2.00 | 1.36 $\pm$ 0.02 | 2.85 $\pm$ 0.07 | 0.17 $\pm$ 0.00 | 5.60 $\pm$ 0.17 +Midpoint Fixed (ms) | 588.00 $\pm$ 18.00 | 8.72 $\pm$ 0.06 | 15.90 $\pm$ 0.30 | 0.68 $\pm$ 0.01 | 25.10 $\pm$ 0.80 +RK4 (ms) | 275.00 $\pm$ 22.00 | 1.87 $\pm$ 0.00 | 5.76 $\pm$ 0.17 | 0.79 $\pm$ 0.04 | - +FD - L Convection (ms) | 2190.00 $\pm$ 60.00 | 1.48 $\pm$ 0.03 | 9.39 $\pm$ 0.06 | 1.65 $\pm$ 0.02 | 1.57 $\pm$ 0.02 +FD - NL Convection (ms) | 3150.00 $\pm$ 90.00 | 1.96 $\pm$ 0.03 | 9.25 $\pm$ 0.06 | 1.72 $\pm$ 0.01 | 1.84 $\pm$ 0.02 +FD - Poisson (ms) | 4570.00 $\pm$ 170.00 | 2.06 $\pm$ 0.03 | 10.50 $\pm$ 0.10 | 3.97 $\pm$ 0.11 | 1.78 $\pm$ 0.01 +FD - Laplace (\textmu s) | 60.90 $\pm$ 2.90 | 2.36 $\pm$ 0.03 | 8.72 $\pm$ 0.13 | 2.22 $\pm$ 0.03 | - +M-D (ms) | 52500.00 $\pm$ 600.00 | 55.20 $\pm$ 0.50 | 219.00 $\pm$ 1.00 | 48.20 $\pm$ 0.20 | 61.60 $\pm$ 0.60 From 9944bd0e8cf971bc75c451d0c3f92ac84af2908b Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Sat, 16 Jul 2022 11:10:19 +0200 Subject: [PATCH 13/31] Try and prevent trigger --- .github/workflows/master.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index afb51c6f3d..23cf7f32ca 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -2,7 +2,7 @@ name: master_tests on: push: - branches: [ master ] + branches: [ pyccel:master ] jobs: From 5e2da5072fecb31c82317c3358a0a2a3ad260af5 Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Sat, 16 Jul 2022 11:19:54 +0200 Subject: [PATCH 14/31] Add printing functions --- pyccel/ast/builtins.py | 11 ++++++++++- pyccel/codegen/printing/ccode.py | 9 ++++++--- pyccel/codegen/printing/fcode.py | 6 +++++- pyccel/codegen/printing/pycode.py | 7 ++++++- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/pyccel/ast/builtins.py b/pyccel/ast/builtins.py index b31857a720..c81c09c89d 100644 --- a/pyccel/ast/builtins.py +++ b/pyccel/ast/builtins.py @@ -23,7 +23,7 @@ from .literals import Literal, LiteralImaginaryUnit, get_default_literal_value from .literals import LiteralString from .operators import PyccelAdd, PyccelAnd, PyccelMul, PyccelIsNot -from .operators import PyccelMinus, PyccelUnarySub, PyccelNot +from .operators import PyccelMinus, PyccelUnarySub, PyccelNot, PyccelPow from .variable import IndexedElement pyccel_stage = PyccelStage() @@ -389,6 +389,15 @@ def ndigits(self): """ return self._ndigits + @property + def get_round_with_0_digits(self): + """ Get expression returning the same value but containing + a call to PyccelRound with ndigits=None + """ + assert self.ndigits is not None + factor = PyccelPow(LiteralFloat(10), self.ndigits) + return PyccelDiv(PyccelRound(PyccelMul(self.arg, factor)), factor) + #============================================================================== class PythonInt(PyccelAstNode): """ Represents a call to Python's native int() function. diff --git a/pyccel/codegen/printing/ccode.py b/pyccel/codegen/printing/ccode.py index 5a2dfdc6c6..78c6484d94 100644 --- a/pyccel/codegen/printing/ccode.py +++ b/pyccel/codegen/printing/ccode.py @@ -516,9 +516,12 @@ def _print_PythonAbs(self, expr): return "{}({})".format(func, self._print(expr.arg)) def _print_PythonRound(self, expr): - self.add_import(c_imports['math']) - func = "round" - return "{}({})".format(func, self._print(expr.arg)) + if self.ndigits is None: + self.add_import(c_imports['math']) + arg = self._print(expr.arg) + return f"round({arg})" + else: + return self._print(expr.get_round_with_0_digits()) def _print_PythonMin(self, expr): arg = expr.args[0] diff --git a/pyccel/codegen/printing/fcode.py b/pyccel/codegen/printing/fcode.py index 94446820c5..3752496eda 100644 --- a/pyccel/codegen/printing/fcode.py +++ b/pyccel/codegen/printing/fcode.py @@ -766,7 +766,11 @@ def _print_PythonRound(self, expr): """ print the python builtin function round args : variable """ - return "nint({})".format(self._print(expr.arg)) + if self.ndigits is None: + arg = self._print(expr.arg) + return f"nint({arg})" + else: + return self._print(expr.get_round_with_0_digits()) def _print_PythonTuple(self, expr): shape = tuple(reversed(expr.shape)) diff --git a/pyccel/codegen/printing/pycode.py b/pyccel/codegen/printing/pycode.py index 639ec07e30..7805261bbc 100644 --- a/pyccel/codegen/printing/pycode.py +++ b/pyccel/codegen/printing/pycode.py @@ -409,7 +409,12 @@ def _print_PythonPrint(self, expr): return 'print({})\n'.format(', '.join(self._print(a) for a in expr.expr)) def _print_PythonRound(self, expr): - return 'round({})'.format(self._print(expr.arg)) + arg = self._print(expr.arg) + if self.ndigits: + ndigits = self._print(self.ndigits) + return f'round({arg}, {ndigits})' + else: + return f'round({arg})' def _print_PyccelArraySize(self, expr): arg = self._print(expr.arg) From e6524df70e6ce693fcebb8b68bbe0dbe0cdc2e30 Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Sat, 16 Jul 2022 11:21:37 +0200 Subject: [PATCH 15/31] Prevent bench trigger --- .github/workflows/bench.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 789cbab4ec..8700cc3925 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -2,7 +2,7 @@ name: Benchmarks on: push: - branches: [ master ] + branches: [ pyccel:master ] jobs: From 0e5a57f7b303605762dfe2827b037786bb6d5416 Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Sat, 16 Jul 2022 11:36:57 +0200 Subject: [PATCH 16/31] Correct typo --- pyccel/codegen/printing/ccode.py | 2 +- pyccel/codegen/printing/fcode.py | 2 +- pyccel/codegen/printing/pycode.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pyccel/codegen/printing/ccode.py b/pyccel/codegen/printing/ccode.py index 78c6484d94..90ef40f8c1 100644 --- a/pyccel/codegen/printing/ccode.py +++ b/pyccel/codegen/printing/ccode.py @@ -516,7 +516,7 @@ def _print_PythonAbs(self, expr): return "{}({})".format(func, self._print(expr.arg)) def _print_PythonRound(self, expr): - if self.ndigits is None: + if expr.ndigits is None: self.add_import(c_imports['math']) arg = self._print(expr.arg) return f"round({arg})" diff --git a/pyccel/codegen/printing/fcode.py b/pyccel/codegen/printing/fcode.py index 3752496eda..37cb454bb0 100644 --- a/pyccel/codegen/printing/fcode.py +++ b/pyccel/codegen/printing/fcode.py @@ -766,7 +766,7 @@ def _print_PythonRound(self, expr): """ print the python builtin function round args : variable """ - if self.ndigits is None: + if expr.ndigits is None: arg = self._print(expr.arg) return f"nint({arg})" else: diff --git a/pyccel/codegen/printing/pycode.py b/pyccel/codegen/printing/pycode.py index 7805261bbc..ff34c20a34 100644 --- a/pyccel/codegen/printing/pycode.py +++ b/pyccel/codegen/printing/pycode.py @@ -410,8 +410,8 @@ def _print_PythonPrint(self, expr): def _print_PythonRound(self, expr): arg = self._print(expr.arg) - if self.ndigits: - ndigits = self._print(self.ndigits) + if expr.ndigits: + ndigits = self._print(expr.ndigits) return f'round({arg}, {ndigits})' else: return f'round({arg})' From a581983422f7c391996dc209b5d639a4f24cdbb1 Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Sat, 16 Jul 2022 12:26:05 +0200 Subject: [PATCH 17/31] Use banker's round --- pyccel/ast/builtins.py | 1 - pyccel/codegen/printing/ccode.py | 2 +- pyccel/codegen/printing/fcode.py | 3 ++- pyccel/stdlib/math/pyc_math_f90.f90 | 30 ++++++++++++++++++++++++++++- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/pyccel/ast/builtins.py b/pyccel/ast/builtins.py index c81c09c89d..7198fad788 100644 --- a/pyccel/ast/builtins.py +++ b/pyccel/ast/builtins.py @@ -389,7 +389,6 @@ def ndigits(self): """ return self._ndigits - @property def get_round_with_0_digits(self): """ Get expression returning the same value but containing a call to PyccelRound with ndigits=None diff --git a/pyccel/codegen/printing/ccode.py b/pyccel/codegen/printing/ccode.py index 90ef40f8c1..abd338d7c7 100644 --- a/pyccel/codegen/printing/ccode.py +++ b/pyccel/codegen/printing/ccode.py @@ -519,7 +519,7 @@ def _print_PythonRound(self, expr): if expr.ndigits is None: self.add_import(c_imports['math']) arg = self._print(expr.arg) - return f"round({arg})" + return f"lrint({arg})" else: return self._print(expr.get_round_with_0_digits()) diff --git a/pyccel/codegen/printing/fcode.py b/pyccel/codegen/printing/fcode.py index 37cb454bb0..406d101cc4 100644 --- a/pyccel/codegen/printing/fcode.py +++ b/pyccel/codegen/printing/fcode.py @@ -768,7 +768,8 @@ def _print_PythonRound(self, expr): """ if expr.ndigits is None: arg = self._print(expr.arg) - return f"nint({arg})" + self._additional_imports.add(Import('pyc_math_f90', Module('pyc_math_f90',(),()))) + return f"pyc_bankers_round({arg})" else: return self._print(expr.get_round_with_0_digits()) diff --git a/pyccel/stdlib/math/pyc_math_f90.f90 b/pyccel/stdlib/math/pyc_math_f90.f90 index d413df6083..a4472ab945 100644 --- a/pyccel/stdlib/math/pyc_math_f90.f90 +++ b/pyccel/stdlib/math/pyc_math_f90.f90 @@ -5,10 +5,12 @@ module pyc_math_f90 -use ISO_C_BINDING +use, intrinsic :: ISO_C_BINDING implicit none +private + real(C_DOUBLE), parameter, private :: pi = 4.0_C_DOUBLE * DATAN(1.0_C_DOUBLE) interface pyc_gcd @@ -26,6 +28,13 @@ module pyc_math_f90 module procedure pyc_lcm_8 end interface pyc_lcm +public :: pyc_gcd, & + pyc_factorial, & + pyc_lcm, & + pyc_radians, & + pyc_degrees, & + pyc_bankers_round + contains ! Implementation of math factorial function @@ -156,4 +165,23 @@ pure function pyc_degrees(rad) result(deg) end function pyc_degrees +pure function pyc_bankers_round(arg) result(rnd) + + implicit none + + real(C_DOUBLE), value :: arg + integer(C_INT64_T) :: rnd + + real(C_DOUBLE) :: diff + + rnd = nint(arg, kind=C_INT64_T) + + diff = arg - rnd + + if (diff == 0.5_C_DOUBLE .or. diff == -0.5_C_DOUBLE) then + rnd = nint(arg*0.5_C_DOUBLE, kind=C_INT64_T)*2_C_INT64_T + end if + +end function pyc_bankers_round + end module pyc_math_f90 From 5ac8200e0b7e059c36f755f7db7bef8e53ad679f Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Sat, 16 Jul 2022 13:23:23 +0200 Subject: [PATCH 18/31] Match python behaviour --- pyccel/stdlib/math/pyc_math_f90.f90 | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pyccel/stdlib/math/pyc_math_f90.f90 b/pyccel/stdlib/math/pyc_math_f90.f90 index a4472ab945..95a2cf1c4c 100644 --- a/pyccel/stdlib/math/pyc_math_f90.f90 +++ b/pyccel/stdlib/math/pyc_math_f90.f90 @@ -165,23 +165,28 @@ pure function pyc_degrees(rad) result(deg) end function pyc_degrees -pure function pyc_bankers_round(arg) result(rnd) +pure function pyc_bankers_round(arg, ndigits) result(rnd) implicit none real(C_DOUBLE), value :: arg - integer(C_INT64_T) :: rnd + integer(C_INT64_T), value :: ndigits + real(C_DOUBLE) :: rnd real(C_DOUBLE) :: diff + arg = arg * 10._C_DOUBLE**ndigits + rnd = nint(arg, kind=C_INT64_T) diff = arg - rnd - if (diff == 0.5_C_DOUBLE .or. diff == -0.5_C_DOUBLE) then + if (ndigits <= 0 .and. (diff == 0.5_C_DOUBLE .or. diff == -0.5_C_DOUBLE)) then rnd = nint(arg*0.5_C_DOUBLE, kind=C_INT64_T)*2_C_INT64_T end if + rnd = rnd * 10._C_DOUBLE**(-ndigits) + end function pyc_bankers_round end module pyc_math_f90 From d24bb621f6c7e09007f652798bfd6f65116e6833 Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Sat, 16 Jul 2022 13:23:40 +0200 Subject: [PATCH 19/31] Typo. Missing import --- pyccel/ast/builtins.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyccel/ast/builtins.py b/pyccel/ast/builtins.py index 7198fad788..40ef3c9263 100644 --- a/pyccel/ast/builtins.py +++ b/pyccel/ast/builtins.py @@ -22,7 +22,7 @@ from .literals import LiteralInteger, LiteralFloat, LiteralComplex, Nil from .literals import Literal, LiteralImaginaryUnit, get_default_literal_value from .literals import LiteralString -from .operators import PyccelAdd, PyccelAnd, PyccelMul, PyccelIsNot +from .operators import PyccelAdd, PyccelAnd, PyccelMul, PyccelIsNot, PyccelDiv from .operators import PyccelMinus, PyccelUnarySub, PyccelNot, PyccelPow from .variable import IndexedElement @@ -395,7 +395,7 @@ def get_round_with_0_digits(self): """ assert self.ndigits is not None factor = PyccelPow(LiteralFloat(10), self.ndigits) - return PyccelDiv(PyccelRound(PyccelMul(self.arg, factor)), factor) + return PyccelDiv(PythonRound(PyccelMul(self.arg, factor)), factor) #============================================================================== class PythonInt(PyccelAstNode): From cadd954e6d1e0f0253e00794afe5de15638af72e Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Sat, 16 Jul 2022 13:24:42 +0200 Subject: [PATCH 20/31] Use pyc_bankers_round with ndigits argument --- pyccel/codegen/printing/fcode.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pyccel/codegen/printing/fcode.py b/pyccel/codegen/printing/fcode.py index 406d101cc4..1c4db108e3 100644 --- a/pyccel/codegen/printing/fcode.py +++ b/pyccel/codegen/printing/fcode.py @@ -766,12 +766,15 @@ def _print_PythonRound(self, expr): """ print the python builtin function round args : variable """ - if expr.ndigits is None: - arg = self._print(expr.arg) - self._additional_imports.add(Import('pyc_math_f90', Module('pyc_math_f90',(),()))) - return f"pyc_bankers_round({arg})" + arg = self._print(expr.arg) + self._additional_imports.add(Import('pyc_math_f90', Module('pyc_math_f90',(),()))) + if expr.ndigits: + ndigits = self._print(expr.ndigits) + return f"pyc_bankers_round({arg}, {ndigits})" else: - return self._print(expr.get_round_with_0_digits()) + prec = self.print_kind(expr) + zero = self._print(LiteralInteger(0)) + return f"Int(pyc_bankers_round({arg}, {zero}), kind={prec})" def _print_PythonTuple(self, expr): shape = tuple(reversed(expr.shape)) From 0a3f405ada928c7b4da2ea899651b931dd49ea52 Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Sat, 16 Jul 2022 13:24:54 +0200 Subject: [PATCH 21/31] Add tests. Add failing test in C --- tests/epyccel/test_epyccel_round.py | 82 +++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/tests/epyccel/test_epyccel_round.py b/tests/epyccel/test_epyccel_round.py index 9c10c6eea8..7456f34e70 100644 --- a/tests/epyccel/test_epyccel_round.py +++ b/tests/epyccel/test_epyccel_round.py @@ -1,11 +1,13 @@ # pylint: disable=missing-function-docstring, missing-module-docstring/ +import pytest +import numpy as np from numpy.random import randint from pyccel.decorators import types from pyccel.epyccel import epyccel def test_round_int(language): - @types('real') + @types('float') def round_int(x): return round(x) @@ -42,7 +44,7 @@ def round_int(x): assert isinstance(f_output, type(round_int_output)) def test_negative_round_int(language): - @types('real') + @types('float') def round_int(x): return round(x) @@ -78,4 +80,78 @@ def round_int(x): assert round_int_output == f_output assert isinstance(f_output, type(round_int_output)) -#TODO: Add float tests +def test_round_ndigits(language): + @types('float','int') + def round_ndigits(x, i): + return round(x,i) + + f = epyccel(round_ndigits, language=language, developer_mode=True) + x = randint(100) / 10 + + f_output = f(x, 1) + round_ndigits_output = round_ndigits(x, 1) + assert np.isclose(round_ndigits_output, f_output) + assert isinstance(f_output, type(round_ndigits_output)) + + x = 3.343 + + f_output = f(x,2) + round_ndigits_output = round_ndigits(x,2) + assert np.isclose(round_ndigits_output, f_output) + assert isinstance(f_output, type(round_ndigits_output)) + + x = 3323.0 + + f_output = f(x,-2) + round_ndigits_output = round_ndigits(x, -2) + assert np.isclose(round_ndigits_output, f_output) + assert isinstance(f_output, type(round_ndigits_output)) + + x = -3390.0 + + f_output = f(x,-2) + round_ndigits_output = round_ndigits(x, -2) + assert np.isclose(round_ndigits_output, f_output) + assert isinstance(f_output, type(round_ndigits_output)) + +@pytest.mark.parametrize( 'language', ( + pytest.param('fortran', marks = pytest.mark.fortran), + pytest.param('c', marks = [ + pytest.mark.xfail(reason="Python implements bankers' round. But only for ndigits=0"), + pytest.mark.c]), + pytest.param('python', marks = pytest.mark.python), + ) +) +def test_round_ndigits_half(language): + @types('float','int') + def round_ndigits(x, i): + return round(x,i) + + f = epyccel(round_ndigits, language=language, developer_mode=True) + x = randint(100) / 10 + + f_output = f(x, 1) + round_ndigits_output = round_ndigits(x, 1) + assert np.isclose(round_ndigits_output, f_output) + assert isinstance(f_output, type(round_ndigits_output)) + + x = 3.345 + + f_output = f(x,2) + round_ndigits_output = round_ndigits(x,2) + assert np.isclose(round_ndigits_output, f_output) + assert isinstance(f_output, type(round_ndigits_output)) + + x = -3350.0 + + f_output = f(x,-2) + round_ndigits_output = round_ndigits(x, -2) + assert np.isclose(round_ndigits_output, f_output) + assert isinstance(f_output, type(round_ndigits_output)) + + x = 45.0 + + f_output = f(x,-1) + round_ndigits_output = round_ndigits(x,-1) + assert np.isclose(round_ndigits_output, f_output) + assert isinstance(f_output, type(round_ndigits_output)) From 8993b892c6ec84155b6598ca2c5ee5548ff9aaea Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Sat, 16 Jul 2022 13:42:34 +0200 Subject: [PATCH 22/31] Remove debugging info --- tests/epyccel/test_epyccel_round.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/epyccel/test_epyccel_round.py b/tests/epyccel/test_epyccel_round.py index 7456f34e70..aa0e3fb023 100644 --- a/tests/epyccel/test_epyccel_round.py +++ b/tests/epyccel/test_epyccel_round.py @@ -11,7 +11,7 @@ def test_round_int(language): def round_int(x): return round(x) - f = epyccel(round_int, language=language, developer_mode=True) + f = epyccel(round_int, language=language) x = randint(100) / 10 f_output = f(x) @@ -48,7 +48,7 @@ def test_negative_round_int(language): def round_int(x): return round(x) - f = epyccel(round_int, language=language, developer_mode=True) + f = epyccel(round_int, language=language) x = -randint(100) / 10 f_output = f(x) @@ -85,7 +85,7 @@ def test_round_ndigits(language): def round_ndigits(x, i): return round(x,i) - f = epyccel(round_ndigits, language=language, developer_mode=True) + f = epyccel(round_ndigits, language=language) x = randint(100) / 10 f_output = f(x, 1) @@ -127,7 +127,7 @@ def test_round_ndigits_half(language): def round_ndigits(x, i): return round(x,i) - f = epyccel(round_ndigits, language=language, developer_mode=True) + f = epyccel(round_ndigits, language=language) x = randint(100) / 10 f_output = f(x, 1) From 1870ec2a7c89f733296408c69bddc6a438c317d9 Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Sat, 16 Jul 2022 13:44:40 +0200 Subject: [PATCH 23/31] Ensure developer mode is temporary --- pyccel/commands/console.py | 8 +++++--- pyccel/epyccel.py | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pyccel/commands/console.py b/pyccel/commands/console.py index 22e9f8afd9..23c7499802 100644 --- a/pyccel/commands/console.py +++ b/pyccel/commands/console.py @@ -221,11 +221,13 @@ def pyccel(files=None, mpi=None, openmp=None, openacc=None, output_dir=None, com # ... # ... + # this will initialize the singelton ErrorsMode + # making this settings available everywhere + err_mode = ErrorsMode() if args.developer_mode: - # this will initialize the singelton ErrorsMode - # making this settings available everywhere - err_mode = ErrorsMode() err_mode.set_mode('developer') + else: + err_mode.set_mode('user') # ... base_dirpath = os.getcwd() diff --git a/pyccel/epyccel.py b/pyccel/epyccel.py index fecc7cca52..1548198bf4 100644 --- a/pyccel/epyccel.py +++ b/pyccel/epyccel.py @@ -264,11 +264,13 @@ def epyccel( python_function_or_module, **kwargs ): comm = kwargs.pop('comm', None) root = kwargs.pop('root', 0) bcast = kwargs.pop('bcast', True) + # This will initialize the singleton ErrorsMode + # making this setting available everywhere + err_mode = ErrorsMode() if kwargs.pop('developer_mode', None): - # This will initialize the singleton ErrorsMode - # making this setting available everywhere - err_mode = ErrorsMode() err_mode.set_mode('developer') + else: + err_mode.set_mode('user') # Parallel version if comm is not None: From f8ce870216dfed4c35bae41896e356394d63f034 Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Sat, 16 Jul 2022 14:25:26 +0200 Subject: [PATCH 24/31] Make into interface --- pyccel/stdlib/math/pyc_math_f90.f90 | 33 +++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/pyccel/stdlib/math/pyc_math_f90.f90 b/pyccel/stdlib/math/pyc_math_f90.f90 index 95a2cf1c4c..2d9d49043f 100644 --- a/pyccel/stdlib/math/pyc_math_f90.f90 +++ b/pyccel/stdlib/math/pyc_math_f90.f90 @@ -28,6 +28,11 @@ module pyc_math_f90 module procedure pyc_lcm_8 end interface pyc_lcm +interface pyc_bankers_round + module procedure pyc_bankers_round_4 + module procedure pyc_bankers_round_8 +end interface pyc_bankers_round + public :: pyc_gcd, & pyc_factorial, & pyc_lcm, & @@ -165,7 +170,31 @@ pure function pyc_degrees(rad) result(deg) end function pyc_degrees -pure function pyc_bankers_round(arg, ndigits) result(rnd) +pure function pyc_bankers_round_4(arg, ndigits) result(rnd) + + implicit none + + real(C_DOUBLE), value :: arg + integer(C_INT32_T), value :: ndigits + real(C_DOUBLE) :: rnd + + real(C_DOUBLE) :: diff + + arg = arg * 10._C_DOUBLE**ndigits + + rnd = nint(arg, kind=C_INT64_T) + + diff = arg - rnd + + if (ndigits <= 0 .and. (diff == 0.5_C_DOUBLE .or. diff == -0.5_C_DOUBLE)) then + rnd = nint(arg*0.5_C_DOUBLE, kind=C_INT64_T)*2_C_INT64_T + end if + + rnd = rnd * 10._C_DOUBLE**(-ndigits) + +end function pyc_bankers_round_4 + +pure function pyc_bankers_round_8(arg, ndigits) result(rnd) implicit none @@ -187,6 +216,6 @@ pure function pyc_bankers_round(arg, ndigits) result(rnd) rnd = rnd * 10._C_DOUBLE**(-ndigits) -end function pyc_bankers_round +end function pyc_bankers_round_8 end module pyc_math_f90 From af5f14731a4a2a14f757e2dc94c18738c889037a Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Sat, 16 Jul 2022 18:19:33 +0200 Subject: [PATCH 25/31] Simplify statement --- pyccel/ast/builtins.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyccel/ast/builtins.py b/pyccel/ast/builtins.py index 40ef3c9263..d358926782 100644 --- a/pyccel/ast/builtins.py +++ b/pyccel/ast/builtins.py @@ -370,10 +370,9 @@ def __init__(self, number, ndigits = None): self._arg = number if ndigits is None: self._dtype = NativeInteger() - self._ndigits = None else: self._dtype = NativeFloat() - self._ndigits = ndigits + self._ndigits = ndigits self._precision = -1 super().__init__() From a087bac20c64e055240048560608b2b43dce6066 Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Wed, 20 Jul 2022 12:32:12 +0200 Subject: [PATCH 26/31] Correct expected dtype --- pyccel/ast/builtins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyccel/ast/builtins.py b/pyccel/ast/builtins.py index d358926782..6a2e4770b4 100644 --- a/pyccel/ast/builtins.py +++ b/pyccel/ast/builtins.py @@ -371,7 +371,7 @@ def __init__(self, number, ndigits = None): if ndigits is None: self._dtype = NativeInteger() else: - self._dtype = NativeFloat() + self._dtype = number.dtype self._ndigits = ndigits self._precision = -1 super().__init__() From 95017a88fb76e47b3aa1eb03affff988f053fba1 Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Wed, 20 Jul 2022 12:32:26 +0200 Subject: [PATCH 27/31] Add missing functions --- pyccel/stdlib/math/pyc_math_f90.f90 | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/pyccel/stdlib/math/pyc_math_f90.f90 b/pyccel/stdlib/math/pyc_math_f90.f90 index 2d9d49043f..13fdfa8983 100644 --- a/pyccel/stdlib/math/pyc_math_f90.f90 +++ b/pyccel/stdlib/math/pyc_math_f90.f90 @@ -31,6 +31,8 @@ module pyc_math_f90 interface pyc_bankers_round module procedure pyc_bankers_round_4 module procedure pyc_bankers_round_8 + module procedure pyc_bankers_round_int_4 + module procedure pyc_bankers_round_int_8 end interface pyc_bankers_round public :: pyc_gcd, & @@ -218,4 +220,40 @@ pure function pyc_bankers_round_8(arg, ndigits) result(rnd) end function pyc_bankers_round_8 +pure function pyc_bankers_round_int_4(arg, ndigits) result(rnd) + + implicit none + + integer(C_INT32_T), value :: arg + integer(C_INT32_T), value :: ndigits + integer(C_INT32_T) :: rnd + + real(C_DOUBLE) :: val + + val = arg * 10._C_DOUBLE**ndigits + + rnd = nint(val, kind=C_INT64_T) + + rnd = rnd * 10._C_DOUBLE**(-ndigits) + +end function pyc_bankers_round_int_4 + +pure function pyc_bankers_round_int_8(arg, ndigits) result(rnd) + + implicit none + + integer(C_INT64_T), value :: arg + integer(C_INT64_T), value :: ndigits + integer(C_INT64_T) :: rnd + + real(C_DOUBLE) :: val + + val = arg * 10._C_DOUBLE**ndigits + + rnd = nint(val, kind=C_INT64_T) + + rnd = rnd * 10._C_DOUBLE**(-ndigits) + +end function pyc_bankers_round_int_8 + end module pyc_math_f90 From 09ac6cc9bc64dde50684dc629f65ea4574349e6c Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Wed, 20 Jul 2022 12:33:46 +0200 Subject: [PATCH 28/31] Add int tests --- tests/epyccel/test_epyccel_round.py | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/epyccel/test_epyccel_round.py b/tests/epyccel/test_epyccel_round.py index aa0e3fb023..8dcae13317 100644 --- a/tests/epyccel/test_epyccel_round.py +++ b/tests/epyccel/test_epyccel_round.py @@ -155,3 +155,37 @@ def round_ndigits(x, i): round_ndigits_output = round_ndigits(x,-1) assert np.isclose(round_ndigits_output, f_output) assert isinstance(f_output, type(round_ndigits_output)) + +def test_round_ndigits_int(language): + @types('int','int') + def round_ndigits(x, i): + return round(x,i) + + f = epyccel(round_ndigits, language=language) + x = randint(100) // 10 + + f_output = f(x, 1) + round_ndigits_output = round_ndigits(x, 1) + assert np.isclose(round_ndigits_output, f_output) + assert isinstance(f_output, type(round_ndigits_output)) + + x = 3 + + f_output = f(x,2) + round_ndigits_output = round_ndigits(x,2) + assert np.isclose(round_ndigits_output, f_output) + assert isinstance(f_output, type(round_ndigits_output)) + + x = 3323 + + f_output = f(x,-2) + round_ndigits_output = round_ndigits(x, -2) + assert np.isclose(round_ndigits_output, f_output) + assert isinstance(f_output, type(round_ndigits_output)) + + x = -3390 + + f_output = f(x,-2) + round_ndigits_output = round_ndigits(x, -2) + assert np.isclose(round_ndigits_output, f_output) + assert isinstance(f_output, type(round_ndigits_output)) From 55d95a281889723dff4c0eb2db051c5aae89c57b Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Wed, 20 Jul 2022 12:37:24 +0200 Subject: [PATCH 29/31] Handle unexpected precision --- pyccel/codegen/printing/fcode.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pyccel/codegen/printing/fcode.py b/pyccel/codegen/printing/fcode.py index 739bd61dc5..b4540fdc4c 100644 --- a/pyccel/codegen/printing/fcode.py +++ b/pyccel/codegen/printing/fcode.py @@ -765,8 +765,12 @@ def _print_PythonRound(self, expr): """ print the python builtin function round args : variable """ - arg = self._print(expr.arg) + arg = expr.arg self._additional_imports.add(Import('pyc_math_f90', Module('pyc_math_f90',(),()))) + if arg.dtype != -1: + arg = DtypePrecisionToCastFunction[arg.dtype.name][arg.precision] + + arg_code = self._print(arg) if expr.ndigits: ndigits = self._print(expr.ndigits) return f"pyc_bankers_round({arg}, {ndigits})" From a4a947f22f7390b59efae6cea1445a2008c213b3 Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Wed, 20 Jul 2022 12:39:04 +0200 Subject: [PATCH 30/31] Correct cast --- pyccel/codegen/printing/fcode.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pyccel/codegen/printing/fcode.py b/pyccel/codegen/printing/fcode.py index b4540fdc4c..1d18989bf2 100644 --- a/pyccel/codegen/printing/fcode.py +++ b/pyccel/codegen/printing/fcode.py @@ -766,18 +766,22 @@ def _print_PythonRound(self, expr): args : variable """ arg = expr.arg + ndigits = expr.ndigits self._additional_imports.add(Import('pyc_math_f90', Module('pyc_math_f90',(),()))) - if arg.dtype != -1: + if arg.prec != -1: arg = DtypePrecisionToCastFunction[arg.dtype.name][arg.precision] arg_code = self._print(arg) - if expr.ndigits: - ndigits = self._print(expr.ndigits) - return f"pyc_bankers_round({arg}, {ndigits})" + if ndigits: + if ndigits.prec != -1: + ndigits = DtypePrecisionToCastFunction[ndigits.dtype.name][ndigits.precision] + + ndigits_code = self._print(ndigits) + return f"pyc_bankers_round({arg_code}, {ndigits_code})" else: prec = self.print_kind(expr) zero = self._print(LiteralInteger(0)) - return f"Int(pyc_bankers_round({arg}, {zero}), kind={prec})" + return f"Int(pyc_bankers_round({arg_code}, {zero}), kind={prec})" def _print_PythonTuple(self, expr): shape = tuple(reversed(expr.shape)) From c279c5290109ba81a1dbffceadf342f4a58cea82 Mon Sep 17 00:00:00 2001 From: EmilyBoune Date: Wed, 20 Jul 2022 13:51:43 +0200 Subject: [PATCH 31/31] Correct stupid typo --- pyccel/codegen/printing/fcode.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyccel/codegen/printing/fcode.py b/pyccel/codegen/printing/fcode.py index 1d18989bf2..a4166eb9df 100644 --- a/pyccel/codegen/printing/fcode.py +++ b/pyccel/codegen/printing/fcode.py @@ -768,12 +768,12 @@ def _print_PythonRound(self, expr): arg = expr.arg ndigits = expr.ndigits self._additional_imports.add(Import('pyc_math_f90', Module('pyc_math_f90',(),()))) - if arg.prec != -1: + if arg.precision != -1: arg = DtypePrecisionToCastFunction[arg.dtype.name][arg.precision] arg_code = self._print(arg) if ndigits: - if ndigits.prec != -1: + if ndigits.precision != -1: ndigits = DtypePrecisionToCastFunction[ndigits.dtype.name][ndigits.precision] ndigits_code = self._print(ndigits)