[Python-Dev] Deprecating float.is_integer()
Tim Peters
tim.peters at gmail.com
Wed Mar 21 15:02:37 EDT 2018
[David Mertz]
> I've been using and teaching python for close to 20 years and I never
> noticed that x.is_integer() exists until this thread.
Except it was impossible to notice across most of those years, because
it didn't exist across most of those years ;-)
> I would say the "one obvious way" is less than obvious.
When it was introduced, it _became_ the one obvious way.
> On the other hand, `x == int(x)` is genuinely obvious..
But a bad approach: it can raise OverflowError (for infinite x); it
can raise ValueError (for x a NaN); and can waste relative mountains
of time creating huge integers, e.g.,
>>> int(1e306)
1000000000000000017216064596736454828831087825013238982328892017892380671244575047987920451875459594568606138861698291060311049225532948520696938805711440650122628514669428460356992624968028329550689224175284346730060716088829214255439694630119794546505512415617982143262670862918816362862119154749127262208
In Python 2, x == math.floor(x) was much better on the latter count,
but not in Python 3 (math.floor used to return a float, but returns an
int now).
As to Serhiy's `not x % 1.0`, after 5 minutes I gave up trying to
prove it's always correct. Besides infinities and NaNs, there's also
that Python's float mod can be surprising:
>>> (-1e-20) % 1.0
1.0
There isn't a "clean" mathematical definition of what Python's float %
does, which is why proof is strained. In general, the "natural"
result is patched when and if needed to maintain that
x == y*(x//y) + x%y
is approximately true. The odd % result above is a consequence of
that, and that (-1e-20) // 1.0 is inarguably -1.0.
> and it immediately suggests the probably better `math.isclose(x, int(x))` that
> is what you usually mean.
Even in some of the poor cases Serhiy found, that wouldn't be a lick
better. For example,
math.isclose(x/5, int(x/5))
is still a plain wrong way to check whether x is divisible by 5.
>>> x = 1e306
>>> math.isclose(x/5, int(x/5))
True
>>> x/5 == int(x/5)
True
>>> int(x) % 5
3
The problem there isn't how "is it an integer?" is spelled, it's that
_any_ way of spelling "is it an integer?" doesn't answer the question
they're trying to answer. They're just plain confused about how
floating point works. The use of `.is_integer()` (however spelled!)
isn't the cause of that, it's a symptom.
More information about the Python-Dev
mailing list