summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2017-07-25 11:49:22 +1000
committerDamien George <damien.p.george@gmail.com>2017-07-25 11:49:22 +1000
commit04552ff71b6c722b21597d93481f024c72457cef (patch)
treefdbc66843e079a78cbf964aa6308ab5db78a42d1
parent4d1fb6107fdedb0dda8dfb1491c033bf731222c6 (diff)
downloadmicropython-04552ff71b6c722b21597d93481f024c72457cef.tar.gz
micropython-04552ff71b6c722b21597d93481f024c72457cef.zip
py: Implement raising a big-int to a negative power.
Before this patch raising a big-int to a negative power would just return 0. Now it returns a floating-point number with the correct value.
-rw-r--r--py/mpz.c4
-rw-r--r--py/mpz.h1
-rw-r--r--py/objint_longlong.c7
-rw-r--r--py/objint_mpz.c7
-rw-r--r--tests/float/int_big_float.py4
5 files changed, 19 insertions, 4 deletions
diff --git a/py/mpz.c b/py/mpz.c
index 80473df882..f58e262e23 100644
--- a/py/mpz.c
+++ b/py/mpz.c
@@ -946,10 +946,6 @@ bool mpz_is_pos(const mpz_t *z) {
return z->len > 0 && z->neg == 0;
}
-bool mpz_is_neg(const mpz_t *z) {
- return z->len > 0 && z->neg != 0;
-}
-
bool mpz_is_odd(const mpz_t *z) {
return z->len > 0 && (z->dig[0] & 1) != 0;
}
diff --git a/py/mpz.h b/py/mpz.h
index 2ff404ffa8..55967cc4c3 100644
--- a/py/mpz.h
+++ b/py/mpz.h
@@ -112,6 +112,7 @@ size_t mpz_set_from_str(mpz_t *z, const char *str, size_t len, bool neg, unsigne
void mpz_set_from_bytes(mpz_t *z, bool big_endian, size_t len, const byte *buf);
static inline bool mpz_is_zero(const mpz_t *z) { return z->len == 0; }
+static inline bool mpz_is_neg(const mpz_t *z) { return z->len != 0 && z->neg != 0; }
int mpz_cmp(const mpz_t *lhs, const mpz_t *rhs);
void mpz_abs_inpl(mpz_t *dest, const mpz_t *z);
diff --git a/py/objint_longlong.c b/py/objint_longlong.c
index eb80407bcb..1d184a7dc2 100644
--- a/py/objint_longlong.c
+++ b/py/objint_longlong.c
@@ -191,6 +191,13 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
case MP_BINARY_OP_POWER:
case MP_BINARY_OP_INPLACE_POWER: {
+ if (rhs_val < 0) {
+ #if MICROPY_PY_BUILTINS_FLOAT
+ return mp_obj_float_binary_op(op, lhs_val, rhs_in);
+ #else
+ mp_raise_ValueError("negative power with no float support");
+ #endif
+ }
long long ans = 1;
while (rhs_val > 0) {
if (rhs_val & 1) {
diff --git a/py/objint_mpz.c b/py/objint_mpz.c
index d818b6f407..26492aab48 100644
--- a/py/objint_mpz.c
+++ b/py/objint_mpz.c
@@ -290,6 +290,13 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
case MP_BINARY_OP_POWER:
case MP_BINARY_OP_INPLACE_POWER:
+ if (mpz_is_neg(zrhs)) {
+ #if MICROPY_PY_BUILTINS_FLOAT
+ return mp_obj_float_binary_op(op, mpz_as_float(zlhs), rhs_in);
+ #else
+ mp_raise_ValueError("negative power with no float support");
+ #endif
+ }
mpz_pow_inpl(&res->mpz, zlhs, zrhs);
break;
diff --git a/tests/float/int_big_float.py b/tests/float/int_big_float.py
index b1a26ca73d..0bd1662186 100644
--- a/tests/float/int_big_float.py
+++ b/tests/float/int_big_float.py
@@ -18,6 +18,10 @@ print("%.5g" % (i / 1.2))
# this should delegate to complex
print("%.5g" % (i * 1.2j).imag)
+# negative power should produce float
+print("%.5g" % (i ** -1))
+print("%.5g" % ((2 + i - i) ** -3))
+
try:
i / 0
except ZeroDivisionError: