bug in modulus?
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)". print 0.0 % 2.0 # => 0.0 print -1e-010 % 2.0 # =>1.99 which is correct, but: print -1e-050 % 2.0 # => 2.0 print -1e-050 % 2.0 < 2.0 # => False This means I can't use modulus to "wrap around" before it reaches a certain value. I'm using Python 2.4.2 on WindowsXP. Thanks Janto -- http://mail.python.org/mailman/listinfo/python-list
Re: bug in modulus?
[EMAIL PROTECTED] > 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.99 > > 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. -- http://mail.python.org/mailman/listinfo/python-list
Re: bug in modulus?
Hmmm. I understand. I'd suggest that someone just drop a link from the Library reference manual as the divmod entry over there seems to contradict it. """ divmod(a, b) Take two (non complex) numbers as arguments and return a pair of numbers consisting of their quotient and remainder when using long division. With mixed operand types, the rules for binary arithmetic operators apply. For plain and long integers, the result is the same as (a / b, a % b). For floating point numbers the result is (q, a % b), where q is usually math.floor(a / b) but may be 1 less than that. In any case q * b + a % b is very close to a, if a % b is non-zero it has the same sign as b, and 0 <= abs(a % b) < abs(b). """ But maybe I'm reading it wrong. In any case what I wanted was simply a way to extract the angle from a complex number where the angle is between 0 and 2*pi. I think I'll just take the modulus twice. def angle(complex): """Returns angle where 2*pi > angle >=0 >>> angle(1+1j) - atan(1) < 1e-3 True >>> angle(-1+1j) - (atan(-1) + 3*pi) % (2*pi) < 1e-3 True >>> angle(0+1j) == pi/2 True >>> angle(0-1j) == 1.5*pi True >>> angle(1+0j) == 0 True >>> angle(0+0j) == 0 True >>> angle(1-1e-100*1j) == 0 True """ if complex.real == 0: if complex.imag == 0: return 0 if complex.imag < 0: return 1.5*pi return pi/2 theta = (atan2(complex.imag, complex.real) % (2*pi)) % (2*pi) assert 2*pi > theta >=0, (theta, complex) return theta Thanks for your help! -- http://mail.python.org/mailman/listinfo/python-list
Re: bug in modulus?
[EMAIL PROTECTED] wrote: > Hmmm. I understand. I'd suggest that someone just drop a link from the > Library reference manual as the divmod entry over there seems to > contradict it. > > """ > divmod(a, b) > > Take two (non complex) numbers as arguments and return a pair of > numbers consisting of their quotient and remainder when using long > division. With mixed operand types, the rules for binary arithmetic > operators apply. For plain and long integers, the result is the same as > (a / b, a % b). For floating point numbers the result is (q, a % b), > where q is usually math.floor(a / b) but may be 1 less than that. In > any case q * b + a % b is very close to a, if a % b is non-zero it has > the same sign as b, and 0 <= abs(a % b) < abs(b). > """ > > But maybe I'm reading it wrong. In any case what I wanted was simply a > way to extract the angle from a complex number where the angle is > between 0 and 2*pi. I think I'll just take the modulus twice. If you absolutely insist on having the angle be less than 2*pi, you could always do something like: theta = min(theta, pi*2 - 2**(-50)) -- http://mail.python.org/mailman/listinfo/python-list
Re: bug in modulus?
[EMAIL PROTECTED] wrote: > But maybe I'm reading it wrong. In any case what I wanted was simply a > way to extract the angle from a complex number where the angle is > between 0 and 2*pi. I think I'll just take the modulus twice. > > def angle(complex): > """Returns angle where 2*pi > angle >=0 > > >>> angle(1+1j) - atan(1) < 1e-3 > True > >>> angle(-1+1j) - (atan(-1) + 3*pi) % (2*pi) < 1e-3 > True > >>> angle(0+1j) == pi/2 > True > >>> angle(0-1j) == 1.5*pi > True > >>> angle(1+0j) == 0 > True > >>> angle(0+0j) == 0 > True > >>> angle(1-1e-100*1j) == 0 > True > """ > if complex.real == 0: > if complex.imag == 0: > return 0 > if complex.imag < 0: > return 1.5*pi > return pi/2 > theta = (atan2(complex.imag, complex.real) % (2*pi)) % (2*pi) > assert 2*pi > theta >=0, (theta, complex) > return theta > from math import atan2, pi def cangle(z): ret = atan2(z.imag, z.real) if ret < 0: ret += 2*pi return ret assert cangle(1+1j) * 180 / pi == 45.0 assert cangle(-1+1j) * 180 / pi == 135.0 assert cangle(-1-1j) * 180 / pi == 225.0 assert cangle(1-1j) * 180 / pi == 315.0 assert cangle(1+0j) * 180 / pi == 0.0 assert cangle(-1+0j) * 180 / pi == 180.0 assert cangle(1j) * 180 / pi == 90.0 assert cangle(-1j) * 180 / pi == 270.0 Gerard -- http://mail.python.org/mailman/listinfo/python-list
Re: bug in modulus?
[EMAIL PROTECTED] a écrit : > 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)". > > print 0.0 % 2.0 # => 0.0 > print -1e-010 % 2.0 # =>1.99 > > which is correct, but: > > print -1e-050 % 2.0 # => 2.0 > print -1e-050 % 2.0 < 2.0 # => False > > This means I can't use modulus to "wrap around" before it reaches a > certain value. I'm using Python 2.4.2 on WindowsXP. > > Thanks > Janto > Consider that -1e-050 % 2.0 = 2.0 - 1e-050 Now, test that : >>> 2.0 - 1e-050 == 2.0 True Floating point numbers just don't have the required precision to represent 2.0 - 1e-050. For your specific problem, if you really want the result to be < 2.0, the the best you can do is admit that floating point operations have errors and return 0.0 when the modulus operation equals 2.0. -- http://mail.python.org/mailman/listinfo/python-list
Re: bug in modulus?
"Christophe" <[EMAIL PROTECTED]> wrote in message news:[EMAIL PROTECTED] > [EMAIL PROTECTED] a écrit : > Floating point numbers just don't have the required precision to represent > 2.0 - 1e-050. For your specific problem, if you really want the result to > be < 2.0, the the best you can do is admit that floating point operations > have errors and return 0.0 when the modulus operation equals 2.0. I disagree. For any two floating-point numbers a and b, with b != 0, it is always possible to represent the exact value of a mod b as a floating-point number--at least on every floating-point system I have ever encountered. The implementation is not even that difficult. -- http://mail.python.org/mailman/listinfo/python-list
Re: bug in modulus?
"Andrew Koenig" <[EMAIL PROTECTED]> wrote in message news:[EMAIL PROTECTED] > I disagree. For any two floating-point numbers a and b, with b != 0, it > is always possible to represent the exact value of a mod b as a > floating-point number--at least on every floating-point system I have ever > encountered. The implementation is not even that difficult. Oops... This statement is true for the Fortran definition of modulus (result has the sign of the dividend) but not the Python definition (result has the sign of the divisor). In the Python world, it's true only when the dividend and divisor have the same sign. -- http://mail.python.org/mailman/listinfo/python-list
Re: bug in modulus?
[Andrew Koenig, on the counter intuitive -1e-050 % 2.0 == 2.0 example] >> I disagree. For any two floating-point numbers a and b, with b != 0, it >> is always possible to represent the exact value of a mod b as a >> floating-point number--at least on every floating-point system I have ever >> encountered. The implementation is not even that difficult. [also Andrew] > Oops... This statement is true for the Fortran definition of modulus (result > has the sign of the dividend) but not the Python definition (result has the > sign of the divisor). In the Python world, it's true only when the dividend > and divisor have the same sign. Note that you can have it in Python too, by using math.fmod(a, b) instead of "a % b". IMO, it was a mistake (and partly my fault cuz I didn't whine early) for Python to try to define % the same way for ints and floats. The hardware realities are too different, and so are the pragmatics. For floats, it's actually most useful most often to have both that a % b is exact and that 0.0 <= abs(a % b) <= abs(b/2). Then the sign of a%b bears no relationship to the signs of a and b, but for purposes of modular reduction it yields the result with the smallest possible absolute value. That's often valuable for floats (e.g., think of argument reduction feeding into a series expansion, where time to convergence typically depends on the magnitude of the input and couldn't care less about the input's sign), but rarely useful for ints. I'd like to see this change in Python 3000. Note that IBM's proposed standard for decimal arithmetic (which Python's "decimal" module implements) requires two operations here, one that works like math.fmod(a, b) (exact and sign of a), and the other as described above (exact and |a%b| <= |b/2|). Those are really the only sane definitions for a floating point modulo/remainder. -- http://mail.python.org/mailman/listinfo/python-list
Re: [Python-3000] bug in modulus?
This is way above my head. :-) 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 %. --Guido On 5/2/06, Tim Peters <[EMAIL PROTECTED]> wrote: > [Andrew Koenig, on the counter intuitive -1e-050 % 2.0 == 2.0 example] > >> I disagree. For any two floating-point numbers a and b, with b != 0, it > >> is always possible to represent the exact value of a mod b as a > >> floating-point number--at least on every floating-point system I have ever > >> encountered. The implementation is not even that difficult. > > [also Andrew] > > Oops... This statement is true for the Fortran definition of modulus (result > > has the sign of the dividend) but not the Python definition (result has the > > sign of the divisor). In the Python world, it's true only when the dividend > > and divisor have the same sign. > > Note that you can have it in Python too, by using math.fmod(a, b) > instead of "a % b". > > IMO, it was a mistake (and partly my fault cuz I didn't whine early) > for Python to try to define % the same way for ints and floats. The > hardware realities are too different, and so are the pragmatics. For > floats, it's actually most useful most often to have both that a % b > is exact and that 0.0 <= abs(a % b) <= abs(b/2). Then the sign of a%b > bears no relationship to the signs of a and b, but for purposes of > modular reduction it yields the result with the smallest possible > absolute value. That's often valuable for floats (e.g., think of > argument reduction feeding into a series expansion, where time to > convergence typically depends on the magnitude of the input and > couldn't care less about the input's sign), but rarely useful for > ints. > > I'd like to see this change in Python 3000. Note that IBM's proposed > standard for decimal arithmetic (which Python's "decimal" module > implements) requires two operations here, one that works like > math.fmod(a, b) (exact and sign of a), and the other as described > above (exact and |a%b| <= |b/2|). Those are really the only sane > definitions for a floating point modulo/remainder. > ___ > Python-3000 mailing list > Python-3000@python.org > http://mail.python.org/mailman/listinfo/python-3000 > Unsubscribe: > http://mail.python.org/mailman/options/python-3000/guido%40python.org > -- --Guido van Rossum (home page: http://www.python.org/~guido/) -- http://mail.python.org/mailman/listinfo/python-list
Re: [Python-3000] bug in modulus?
Guido van Rossum a écrit : > This is way above my head. :-) > > 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). Which is exactly the case at hand. As a proposed change, I would say that when the implementation of x%y returns y, then we should return 0 instead, or maybe the biggest possible number that is still < y. That way we would have a result that respects the "x%y < y" rule and still be as good as possible with the reduced float precision. And besides, mathematics say that "0 = y = 2y = 3y [y]" and so there is no problem for returning 0 instead of y :) -- http://mail.python.org/mailman/listinfo/python-list
RE: [Python-3000] bug in modulus?
Tim Peters writes: > IMO, it was a mistake (and partly my fault cuz I didn't whine early) > for Python to try to define % the same way for ints and floats. [...] > I'd like to see this change in Python 3000. Note that IBM's proposed > standard for decimal arithmetic (which Python's "decimal" module > implements) requires two operations here, one that works like > math.fmod(a, b) (exact and sign of a), and the other as described > above (exact and |a%b| <= |b/2|). Providing both operations is a no-brainer. But only one gets to be spelled "x % y". Experts will care about sensible behavior of numerical algorithms... but they're experts, they can use whichever operation they need. Beginners will care that floats and integers behave "the same" (okay, that's not actually possible, but beginners don't know it). So why not make "x % y" for floats behave exactly like it does for integers and provide a separate operation with your described behavior? (Or is that what you were suggesting, and I'm just confused?) If you're worried about beginners who are implementing numerical algorithms and hoping to make the language smart enough to "just work" for them, then I'm afraid it's hopeless. I'm far from a beginner, but I don't think I could implement a non-trivial numerical algorithm. (Well, I could make it work, but I'm betting it would be non-optimal or have corner cases of failure that an expert could point out.) -- Michael Chermside -- http://mail.python.org/mailman/listinfo/python-list
Re: [Python-3000] bug in modulus?
Michael> So why not make "x % y" for floats behave exactly like it does Michael> for integers and provide a separate operation with your Michael> described behavior? %% anyone? (Skip ducks and runs...) Skip -- http://mail.python.org/mailman/listinfo/python-list