From ad2307c92c15f0aa90dbd0741fd2538719d0b5e1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 7 Jan 2015 12:10:47 +0000 Subject: [PATCH] py: Temporary fix for conversion of float to int when fits in small int. Addresses issue #1044 (see also #1040). Could do with a better fix. --- py/objint_mpz.c | 3 +++ tests/float/float2int.py | 17 ++++++++++------- tests/float/float2int_doubleprec.py | 21 +++++++++++++++++++++ tests/run-tests | 2 +- 4 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 tests/float/float2int_doubleprec.py diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 49a9a91e25..02b3ec0fe4 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -303,6 +303,9 @@ mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "can't convert inf to int")); } else if (cl == FP_NAN) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "can't convert NaN to int")); + } else if (MICROPY_FLOAT_C_FUN(fabs)(val) < 10000) { + // temporary(?) fix for optimising case where int will be small int + return MP_OBJ_NEW_SMALL_INT(MICROPY_FLOAT_C_FUN(trunc)(val)); } else { mp_obj_int_t *o = mp_obj_int_new_mpz(); mpz_set_from_float(&o->mpz, val); diff --git a/tests/float/float2int.py b/tests/float/float2int.py index 42210b4413..4629642874 100644 --- a/tests/float/float2int.py +++ b/tests/float/float2int.py @@ -1,22 +1,21 @@ -# This case occurs with time.time() values -print(int(1418774543.)) +# check cases converting float to int, relying only on single precision float +print(int(14187745.)) print(int(2.**100)) - -print("%d" % 1418774543.) - +print("%d" % 14187745.) print("%d" % 2.**100) testpass = True -for i in range(0,1024): +for i in range(0,128): bitcnt = len(bin(int(2.**i))) - 3; if i != bitcnt: print('fail: 2**%u was %u bits long' % (i, bitcnt)); testpass = False print("power of 2 test: %s" % (testpass and 'passed' or 'failed')) +# TODO why does 10**12 fail this test for single precision float? testpass = True -for i in range(0,23): +for i in range(0,12): digcnt = len(str(int(10.**i))) - 1; if i != digcnt: print('fail: 10**%u was %u digits long' % (i, digcnt)); @@ -34,3 +33,7 @@ try: int(float('nan')) except ValueError: print("ValueError") + +# test numbers < 1 (this used to fail; see issue #1044) +import struct +struct.pack('I', int(1/2)) diff --git a/tests/float/float2int_doubleprec.py b/tests/float/float2int_doubleprec.py new file mode 100644 index 0000000000..c6fe3783e6 --- /dev/null +++ b/tests/float/float2int_doubleprec.py @@ -0,0 +1,21 @@ +# check cases converting float to int, requiring double precision float + +# This case occurs with time.time() values +print(int(1418774543.)) +print("%d" % 1418774543.) + +testpass = True +for i in range(0,1024): + bitcnt = len(bin(int(2.**i))) - 3; + if i != bitcnt: + print('fail: 2**%u was %u bits long' % (i, bitcnt)); + testpass = False +print("power of 2 test: %s" % (testpass and 'passed' or 'failed')) + +testpass = True +for i in range(0,23): + digcnt = len(str(int(10.**i))) - 1; + if i != digcnt: + print('fail: 10**%u was %u digits long' % (i, digcnt)); + testpass = False +print("power of 10 test: %s" % (testpass and 'passed' or 'failed')) diff --git a/tests/run-tests b/tests/run-tests index 13f584e41f..a88ad4c2b1 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -65,7 +65,7 @@ def run_tests(pyb, tests, args): # Some tests shouldn't be run on pyboard if pyb is not None: skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead - skip_tests.add('float/float2int.py') # requires double precision floating point to work + skip_tests.add('float/float2int_doubleprec.py') # requires double precision floating point to work # Some tests are known to fail on 64-bit machines if pyb is None and platform.architecture()[0] == '64bit':