From 2d15deebdcf7d6fb8f78907e0c6ca9cb9c2aa000 Mon Sep 17 00:00:00 2001 From: Rachel Dowdall Date: Sat, 22 Mar 2014 20:29:56 +0000 Subject: [PATCH] Fixed floor division on mp ints and small ints. Added a floordivide test case. --- py/compile.c | 10 ++++++---- py/intdivmod.c | 24 ++++++++++++++++++++++++ py/intdivmod.h | 4 ++++ py/objint_mpz.c | 11 +++++++++-- py/runtime.c | 7 ++++++- tests/basics/floordivide.py | 29 +++++++++++++++++++++++++++++ tests/basics/modulo.py | 17 +++++++++++++++-- 7 files changed, 93 insertions(+), 9 deletions(-) create mode 100644 py/intdivmod.c create mode 100644 py/intdivmod.h create mode 100644 tests/basics/floordivide.py diff --git a/py/compile.c b/py/compile.c index 4eab094230..0a10b81768 100644 --- a/py/compile.c +++ b/py/compile.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "misc.h" #include "mpconfig.h" @@ -141,12 +142,13 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) { } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_SLASH)) { ; // 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, 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); + //pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, + // floor((mp_float_t)arg0 / arg1)); + pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, + python_floor_divide(arg0, arg1)); + } else { // shouldn't happen assert(0); diff --git a/py/intdivmod.c b/py/intdivmod.c new file mode 100644 index 0000000000..4cb363b511 --- /dev/null +++ b/py/intdivmod.c @@ -0,0 +1,24 @@ +#include "mpconfig.h" + +machine_int_t python_modulo(machine_int_t dividend, machine_int_t divisor) { + machine_int_t lsign = (dividend >= 0) ? 1 :-1; + machine_int_t rsign = (divisor >= 0) ? 1 :-1; + dividend %= divisor; + if (lsign != rsign) { + dividend += divisor; + } + return dividend; +} + + +machine_int_t python_floor_divide(machine_int_t num, machine_int_t denom) { + machine_int_t lsign = num > 0 ? 1 : -1; + machine_int_t rsign = denom > 0 ? 1 : -1; + if (lsign == -1) {num *= -1;} + if (rsign == -1) {denom *= -1;} + if (lsign != rsign){ + return - ( num + denom - 1) / denom; + } else { + return num / denom; + } +} diff --git a/py/intdivmod.h b/py/intdivmod.h new file mode 100644 index 0000000000..7716bd21e9 --- /dev/null +++ b/py/intdivmod.h @@ -0,0 +1,4 @@ +// Functions for integer modulo and floor division + +machine_int_t python_modulo(machine_int_t dividend, machine_int_t divisor); +machine_int_t python_floor_divide(machine_int_t num, machine_int_t denom); diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 9c7727ba42..39ea7ca115 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -1,5 +1,6 @@ #include #include +#include #include "nlr.h" #include "misc.h" @@ -97,6 +98,12 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { case RT_BINARY_OP_INPLACE_FLOOR_DIVIDE: { mpz_t rem; mpz_init_zero(&rem); mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs); + if (zlhs->neg != zrhs->neg) { + if (!mpz_is_zero(&rem)) { + mpz_t mpzone; mpz_init_from_int(&mpzone, -1); + mpz_add_inpl(&res->mpz, &res->mpz, &mpzone); + } + } mpz_deinit(&rem); break; } @@ -105,8 +112,8 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { 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) { + // 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/runtime.c b/py/runtime.c index 95c3a44159..94f3190566 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "nlr.h" #include "misc.h" @@ -661,7 +662,11 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { break; } case RT_BINARY_OP_FLOOR_DIVIDE: - case RT_BINARY_OP_INPLACE_FLOOR_DIVIDE: lhs_val /= rhs_val; break; + case RT_BINARY_OP_INPLACE_FLOOR_DIVIDE: + { + lhs_val = python_floor_divide(lhs_val, rhs_val); + break; + } #if MICROPY_ENABLE_FLOAT case RT_BINARY_OP_TRUE_DIVIDE: case RT_BINARY_OP_INPLACE_TRUE_DIVIDE: return mp_obj_new_float((mp_float_t)lhs_val / (mp_float_t)rhs_val); diff --git a/tests/basics/floordivide.py b/tests/basics/floordivide.py new file mode 100644 index 0000000000..930313d6c1 --- /dev/null +++ b/tests/basics/floordivide.py @@ -0,0 +1,29 @@ +# check modulo matches python definition + +# This tests compiler version +print(123 // 7) +print(-123 // 7) +print(123 // -7) +print(-123 // -7) + +a = 10000001 +b = 10000000 +print(a // b) +print(a // -b) +print(-a // b) +print(-a // -b) + +if True: + a = 987654321987987987987987987987 + b = 19 + + print(a // b) + print(a // -b) + print(-a // b) + print(-a // -b) + a = 10000000000000000000000000000000000000000000 + b = 100 + print(a // b) + print(a // -b) + print(-a // b) + print(-a // -b) diff --git a/tests/basics/modulo.py b/tests/basics/modulo.py index ce7ed2578c..4d83db6ec8 100644 --- a/tests/basics/modulo.py +++ b/tests/basics/modulo.py @@ -1,5 +1,5 @@ # check modulo matches python definition - +# This test compiler version print(123 % 7) print(-123 % 7) print(123 % -7) @@ -7,7 +7,6 @@ print(-123 % -7) a = 321 b = 19 - print(a % b) print(a % -b) print(-a % b) @@ -21,3 +20,17 @@ print(a % b) print(a % -b) print(-a % b) print(-a % -b) + +if False: + print(1.23456 % 0.7) + print(-1.23456 % 0.7) + print(1.23456 % -0.7) + print(-1.23456 % -0.7) + + a = 1.23456 + b = 0.7 + print(a % b) + print(a % -b) + print(-a % b) + print(-a % -b) +