bug in modulus?
Tim Peters
tim.peters at gmail.com
Sun Apr 23 14:03:20 EDT 2006
[jantod at gmail.com]
> I think there might be something wrong with the implementation of
> modulus.
>
> Negative float values close to 0.0 break the identity "0 <= abs(a % b) < abs(b)".
While that's a mathematical identity, floating point has finite
precision. Many mathematical identities can fail when using floats.
For example,
(x+y)+z = x+(y+z)
doesn't always hold when using floats either.
> print 0.0 % 2.0 # => 0.0
> print -1e-010 % 2.0 # =>1.9999999999
>
> which is correct, but:
>
> print -1e-050 % 2.0 # => 2.0
> print -1e-050 % 2.0 < 2.0 # => False
See footnote 5.2 in the Language (not Library) reference manual,
section 5.6 "Binary arithmetic operations":
While abs(x%y) < abs(y) is true mathematically, for floats it may
not be true
numerically due to roundoff. For example, and assuming a platform on which
a Python float is an IEEE 754 double-precision number, in order that
-1e-100 % 1e100 have the same sign as 1e100, the computed result is
-1e-100 + 1e100, which is numerically exactly equal to 1e100.
Function fmod()
in the math module returns a result whose sign matches the sign of the first
argument instead, and so returns -1e-100 in this case. Which
approach is more
appropriate depends on the application.
> This means I can't use modulus to "wrap around" before it reaches a
> certain value.
It's simply not possible to deliver a float result in all cases that
satisfies all desirable identities. % and math.fmod make different
tradeoffs, but neither is suitable for all applications, and it's
possble that the neither is suitable for a particular application --
pick your poison, or brew your own.
> I'm using Python 2.4.2 on WindowsXP.
Because it's inherent to using finite-precision approximations to real
numbers, this is a cross-platorm and cross-language phenomenon. If
you can't tolerate approximations, rework your logic to use integers
instead.
More information about the Python-list
mailing list