By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
 443,660 Members | 1,105 Online
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,660 IT Pros & Developers. It's quick & easy.

# round() wrong in Python 2.4?

 P: n/a Why did round() change in Python 2.4? \$ python2.3 Python 2.3.5 (#2, Jun 19 2005, 13:28:00) [GCC 3.3.6 (Debian 1:3.3.6-6)] on linux2 round(0.0225, 3) 0.023 "%.3f" % round(0.0225, 3) '0.023' \$ python2.4 Python 2.4.1 (#2, Jul 12 2005, 09:22:25) [GCC 4.0.1 (Debian 4.0.1-1)] on linux2 round(0.0225, 3) 0.021999999999999999 "%.3f" % round(0.0225, 3) '0.022' (Is this due to the different GCC used?) How do you correctly output floating-point numbers in 2.4? I do not like the "print number + EPS" solution, as you would need different EPS for different exponent sizes. In C you could get it by taking integer 1, and &-ing in the right exponent, and then casting to double via void*. This would not be very portable, though. Klem fra Nils Sep 13 '05 #1
Share this Question
14 Replies

 P: n/a Nils Grimsmo wrote: Why did round() change in Python 2.4? It the usual floating point representation problem. 0.0225 cannot be represented exactly: xpc20:~> python Python 2.3.4 (#1, Mar 14 2005, 16:47:22) [GCC 3.4.3 20041212 (Red Hat 3.4.3-9.EL4)] on linux2 Type "help", "copyright", "credits" or "license" for more information. 0.0225 0.022499999999999999 See http://www.python.org/doc/current/tu...00000000000000 If you need exact maths, then you're better off using integers or decimal arithmetic. Jeremy -- Jeremy Sanders http://www.jeremysanders.net/ Sep 13 '05 #2

 P: n/a Jeremy Sanders wrote: Nils Grimsmo wrote:Why did round() change in Python 2.4? It the usual floating point representation problem. 0.0225 cannot be represented exactly: That's not what he's asking about. He's asking why his Python 2.3 rounds 0.0225 *up* to 0.023 while his Python 2.4 rounds *down* to 0.022. It's the change in behavior that he's concerned with and isn't just the usual floating point problem. I'm going to suggest that it's a platform issue, possibly the change in compiler. I get identical results on OS X with both versions of Python both compiled by gcc-3.3 . [~]\$ python2.3 Python 2.3.5 (#1, Mar 20 2005, 20:38:20) [GCC 3.3 20030304 (Apple Computer, Inc. build 1809)] on darwin Type "help", "copyright", "credits" or "license" for more information. 0.0225 0.022499999999999999 round(0.0225, 3) 0.023 [~]\$ python2.4 Python 2.4.1 (#2, Mar 31 2005, 00:05:10) [GCC 3.3 20030304 (Apple Computer, Inc. build 1666)] on darwin Type "help", "copyright", "credits" or "license" for more information. 0.0225 0.022499999999999999 round(0.0225, 3) 0.023 -- Robert Kern rk***@ucsd.edu "In the fields of hell where the grass grows high Are the graves of dreams allowed to die." -- Richard Harter Sep 13 '05 #3

 P: n/a Nils Grimsmo wrote:Why did round() change in Python 2.4?\$ python2.3Python 2.3.5 (#2, Jun 19 2005, 13:28:00)[GCC 3.3.6 (Debian 1:3.3.6-6)] on linux2 round(0.0225, 3)0.023 "%.3f" % round(0.0225, 3)'0.023'\$ python2.4Python 2.4.1 (#2, Jul 12 2005, 09:22:25)[GCC 4.0.1 (Debian 4.0.1-1)] on linux2 round(0.0225, 3)0.021999999999999999 "%.3f" % round(0.0225, 3)'0.022'(Is this due to the different GCC used?) That would look like a good guess to me: \$ python Python 2.4.1 (#2, May 5 2005, 11:32:06) [GCC 3.3.5 (Debian 1:3.3.5-12)] on linux2 Type "help", "copyright", "credits" or "license" for more information. round(0.0225, 3) 0.023 "%.3f" % round(0.0225, 3) '0.023' Is that python2.4 of yours from the python2.4 package or one you compiled up yourself? -- \S -- si***@chiark.greenend.org.uk -- http://www.chaos.org.uk/~sion/ ___ | "Frankly I have no feelings towards penguins one way or the other" \X/ | -- Arthur C. Clarke her nu becomež se bera eadward ofdun hlęddre heafdes bęce bump bump bump Sep 13 '05 #4

 P: n/a I am running Debian unstable for 386. Python 2.4 is from the official package archive, and seems to be compiled with GCC 4.0.2. \$ dpkg -l python2.4 ii python2.4 2.4.1-4 ... \$ python2.4 Python 2.4.1+ (#2, Sep 4 2005, 21:58:51) [GCC 4.0.2 20050821 (prerelease) (Debian 4.0.1-6)] on linux2 Type "help", "copyright", "credits" or "license" for more information. \$ gcc-4.0 --version gcc-4.0 (GCC) 4.0.2 20050725 (prerelease) (Debian 4.0.1-3) Klem fra Nils Sep 14 '05 #5

 P: n/a Robert Kern wrote: That's not what he's asking about. He's asking why his Python 2.3 rounds 0.0225 *up* to 0.023 while his Python 2.4 rounds *down* to 0.022. It's the change in behavior that he's concerned with and isn't just the usual floating point problem. You can't rely on either being true, given the nature of the inexact representation of the number, and the fact that python ignores quite a lot of the IEEE stuff. Different optimisations (particularly with the 80 bit floating point registers in x86), will lead to different represenations. Any code which relies on a particular behaviour is broken. Jeremy -- Jeremy Sanders http://www.jeremysanders.net/ Sep 14 '05 #6

 P: n/a Op 2005-09-13, Robert Kern schreef : Jeremy Sanders wrote: Nils Grimsmo wrote:Why did round() change in Python 2.4? It the usual floating point representation problem. 0.0225 cannot be represented exactly: That's not what he's asking about. He's asking why his Python 2.3 rounds 0.0225 *up* to 0.023 while his Python 2.4 rounds *down* to 0.022. It's the change in behavior that he's concerned with and isn't just the usual floating point problem. I would say the usual floating point problem is involved. Python 2.3 isn't rounding 0.0225 up while pyton 2.4 rounds it down. 0.0225 isn't representable and it happens that the actual number you get differ. Now which number python should choose when it is fed 0.0225, I don't know. But expressing the different behaviour as a change in round, suggest that the O.P. would be wise to learn about floating point problems -- Antoon Pardon Sep 14 '05 #7

 P: n/a Antoon Pardon wrote: Op 2005-09-13, Robert Kern schreef :Jeremy Sanders wrote:Nils Grimsmo wrote:Why did round() change in Python 2.4?It the usual floating point representation problem. 0.0225 cannot berepresented exactly:That's not what he's asking about. He's asking why his Python 2.3 rounds0.0225 *up* to 0.023 while his Python 2.4 rounds *down* to 0.022. It'sthe change in behavior that he's concerned with and isn't just the usualfloating point problem. I would say the usual floating point problem is involved. Python 2.3 isn't rounding 0.0225 up while pyton 2.4 rounds it down. 0.0225 isn't representable and it happens that the actual number you get differ. Now which number python should choose when it is fed 0.0225, I don't know. But expressing the different behaviour as a change in round, suggest that the O.P. would be wise to learn about floating point problems Uhh, Python didn't change anything between 2.3 and 2.4 wrt round(). The reason he is seeing a difference is because the two executables were built with different compilers. The fact that the version of Python was different in the two cases obscures the real cause. Saying that 0.0225 can't be represented exactly as a binary floating point number is entirely true but is an incomplete answer. Yes, obviously binary floating point representations are involved. But one could always define a standard representation scheme that always gives the same answer for the same input. The fact is that for some reason there are two schemes being used. Another fact is that this has nothing to do with difference in the versions of Python he is using. Most of Python's floating point behavior is a platform-dependent accident (as Tim Peters always says), and Nils is using two slightly different platforms. -- Robert Kern rk***@ucsd.edu "In the fields of hell where the grass grows high Are the graves of dreams allowed to die." -- Richard Harter Sep 14 '05 #8

 P: n/a On 2005-09-14, Robert Kern wrote: Antoon Pardon wrote: 0.0225 isn't representable and it happens that the actual number you get differ. Now which number python should choose when it is fed 0.0225, I don't know. But expressing the different behaviour as a change in round, suggest that the O.P. would be wise to learn about floating point problems Uhh, Python didn't change anything between 2.3 and 2.4 wrt round(). That's what Antoon Pardon just said. The above paragraph says that round() didn't change, and the fact that the OP thinks it did indicates that the OP needs to learn more about FP. -- Grant Edwards grante Yow! UH-OH!! We're out at of AUTOMOBILE PARTS and visi.com RUBBER GOODS! Sep 14 '05 #9

 P: n/a Nils Grimsmo wrote: (Is this due to the different GCC used?) Yes, but there are probably other nasty values with the other CGG. Basically, what the code does, for a positive number, is to calculate floor(0.0225*1000.0+0.5)/1000.0. As others have said: Don't trust this. If you use Python 2.4, you can take advantage of the new decimal module, where no floating point calculations are involved. I tried with Python 2.2.3 on RH EL3, and for half a million tested values that ended with 5 in the 4th decimal and used ndigits=3, I got almost 3000 where it rounded towards zero, and not towards infinity as the docs say. I.e. almost 0.6% wrong. Here is a more direct description of the problem in my system: math.floor(4.0925*1.0*10.0*10.0*10.0+0.5) 4093.0 math.floor(4.0935*1.0*10.0*10.0*10.0+0.5) 4093.0 math.floor(4.0945*1.0*10.0*10.0*10.0+0.5) 4095.0 Your 2.4 system is still strange though. I tried the program below on a range of systems: RH Linux, HP-UX, AIX, Solaris, on Sparc, PowerPC, PA-RISC, Intel Pentium and AMD 64, and they always gave the same results with Python 2.2.3 or Python 2.3.1. Program: for N in (1000,2000,3000,5000,10000,100000,1000000): buggy=0 for i in range(1,N,2): f=i/2000.0 r=round(f,3) if r 0.023 and 0.022 => 0.021999999999999999 in different Python versions. Use str() or %s etc. BTW, the C source code looks like this: static PyObject * builtin_round(PyObject *self, PyObject *args) { double x; double f; int ndigits = 0; int i; if (!PyArg_ParseTuple(args, "d|i:round", &x, &ndigits)) return NULL; f = 1.0; i = abs(ndigits); while (--i >= 0) f = f*10.0; if (ndigits < 0) x /= f; else x *= f; if (x >= 0.0) x = floor(x + 0.5); else x = ceil(x - 0.5); if (ndigits < 0) x *= f; else x /= f; return PyFloat_FromDouble(x); } Perhaps one could argue that the code should be changed to if (x >= 0.0) x = floor(x + d + 0.5); else x = ceil(x - d - 0.5); where d is a fairly small number, but this doesn't help in the long run... For large enough floating point numbers, the resolution of the floating point system gets bigger than 1! It might well be possible to make a round() function that works just right in e.g. business accounting applications, where money ranges between perhaps 0.01 and 1,000,000,000,000.00, but it's much more difficult to make such a thing work for the standard library, where we might want to use the whole range available to floats. Sep 14 '05 #10

 P: n/a Grant Edwards wrote: On 2005-09-14, Robert Kern wrote:Antoon Pardon wrote:0.0225 isn't representable and it happens that the actual numberyou get differ. Now which number python should choose when it isfed 0.0225, I don't know. But expressing the different behaviouras a change in round, suggest that the O.P. would be wise tolearn about floating point problemsUhh, Python didn't change anything between 2.3 and 2.4 wrt round(). That's what Antoon Pardon just said. The above paragraph says that round() didn't change, and the fact that the OP thinks it did indicates that the OP needs to learn more about FP. Antoon: "Python 2.3 isn't rounding 0.0225 up while pyton 2.4 rounds it down." -- Robert Kern rk***@ucsd.edu "In the fields of hell where the grass grows high Are the graves of dreams allowed to die." -- Richard Harter Sep 14 '05 #11

 P: n/a Robert Kern wrote: Grant Edwards wrote: On 2005-09-14, Robert Kern wrote:Antoon Pardon wrote:0.0225 isn't representable and it happens that the actual numberyou get differ. Now which number python should choose when it isfed 0.0225, I don't know. But expressing the different behaviouras a change in round, suggest that the O.P. would be wise tolearn about floating point problemsUhh, Python didn't change anything between 2.3 and 2.4 wrt round(). That's what Antoon Pardon just said. The above paragraph says that round() didn't change, and the fact that the OP thinks it did indicates that the OP needs to learn more about FP. Antoon: "Python 2.3 isn't rounding 0.0225 up while pyton 2.4 rounds it down." Written in Pseudocode: not (Py2.3 rounding up and Py2.4 rounding down) Reinhold Sep 15 '05 #12

 P: n/a Reinhold Birkenfeld wrote: Robert Kern wrote: Antoon:"Python 2.3 isn't rounding 0.0225 up while pyton 2.4 rounds it down." Written in Pseudocode: not (Py2.3 rounding up and Py2.4 rounding down) I presumed the "isn't" was a typo given the "while." -- Robert Kern rk***@ucsd.edu "In the fields of hell where the grass grows high Are the graves of dreams allowed to die." -- Richard Harter Sep 15 '05 #13

 P: n/a Robert Kern wrote: Reinhold Birkenfeld wrote:Robert Kern wrote:Antoon:"Python 2.3 isn't rounding 0.0225 up while pyton 2.4 rounds it down."Written in Pseudocode:not (Py2.3 rounding up and Py2.4 rounding down) I presumed the "isn't" was a typo given the "while." Oh never mind. I'm sorry I started this line of conversation. -- Robert Kern rk***@ucsd.edu "In the fields of hell where the grass grows high Are the graves of dreams allowed to die." -- Richard Harter Sep 15 '05 #14

 P: n/a Op 2005-09-14, Robert Kern schreef : Antoon Pardon wrote: Op 2005-09-13, Robert Kern schreef :Jeremy Sanders wrote:Nils Grimsmo wrote:>Why did round() change in Python 2.4?It the usual floating point representation problem. 0.0225 cannot berepresented exactly:That's not what he's asking about. He's asking why his Python 2.3 rounds0.0225 *up* to 0.023 while his Python 2.4 rounds *down* to 0.022. It'sthe change in behavior that he's concerned with and isn't just the usualfloating point problem. I would say the usual floating point problem is involved. Python 2.3 isn't rounding 0.0225 up while pyton 2.4 rounds it down. 0.0225 isn't representable and it happens that the actual number you get differ. Now which number python should choose when it is fed 0.0225, I don't know. But expressing the different behaviour as a change in round, suggest that the O.P. would be wise to learn about floating point problems Uhh, Python didn't change anything between 2.3 and 2.4 wrt round(). That is what I said, or at least meant to say. The reason he is seeing a difference is because the two executables were built with different compilers. The fact that the version of Python was different in the two cases obscures the real cause. IMO the real cause is unimportant. The real cause can be a different CPU or a different compilor or a different library. What it boils down to is that you can't expect 0,0225 to be represented in a value that will be rounded up. Saying that 0.0225 can't be represented exactly as a binary floating point number is entirely true but is an incomplete answer. Yes, obviously binary floating point representations are involved. But one could always define a standard representation scheme that always gives the same answer for the same input. Can we? I don't think we can, unless you are working with decimal numbers. If you work with floats you are basically saying that the program should choose the best approximation it can. That approximation can differ according to circumstances. So one must be prepared that round(0.225,3) can give different results in different circumstances. The fact is that for some reason there are two schemes being used. Another fact is that this has nothing to do with difference in the versions of Python he is using. Most of Python's floating point behavior is a platform-dependent accident (as Tim Peters always says), and Nils is using two slightly different platforms. Yes and he wouldn't have blamed it on round, had he known or thought about FP representations. -- Antoon Pardon Sep 15 '05 #15

### This discussion thread is closed

Replies have been disabled for this discussion.