[Tutor] The '45' bug in round()

Dick Moores rdm at rcblue.com
Mon Mar 19 11:56:04 CET 2007


At 03:29 AM 3/19/2007, Kent Johnson wrote:
>Dick Moores wrote:
>>Yesterday I was shocked, SHOCKED, to discover that round() is 
>>occasionally rounding incorrectly. For example,
>>  >>> print round(0.19945,4)
>>0.1994
>>For rounding of random samples of numbers between 0 and 1 ending in 
>>'45', the error ratio is about 0.041. Here are a few more examples:
>
>As I said yesterday, these are numbers that don't have an exact 
>representation as binary floating point numbers. The actual 
>representation is slightly less than what you ask for and it is 
>rounded correctly. The repr() function will show a decimal 
>approximation of the actual binary number:
>
>In [1]: repr(.19945)
>Out[1]: '0.19944999999999999'
>
>For example 0.19945 is actually stored as approximately 
>0.19944999999999999. What should be the result of
>round(0.19944999999999999, 4)
>
>This is an inherent limitation of binary floating point, not a bug. 
>If you want exact representation of decimal fractions use the decimal module.
>Read more here:
>http://docs.python.org/tut/node16.html
>
>>Comments, Tutors? Am I way out in left field with this?
>
>IMO yes.

Kent, I did understand the points you made in that earlier thread. 
However, I'm unhappy with

 >>> print round(0.19945,4)
0.1994

Am I the only one unhappy with this kind of rounding?

My function, round2() restores me to happiness.  :)

 >>> print round2(0.19945,4)
0.1995

Is there something wrong with it?

Here it is again:

def round2(n, digits=0):
     s = str(n)
     if '.' in s and s[-2:] == '45':
         mantissa = s.split('.')[1]
         if len(mantissa) - digits == 1:
             s = s[:-2] + '5'
             return s
         else:
             return round(float(s), digits)
     else:
         return round(float(n), digits)

Dick




More information about the Tutor mailing list