Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Round-off / round-up criteria in Python

Tags:

I'm porting a MATLAB code to Python 3.5.1 and I found a float round-off issue.

In MATLAB, the following number is rounded up to the 6th decimal place:

fprintf(1,'%f', -67.6640625);
-67.664063

In Python, on the other hand, the following number is rounded off to the 6th decimal place:

print('%f' % -67.6640625)
-67.664062

Interestingly enough, if the number is '-67.6000625', then it is rounded up even in Python:

print('%f' % -67.6000625)
-67.600063

... Why does this happen? What are the criteria to round-off/up in Python? (I believe this has something to do with handling hexadecimal values.)

More importantly, how can I prevent this difference? I'm supposed to create a python code which can reproduce exactly the same output as MATLAB produces.

like image 780
IanHacker Avatar asked Aug 27 '16 15:08

IanHacker


1 Answers

The reason for the python behavior has to do with how floating point numbers are stored in a computer and the standardized rounding rules defined by IEEE, which defined the standard number formats and mathematical operations used on pretty much all modern computers.

The need to store numbers efficiently in binary on a computer has lead computers to use floating-point numbers. These numbers are easy for processors to work with, but have the disadvantage that many decimal numbers cannot be exactly represented. This results in numbers sometimes being a little off from what we think they should be.

The situation becomes a bit clearer if we expand the values in Python, rather than truncating them:

>>> print('%.20f' % -67.6640625)
-67.66406250000000000000
>>>  print('%.20f' % -67.6000625)
-67.60006250000000704858

So as you can see, -67.6640625 is a number that can be exactly represented, but -67.6000625 isn't, it is actually a little bigger. The default rounding mode defined by the IEEE stanard for floating-point numbers says that anything above 5 should be rounded up, anything below should be rounded down. So for the case of -67.6000625, it is actualy 5 plus a small amount, so it is rounded up. However, in the case of -67.6640625, it is exactly equal to five, so a tiebreak rule comes into play. The default tiebreaker rule is round to the nearest even number. Since 2 is the nearest event number, it rounds down to two.

So Python is following the approach recommended by the floating-point standard. The question, then, is why your version of MATLAB doesn't do this. I tried it on my computer with 64bit MATLAB R2016a, and I got the same result as in Python:

>> fprintf(1,'%f', -67.6640625)
-67.664062>>

So it seems like MATLAB was, at some point, using a different rounding approach (perhaps a non-standard approach, perhaps one of the alternatives specified in the standard), and has since switched to follow the same rules as everyone else.

like image 142
TheBlackCat Avatar answered Sep 24 '22 16:09

TheBlackCat