2

First of all, I've read this question and all the related answers. As explained there, the round function rounds a half number to the nearest even number. A simple example:

>>> round(0.5)
0
>>> round(1.5)
2
>>> round(2.5)
2
>>> round(3.5)
4
>>> round(4.5)
4
>>> round(5.5)
6

Now, I still don't understand how the round function works when we set the number of digits:

>>> round(0.05, 1)
0.1
>>> round(0.15, 1)
0.1
>>> round(0.25, 1)
0.2
>>> round(0.35, 1)
0.3
>>> round(0.45, 1)
0.5
>>> round(0.55, 1)
0.6
>>> round(0.65, 1)
0.7
>>> round(0.75, 1)
0.8
>>> round(0.85, 1)
0.8
>>> round(0.95, 1)
0.9

What's going on here? Why am I getting these results and what's the rationale behind them? It doesn't look like it is using even numbers.

Riccardo Bucco
  • 13,980
  • 4
  • 22
  • 50

2 Answers2

2

The issue here has to do with floating point arithmetic, and that the floating literal 0.85 in Python doesn't really mean 0.85 exactly, but some representation which is very close to this value. Consider:

>>> round(0.85, 1)
0.8

In this case, the value 0.85 is being represented by 0.84999999 or something like this, which rounds down to 0.8. I don't have an exact workaround here, but you may look into using the Decimal type if you require exact arithmetic with floating point values.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • 1
    Thanks Tim! Look at my experiment though, do you have any clue about values 0.25 and 0.75? The first one is using the floor function, the second one is using ceil – Riccardo Bucco May 25 '21 at 15:59
  • 1
    @RiccardoBucco The actual representation probably depends on many things, including your Python version, OS, etc. The "best" answer here is to just accept the nature of floating point, and then when you do `var = 0.85` in Python you're not necessarily getting that exact value. – Tim Biegeleisen May 25 '21 at 16:00
  • 1
    @RiccardoBucco 0.25 and 0.75 are integer-multiples of powers of 2, so they are exactly represented by floating point math. As you expect, `0.25` is rounded down to `0.2` and `0.75` is rounded up to `0.8` – Pranav Hosangadi May 25 '21 at 16:01
  • 1
    To be ultra-precise, `0.85` denotes the value 7656119366529843/2**53 = 0.84999999999999997779553950749686919152736663818359375. – dan04 May 25 '21 at 16:01
  • @PranavHosangadi I actually don't expect that. `0.25` should be rounded to `0.3`, right? – Riccardo Bucco May 25 '21 at 16:03
  • 2
    From your question: _"the round function rounds a half number to the nearest even number."_ @RiccardoBucco – Pranav Hosangadi May 25 '21 at 16:03
  • 1
    @PranavHosangadi Right, I'm getting confused, sorry! Thanks again guys – Riccardo Bucco May 25 '21 at 16:04
  • 1
    You might want to mention that `Fraction` is an option if you want exact arithmetic with all rational numbers (and not just those with power-of-ten denominators). – dan04 May 25 '21 at 16:07
1

To further confirm what @Tim Biegeleisen said, here is a little experiment:

>>> for n in [0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95]:
...     print('{:.50f}'.format(n) + ' -> ' + str(round(n, 1)))
... 
0.05000000000000000277555756156289135105907917022705 -> 0.1
0.14999999999999999444888487687421729788184165954590 -> 0.1
0.25000000000000000000000000000000000000000000000000 -> 0.2
0.34999999999999997779553950749686919152736663818359 -> 0.3
0.45000000000000001110223024625156540423631668090820 -> 0.5
0.55000000000000004440892098500626161694526672363281 -> 0.6
0.65000000000000002220446049250313080847263336181641 -> 0.7
0.75000000000000000000000000000000000000000000000000 -> 0.8
0.84999999999999997779553950749686919152736663818359 -> 0.8
0.94999999999999995559107901499373838305473327636719 -> 0.9
Riccardo Bucco
  • 13,980
  • 4
  • 22
  • 50