Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change in Python built in round() function between 2.4 and 2.7

Has the built in round() function in Python changed between 2.4 and 2.7?

Python 2.4:

Python 2.4.6 (#1, Feb 12 2009, 14:52:44)
[GCC 3.4.6 20060404 (Red Hat 3.4.6-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = 1480.39499999999998181010596454143524169921875
>>> round(f,2)
1480.4000000000001
>>>

Python 2.7:

Python 2.7.1 (r271:86832, May 13 2011, 08:14:41)
[GCC 3.4.6 20060404 (Red Hat 3.4.6-11)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = 1480.39499999999998181010596454143524169921875
>>> round(f, 2)
1480.39
>>>

Is there anyway to get the Python 2.4 behaviour back?

I'm aware that the right answer is of course to use the decimal arithmetic module. Unfortunately, this probably isn't an option at this point given time limitations.

Update

For context i'm comparing values in two systems, one of which uses a decimal representation and the other a floating point one. This may (or may not) be a legitimate difference between the systems which needs to be checked further, so i'll consult users and deal with it at the "reporting" level, rather than at the point I get the data from the systems.

Thanks for your help!

like image 860
Paul Johnson Avatar asked Dec 28 '22 09:12

Paul Johnson


2 Answers

Probably not since Python 2.4 actually returned an incorrect result. Since you are rounding away an amount that is strictly less than 5, the correct result should be rounded down.

If you can describe the exact behaviour you need, we may be able to create an alternative approach.

like image 25
casevh Avatar answered Dec 31 '22 13:12

casevh


The answer to your first question is: yes, round was fixed in Python 2.7.

The answer to your second question is: I'm not sure, short of actually using an earlier Python (2.6 should still exhibit 2.4's behavior). In this particular case, your value is indistinguishable from 1480.395, and 1480.395 (to us base-10 humans) rounds to 1480.40. So I suppose you could try first rounding to one place beyond what you are really after, turn that into a string, then get a Decimal from that... but sorry, I can't think of anything that doesn't involve Decimal. If I think of something (before someone else posts something better), I'll come back and edit.

(But really, is Decimal all that hard to use?)

Edit: Here is an example of how to use Decimal:

>>> from decimal import Decimal
>>> f = Decimal('1480.395')
>>> f.quantize(Decimal('0.00'))
Decimal('1480.40')
>>> float(Decimal('1480.40'))
1480.4

Some notes:

Python 2.7 allows you to use floats as input to Decimal. Don't do this as you would be back where you started. Also, don't use the built-in round function on a Decimal, because that function is going to convert your Decimal right back to float, and thus you would be back where you started. In its simplest form, Decimal's quantize takes another Decimal that has the number of decimal places you really want (think of it as a template for the rounding). If your data absolutely has to be float, then only convert back to float after all your Decimal calculations are done.

Finally: I'm not sure this covers all the possible weird corner cases in Python 2.4's float behavior. If you are relying on exactly Python 2.4's behavior, there may be no substitute to running on Python 2.4. What I have described above is merely one step closer to human-style rounding.

like image 200
John Y Avatar answered Dec 31 '22 12:12

John Y