## round builtin inaccuracies

A forum for general discussion of the Python programming language.

### round builtin inaccuracies

The other day I was reading a post where someone had to write a function to emulate the round builtin. They (as well as someone assisting them) both ignored the fact that the function was supposed to take an optional precision argument. I decided to see how well I could do performance wise vs the builtin.

Well... as expected, pretty dismally. But after I wrote mine I started testing it to confirm it corresponded to the builtin.

Mine is as follows:
Code: Select all
`def my_round(number,precision=0):    scale = 10**precision    big = number*scale    big_i = int(big)    round_big = big_i+int(2*(big-big_i))    return round_big/float(scale)`
And a little test:
Code: Select all
`if __name__ == "__main__":    tests = 10000    for i in range(tests):        num = randint(0,10000)+random()        prec = randint(-10,10)        builtin,mine = round(num,prec),my_round(num,prec)        results = "Test {} failed for {:.{p1}f},{p}: builtin = {:.{p}f}, mine = {:.{p}f} "        assert builtin==mine,results.format(i,num,builtin,mine,p=prec,p1=prec+1)`

For the most part it performs identically (result wise), but occasionally it differs; so I investigated these exceptions. And well, it seems that for those cases when the results differed, it was mine that was correct. The built in round doesn't always handle decimals that end in a 5 consistently. And neither does my version for that matter.

So the reason for this is obviously floating point precision; but what is a good solution? It seems like a function that can't consistently round things that are as simple as:
Code: Select all
`>>> round(0.285,2)0.28>>> round(0.385,2)0.39`

I have occasionally run into these floating point precision issues and I never really know the best solution. I suppose one can always use a tolerance inequality to force the machine to admit that something like 0.9999999999999999 is really 1 but this seems like such a pain.

-Mek
• Use code tags when posting code.
• Include any errors with your post (in code tags).
• Make examples the minimum length to demonstrate your issue.

Mekire

Posts: 1711
Joined: Thu Feb 07, 2013 11:33 pm
Location: Tucson, Arizona

### Re: round builtin inaccuracies

Due to the reasons discussed here we will be moving to python-forum.io/ on October 1 2016
This forum will be locked down and no one will be able to post/edit/create threads, etc. here from thereafter. Please create an account at the new site to continue discussion.

Yoriz

Posts: 1672
Joined: Fri Feb 08, 2013 1:35 am
Location: UK

### Re: round builtin inaccuracies

Using Decimal is the most common way to get around that in Python. Though that does involve a significant preformance hit, so you wouldn't want to use it, e.g., for 3D graphics. Another way is to avoid floating point entirely. For example, if you're working with highly precise timings (e.g. you're preformance testing an embedded system), and it is important that you record the exact value of 1.234567901 seconds, you can instead store it as 12345678901 nano seconds and then use integer arithmetic (including division) throughout your application. If you are stuck with using native floating point types, then considering values whos absolute difference is smaller than the machine epsilon as being equal is the the only way around this, as it is essentially a hardware limitation.
setrofim

Posts: 288
Joined: Mon Mar 04, 2013 7:52 pm