Closed tdicola closed 6 years ago
this is probably cause it uses 30-bit floats and that number https://www.h-schmidt.net/FloatConverter/IEEE754.html is 0x4e8799bf
@dhalbert if you agree, lets document this in our intro guide as a common 'gotcha'! which uses the second-to-top bit?
Yes, this is a documentation issue, but it's kind of a more general warning about the limited size of integers, which are 31 bits, not 32 bits. So, @tdicola, I think you're saying that there are peripherals that can take full 32-bit integers but those integers can't be dealt with properly. It would even be true if you were using all-integer arithmetic: there'd be no way for you to do that arithmetic and get a value larger than sys.maxsize
(1073741823, 2**30-1). It only has to do with floats because any conversion from a larger float will fail, just like sys.maxsize + 1
would also fail.
At this point you'll probably have to scale and then "manually" convert back to a 32-bit integer.
In regular Python, ints move smoothly from an efficient implementation to a larger bignum implementation that can represent arbitrary length integer. We don't have this turned on in CPy 2.x because it takes a lot of code space, but we are turning it on for 3.x M4.
math.floor()
and int()
both return an integer value. In both regular Python and MicroPython unix (which supports long ints), you see this:
>>> import math
>>> 1e500 # this float is too big
inf
>>> 1e200 # this float is OK (it's a double internally)
1e+200
>>> math.floor(1e200) # this is the long int representation
99999999999999996973312221251036165947450327545502362648241750950346848435554075534196338404706251868027512415973882408182135734368278484639385041047239877871023591066789981811181813306167128854888448
>>> int(1e200)
99999999999999996973312221251036165947450327545502362648241750950346848435554075534196338404706251868027512415973882408182135734368278484639385041047239877871023591066789981811181813306167128854888448
In IEEE 754, C and python 2.x, the return type of ceil/floor functions is a floating-point type. python3 changed this, so that the return type is an integral type (a fine choice for a language which has an unbounded integral type like long). On circuitpython builds without support for arbitrary precision longs, why not follow python2 and return a float so that there are no unexpected range problems? I have an untested patch prepared to do this, and I could PR it if it stands a chance to be accepted.
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
#define MATH_FUN_1_TO_INT(py_name, c_name) \
STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_int_from_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
#else
#define MATH_FUN_1_TO_INT(py_name, c_name) MATH_FUN_1(py_name, c_name)
#endif
This would affect the implementation of math.floor, math.ceil, and math.trunc on the M0 boards.
We may turn on longints on the M0 boards if we can get things to fit in 3.0.
I'd rather be consistent with python 3 and always return an int. With MPZ on it M4 and M0 express boards (have we turned it on?) for 3.0 this should be less of an issue.
On Fri, Mar 23, 2018 at 9:50 AM Dan Halbert notifications@github.com wrote:
We may turn on longints on the M0 boards if we can get things to fit in 3.0.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/adafruit/circuitpython/issues/572#issuecomment-375729852, or mute the thread https://github.com/notifications/unsubscribe-auth/AADNqXJeJQ7wqZkBtZX9z3MvroKkKTzQks5thSe7gaJpZM4R3pvc .
My proposed patch will leave the behavior unchanged on builds that have MPZ enabled. (but if there's general feeling that it might be superfluous, I'm happy to not push it)
I'd rather throw ValueError on MPZ-less builds. We can consider turning it on for non-Express boards if we have space once everything else is done for 3.0.
Longints are not going to fit in the non-Express builds for 3.0 without removing other stuff. I recently tried MPZ and LONGLONG. Currently a Gemma M0 build has about 1800 bytes free. If I enable MPZ, it overflows by 2900 bytes. If I turn on -finline-limit
, I can get it lower, but it still overflows by about 1k. And this is without touchio
yet. (LONGLONG overflows by more.)
So I think the current behavior for math.floor()
is OK for non-Express builds, and we should just leave it be and close this for now. If no objections, I'll do so.
This isn't really a problem from circuitpython and rather almost certainly a problem with upstream, but it appears math.floor (converting a float into the next lowest integer representation) fails with large numbers.
In circuitpython/micropython:
Vs in python3:
This is kind of unfortunate because some things need very large float values and integer values for associated calculations (I ran into this with a clock generator library that computes very large hertz values for clock frequencies). Presumably math.floor is doing something like a simple int cast internally and failing when it realizes the value is beyond the limits of int precision (that's my guess, haven't dug in to see). Anyways raising this as an issue for folks to be aware of--I really can't think of a good fix but perhaps there's a workaround to get the equivalent behavior of a floor with some math operations.