From: Scott K. <sc...@sc...> - 2001-01-02 22:29:25
|
Hello, my name is Scott and I am a Python newbie (2 months). "hello Scott, what brought you here?" ;^) Anyway, I am having the time of my programming life learning Python and building a serious configuration program in Java/Jython. What I have noticed when I am doing some loops is an annoying precision error that I need to work around. The simple code: #! /usr/bin/python test_var = 0.0 limit = 0.1 inc = 0.01 while test_var <= limit: print test_var test_var = test_var + inc always runs to 1 less loop than I need because of this output: D:\dev\python\test>jython test_loop.py 0.0 0.01 0.02 0.03 0.04 0.05 0.060000000000000005 0.07 0.08 0.09 0.09999999999999999 With native Python 2.0 in the same platform and 1.52 on Linux, the output is a little different: D:\dev\python\test>test_loop.py 0.0 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 This is a little more of what I expected. This trivial example looks harmless enough, but it gets out of hand when the loops are in the 100+ range. What happens is even the Python only runs to 0.99 instead of 1.0 like it should. The only solution I have come up with is to slightly modify the increment like: test_var = round((test_var + inc), 2) so that it cuts off the value every time through. This seems to work well enough, but I am wondering if there is a better way. I also wonder why Jython puts so many decimal places out when Python keeps the original max of 2. This seems like it could be a Java thing to me since I have seen similar behavior in Java programs. Thanks in advance. -- Scott Knight mailto:sc...@sc... |
From: <bc...@wo...> - 2001-01-03 10:54:47
|
[Scott Knight] >Hello, my name is Scott and I am a Python newbie (2 months). >"hello Scott, what brought you here?" >;^) > >Anyway, I am having the time of my programming life learning Python and >building a serious configuration program in Java/Jython. What I have >noticed when I am doing some loops is an annoying precision error that I >need to work around. The simple code: > >#! /usr/bin/python > >test_var = 0.0 >limit = 0.1 >inc = 0.01 > >while test_var <= limit: > print test_var > test_var = test_var + inc > >always runs to 1 less loop than I need because of this output: > >D:\dev\python\test>jython test_loop.py >0.0 >0.01 >0.02 >0.03 >0.04 >0.05 >0.060000000000000005 >0.07 >0.08 >0.09 >0.09999999999999999 > >With native Python 2.0 in the same platform and 1.52 on Linux, the >output is a little different: > >D:\dev\python\test>test_loop.py >0.0 >0.01 >0.02 >0.03 >0.04 >0.05 >0.06 >0.07 >0.08 >0.09 >0.1 First a huge disclaimer: I know nothing about float point numbers or the strangeness of their implementation. I think CPython-2.0 is faking the output above. If you add a repr(test_var) on the print statement, you get (with CPython-2.0 & win2k): 0.0 0.0 0.01 0.01 0.02 0.02 0.03 0.029999999999999999 0.04 0.040000000000000001 0.05 0.050000000000000003 0.06 0.060000000000000005 0.07 0.070000000000000007 0.08 0.080000000000000002 0.09 0.089999999999999997 0.1 0.099999999999999992 >This is a little more of what I expected. This trivial example looks >harmless enough, but it gets out of hand when the loops are in the 100+ >range. What happens is even the Python only runs to 0.99 instead of 1.0 >like it should. Because the actual value of the float is about as imprecise in CPython as it is in Jython and in java. >The only solution I have come up with is to slightly modify the >increment like: > > test_var = round((test_var + inc), 2) > >so that it cuts off the value every time through. This seems to work >well enough, but I am wondering if there is a better way. > >I also wonder why Jython puts so many decimal places out when Python >keeps the original max of 2. This seems like it could be a Java thing >to me since I have seen similar behavior in Java programs. Jython is getting all its float behavior from java, including the string representation. This cause some difference between CPython, in particular with CPython-2.0 where the str(0.1) and repr(0.1) return different string values (at least is does in my w2k). I don't think the jython implementation of floats and float -> string conversion will be changed much. It has its flaws, but it is consistent with java, and java floats are consistent across platforms. That alone is a valuable improvement compared to CPython (this conclusion is reached based on reading python-dev, not on any actual knowledge of CPython). If jython will be changed to closer compliance with CPython, it will not be done by me. I'll leave that for experts on floating point implementations. regards, finn |
From: Tim P. <ti...@ho...> - 2001-01-04 03:50:36
|
Adding to Finn Bock's reply, it's almost certainly the case that Scott (Knight) is running on a platform with IEEE-754 floating-point hardware, and that the results computed by CPython and Jython were identical. The implementations do differ in how they choose to round the display, though; CPython inherits the fine points of its float I/O from the platform C library, while Java defines it more rigorously. And you're going to get the same results in any language if you use floating point: Java, Python, Jython, C, C++, Perl, Eiffel, LISP, Scheme, Fortran, ... it doesn't matter. This link explains one of the fine points in deadly <wink> detail: http://www.python.org/cgi-bin/moinmoin/RepresentationError > test_var = 0.0 > limit = 0.1 > inc = 0.01 > > while test_var <= limit: > print test_var > test_var = test_var + inc Ever since someone first bumped into this in Fortran in the 1950's (honest!), the "correct" way to write such a loop has been to use an integer index (say "i"), and compute test_var = i * inc inside the loop. Each floating-point operation introduces its own rounding error, and in doing test_var = test_var + inc these errors compound over time. In test_var = i * inc you only suffer one rounding error in test_var. However, none of that changes that (for example) 0.9 is not exactly representable in binary floating-point arithmetic, no matter how you compute it (see the link above). Scott, if you're under the illusion <wink> that decimal fractions are a Good Thing, you'll never be happy with hardware floating point arithmetic. You should look into something like Java's BigDecimal class instead: http://www2.hursley.ibm.com/decimalj/decdef.html as-always-the-fast-drives-out-the-sane-ly y'rs - tim |