[BUG] IMO, but no opinions? Uncle Tim? was: int(float(sys.maxint)) buglet ?
Bengt Richter
bokr at oz.net
Tue Dec 7 15:54:19 EST 2004
On Mon, 6 Dec 2004 10:30:06 -0500, Tim Peters <tim.peters at gmail.com> wrote:
>[Bengt Richter]
>> Peculiar boundary cases:
>>
>> >>> 2.0**31-1.0
>> 2147483647.0
>> >>> int(2147483647.0)
>> 2147483647L
>> >>> int(2147483647L )
>> 2147483647
>> >>>
>> >>> -2.0**31
>> -2147483648.0
>> >>> int(-2147483648.0)
>> -2147483648L
>> >>> int(-2147483648L )
>> -2147483648
>>
>> some kind of one-off error?
>
>It would help if you were explicit about what you think "the error"
>is. I see a correct result in all cases there.
>
>Is it just that sometimes
>
> int(a_float)
>
>returns a Python long when
>
> int(a_long_with_the_same_value_as_that_float)
>
>returns a Python int? If so, that's not a bug -- there's no promise
>anywhere, e.g., that Python will return an int whenever it's
>physically possible to do so.
Ok, I understand the expediency of that policy, but what is now the meaning
of int, in that case? Is it now just a vestigial artifact on the way to
transparent unification of int and long to a single integer type?
Promises or not, ISTM that if int->float succeeds in preserving all significant bits, then
then a following float->int should also succeed without converting to long.
>
>Python used to return a (short) int in all cases above, but that lead
>to problems on some oddball systems. See the comments for float_int()
>in floatobject.c for more detail. Slowing float_int() to avoid those
>problems while returning a short int whenever physically possible is a
>tradeoff I would oppose.
The 2.3.2 source snippet in floatobject.c :
--------------
static PyObject *
float_int(PyObject *v)
{
double x = PyFloat_AsDouble(v);
double wholepart; /* integral portion of x, rounded toward 0 */
(void)modf(x, &wholepart);
/* Try to get out cheap if this fits in a Python int. The attempt
* to cast to long must be protected, as C doesn't define what
* happens if the double is too big to fit in a long. Some rare
* systems raise an exception then (RISCOS was mentioned as one,
* and someone using a non-default option on Sun also bumped into
* that). Note that checking for >= and <= LONG_{MIN,MAX} would
* still be vulnerable: if a long has more bits of precision than
* a double, casting MIN/MAX to double may yield an approximation,
* and if that's rounded up, then, e.g., wholepart=LONG_MAX+1 would
* yield true from the C expression wholepart<=LONG_MAX, despite
* that wholepart is actually greater than LONG_MAX.
*/
if (LONG_MIN < wholepart && wholepart < LONG_MAX) {
const long aslong = (long)wholepart;
return PyInt_FromLong(aslong);
}
return PyLong_FromDouble(wholepart);
}
--------------
But this is apparently accessed through a table of pointers, so would you oppose
an auto-configuration that one time tested whether
int(float(sys.maxint))==sys.maxint and int(float(-sys.maxint-1))==-sys.maxint-1
(assuming that's sufficient, of which I'm not 100% sure ;-) and if so switched
the pointer to a version that tested if(LONG_MIN <= wholepart && wholepart<=LONG_MAX)
instead of the safe-for-some-obscure-system version?
Of course, if int isn't all that meaningful any more, I guess the problem can be moved to the
ctypes module, if that gets included amongst the batteries ;-)
Regards,
Bengt Richter
More information about the Python-list
mailing list