From 12033df511a5a5f0237a764379aacfbceb6c45dd Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 30 Dec 2014 00:22:10 +0200 Subject: [PATCH] py: Partially fix float to int conversion. This fixes conversion when float type has more mantissa bits than small int, and float value has small exponent. This is for example the case of 32-bit platform using doubles, and converting value of time.time(). Conversion of floats with larg exponnet is still not handled correctly. --- py/obj.h | 1 + py/objint.c | 2 +- py/objint_longlong.c | 12 ++++++++++++ py/objint_mpz.c | 12 ++++++++++++ tests/float/float2int.py | 5 +++++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/float/float2int.py diff --git a/py/obj.h b/py/obj.h index bd4cd31aa0..0c91f8074f 100644 --- a/py/obj.h +++ b/py/obj.h @@ -399,6 +399,7 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value); mp_obj_t mp_obj_new_int_from_str_len(const char **str, mp_uint_t len, bool neg, mp_uint_t base); mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception) mp_obj_t mp_obj_new_int_from_ull(unsigned long long val); // this must return a multi-precision integer object (or raise an overflow exception) +mp_obj_t mp_obj_new_int_from_float(mp_float_t val); mp_obj_t mp_obj_new_str(const char* data, mp_uint_t len, bool make_qstr_if_not_already); mp_obj_t mp_obj_new_bytes(const byte* data, mp_uint_t len); mp_obj_t mp_obj_new_bytearray(mp_uint_t n, void *items); diff --git a/py/objint.c b/py/objint.c index 7f0e2b2506..8f626190ce 100644 --- a/py/objint.c +++ b/py/objint.c @@ -65,7 +65,7 @@ STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_ return mp_parse_num_integer(s, l, 0); #if MICROPY_PY_BUILTINS_FLOAT } else if (MP_OBJ_IS_TYPE(args[0], &mp_type_float)) { - return MP_OBJ_NEW_SMALL_INT((MICROPY_FLOAT_C_FUN(trunc)(mp_obj_float_get(args[0])))); + return mp_obj_new_int_from_float(mp_obj_float_get(args[0])); #endif } else { // try to convert to small int (eg from bool) diff --git a/py/objint_longlong.c b/py/objint_longlong.c index ec55c77849..5f48b71340 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -40,6 +40,10 @@ #include "runtime0.h" #include "runtime.h" +#if MICROPY_PY_BUILTINS_FLOAT +#include +#endif + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG // Python3 no longer has "l" suffix for long ints. We allow to use it @@ -187,6 +191,14 @@ mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { return o; } +#if MICROPY_PY_BUILTINS_FLOAT +mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { + // TODO raise an exception if the unsigned long long won't fit + long long i = MICROPY_FLOAT_C_FUN(trunc)(val); + return mp_obj_new_int_from_ll(i); +} +#endif + mp_obj_t mp_obj_new_int_from_str_len(const char **str, mp_uint_t len, bool neg, mp_uint_t base) { // TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated // TODO check overflow diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 5480bd385d..1dc1def33d 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -41,6 +41,10 @@ #include "runtime0.h" #include "runtime.h" +#if MICROPY_PY_BUILTINS_FLOAT +#include +#endif + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ #if MICROPY_PY_SYS_MAXSIZE @@ -298,6 +302,14 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { return mp_obj_new_int_from_ll(value); } +#if MICROPY_PY_BUILTINS_FLOAT +mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { + // TODO: This doesn't handle numbers with large exponent + long long i = MICROPY_FLOAT_C_FUN(trunc)(val); + return mp_obj_new_int_from_ll(i); +} +#endif + mp_obj_t mp_obj_new_int_from_str_len(const char **str, mp_uint_t len, bool neg, mp_uint_t base) { mp_obj_int_t *o = mp_obj_int_new_mpz(); mp_uint_t n = mpz_set_from_str(&o->mpz, *str, len, neg, base); diff --git a/tests/float/float2int.py b/tests/float/float2int.py new file mode 100644 index 0000000000..59d904e58a --- /dev/null +++ b/tests/float/float2int.py @@ -0,0 +1,5 @@ +# This case occurs with time.time() values +print(int(1418774543.)) + +# TODO: General case with large exponent +#print(int(2.**100))