[Python-3000] bug in modulus?

Tim Peters tim.peters at gmail.com
Thu May 4 21:07:23 CEST 2006


[Guido]
> This is way above my head. :-)

Of course it's not, but the issues are subtle and messy enough that
it's a burden to make sufficient time for them.  I'm sympathetic to
that ;-)

> The only requirement *I* would like to see is that for floats that
> exactly represent ints (or longs for that matter) the result ought of
> x%y ought to have the same value as the same operation on the
> corresponding ints (except if the result can't be represented exactly
> as a float -- I don't know what's best then).
>
> We're fixing this for / in Py3k, so passing an int into an algorithm
> written for floats won't be harmful and won't require defensiev
> float() casting everywhere. It would be a shame if we *introduced* a
> new difference between ints and floats for %.

I'm sympathetic to that too.  I explained in detail in a different
message why the C99 definition of % is a much better definition for
floats, and why the Python-int flavor of % cannot (as in "impossible,
not even in theory") meet all reasonable integer-derived expectations
when applied to floats.

If Python switched to C99's definition of % for both integers and
floats, that would work out better so far as it goes.  But Python's %
makes much more sense for integers, so that would be a flea on the
tail of the dog wagging the guy walking the dog (float % is rare in
real life).

A variant on what you sketched above would be an odd but probably
workable compromise:  keep __mod__ and __divmod__ for floats, but make
them exceptional when the arguments aren't exact integers, or the
result can't be represented exactly as a float (e.g., -1.0 %
2.0**100).  Then if someone uses "small enough" integers that happen
to be in floating format, % and divmod work and deliver the same
result as integer %/divmod.  If floating %/divmod are allowed to
return longs, then cases like -1.0 % 2.0**100 could also deliver
surprise-free results (although that seems so useless, given that the
_inputs_ were floats, I'd rather raise an exception).

The surprise comes when they apply % or divmod to a non-integral
float, and then the exception can clearly point to a spelling of mod
that makes sense for floats (math.fmod already does -- that's the C99
float %).   That spelling can't have the same definition as integer %,
but since you have to explicitly ask for it I don't see that as a real
problem.

The decimal module should change to the same kind of approach, whatever it is:

>>> from decimal import Decimal as D
>>> D(-1) % D(2)
Decimal("-1")

is already inconsistent with -1 % 2.

BTW, this came up on c.l.py earlier this week:

>>> from math import atan2
>>> atan2(-0, -1)
3.1415926535897931
>>> atan2(-0.0, -1)
-3.1415926535897931

Gotta love signed zeroes :-(


More information about the Python-3000 mailing list