From cde8631f15db9941986f8d04534e52462a76094b Mon Sep 17 00:00:00 2001 From: Rachel Dowdall Date: Sat, 22 Mar 2014 17:29:27 +0000 Subject: [PATCH] Fixed modulo operator on ints and mp ints to agree with python. Added intdivmod.c and tests/basics/modulo.py. --- py/compile.c | 4 +++- py/objint_mpz.c | 5 ++++- py/py.mk | 1 + py/runtime.c | 9 ++++++--- tests/basics/modulo.py | 23 +++++++++++++++++++++++ 5 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 tests/basics/modulo.py diff --git a/py/compile.c b/py/compile.c index bb688d5d8..4eab09423 100644 --- a/py/compile.c +++ b/py/compile.c @@ -15,6 +15,7 @@ #include "obj.h" #include "compile.h" #include "runtime.h" +#include "intdivmod.h" // TODO need to mangle __attr names @@ -141,7 +142,8 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) { ; // pass } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PERCENT)) { // XXX implement this properly as Python's % operator acts differently to C's - pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 % arg1); + //pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 % arg1); + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, python_modulo(arg0, arg1)); } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_SLASH)) { // XXX implement this properly as Python's // operator acts differently to C's pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 / arg1); diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 21e3202a9..9c7727ba4 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -102,10 +102,13 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } case RT_BINARY_OP_MODULO: case RT_BINARY_OP_INPLACE_MODULO: { - // TODO check that this operation matches the CPython operation mpz_t quo; mpz_init_zero(&quo); mpz_divmod_inpl(&quo, &res->mpz, zlhs, zrhs); mpz_deinit(&quo); + // Check signs and do Python style modulo + if (zlhs->neg != zrhs->neg) { + mpz_add_inpl(&res->mpz, &res->mpz, zrhs); + } break; } diff --git a/py/py.mk b/py/py.mk index 081417681..add871632 100644 --- a/py/py.mk +++ b/py/py.mk @@ -78,6 +78,7 @@ PY_O_BASENAME = \ vm.o \ showbc.o \ repl.o \ + intdivmod.o \ # prepend the build destination prefix to the py object files PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME)) diff --git a/py/runtime.c b/py/runtime.c index 1cc1c2e6b..95c3a4415 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -18,6 +18,7 @@ #include "builtin.h" #include "objarray.h" #include "bc.h" +#include "intdivmod.h" #if 0 // print debugging info #define DEBUG_PRINT (1) @@ -666,10 +667,12 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { case RT_BINARY_OP_INPLACE_TRUE_DIVIDE: return mp_obj_new_float((mp_float_t)lhs_val / (mp_float_t)rhs_val); #endif - // TODO implement modulo as specified by Python case RT_BINARY_OP_MODULO: - case RT_BINARY_OP_INPLACE_MODULO: lhs_val %= rhs_val; break; - + case RT_BINARY_OP_INPLACE_MODULO: + { + lhs_val = python_modulo(lhs_val, rhs_val); + break; + } case RT_BINARY_OP_POWER: case RT_BINARY_OP_INPLACE_POWER: if (rhs_val < 0) { diff --git a/tests/basics/modulo.py b/tests/basics/modulo.py new file mode 100644 index 000000000..ce7ed2578 --- /dev/null +++ b/tests/basics/modulo.py @@ -0,0 +1,23 @@ +# check modulo matches python definition + +print(123 % 7) +print(-123 % 7) +print(123 % -7) +print(-123 % -7) + +a = 321 +b = 19 + +print(a % b) +print(a % -b) +print(-a % b) +print(-a % -b) + + +a = 987654321987987987987987987987 +b = 19 + +print(a % b) +print(a % -b) +print(-a % b) +print(-a % -b)