[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