diff options
author | Damien George <damien.p.george@gmail.com> | 2014-04-04 00:16:32 +0100 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2014-04-04 00:16:32 +0100 |
commit | 5bf565e353b73bc87e0b918368dadac701644078 (patch) | |
tree | 21efe4ac810f703902bfe05259c0fe3f63581526 | |
parent | 4b34c76fd6040bb0332923165fcfaf8c85b5dac6 (diff) | |
download | micropython-5bf565e353b73bc87e0b918368dadac701644078.tar.gz micropython-5bf565e353b73bc87e0b918368dadac701644078.zip |
py: Handle small int power overflow correctly.
-rw-r--r-- | py/mpz.c | 5 | ||||
-rw-r--r-- | py/runtime.c | 20 |
2 files changed, 22 insertions, 3 deletions
@@ -993,8 +993,11 @@ void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) { if (mpz_is_odd(n)) { mpz_mul_inpl(dest, dest, x); } - mpz_mul_inpl(x, x, x); n->len = mpn_shr(n->dig, n->dig, n->len, 1); + if (n->len == 0) { + break; + } + mpz_mul_inpl(x, x, x); } mpz_free(x); diff --git a/py/runtime.c b/py/runtime.c index e2e3495648..d9e2298c4c 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -367,18 +367,34 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "negative power with no float support")); #endif } else { - // TODO check for overflow machine_int_t ans = 1; while (rhs_val > 0) { if (rhs_val & 1) { + machine_int_t old = ans; ans *= lhs_val; + if (ans < old) { + goto power_overflow; + } + } + if (rhs_val == 1) { + break; } - lhs_val *= lhs_val; rhs_val /= 2; + machine_int_t old = lhs_val; + lhs_val *= lhs_val; + if (lhs_val < old) { + goto power_overflow; + } } lhs_val = ans; } break; + + power_overflow: + // use higher precision + lhs = mp_obj_new_int_from_ll(MP_OBJ_SMALL_INT_VALUE(lhs)); + goto generic_binary_op; + case MP_BINARY_OP_LESS: return MP_BOOL(lhs_val < rhs_val); break; case MP_BINARY_OP_MORE: return MP_BOOL(lhs_val > rhs_val); break; case MP_BINARY_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val); break; |