3

Possible Duplicate:
Python rounding error with float numbers

I have a rounding Problem in Python. If i calculate

32.50 * 0.19 = 6.1749999999999998

But this should be 6.175. If i round 6.1749999999999998 with 2 decimal places it correctly shows 6.18. So i can live with that.

But if i calculate this:

32.50 * 0.19 * 3 = 18.524999999999999

This should be 18.525. If i round the value 18.524999999999999 with two decimal places it shows 18.52.

It should show me 18.53. What am i doing wrong and how can i fix it ?

Community
  • 1
  • 1
fastidias
  • 53
  • 1
  • 1
  • 3
  • Try `print 32.50 * 0.19` or `print 32.50 * 0.19 * 3`. Python knows how to correctly display those floating point values. As long as that is the case, you're as close as a computer will be to the correct (decimal) value with floating point storage. If you really need an _exact_ answer (you don't) use `Decimal.decimal`. – agf Sep 22 '11 at 13:21
  • -1. Typing the title of this post into StackOverflow's search easily finds answers to this question. -1 is for not putting forth the effort to do this. – Steven Rumbalski Sep 22 '11 at 14:35

7 Answers7

7

What Every Computer Scientist Should Know About Floating-Point Arithmetic.

In short - you should not rely on precise values of float numbers because of the way they are stored in the memory.

See also python docs about it - Floating Point Arithmetic: Issues and Limitations. It contains the next passage:

For example, if you try to round the value 2.675 to two decimal places, you get this

>>> round(2.675, 2)
2.67

The documentation for the built-in round() function says that it rounds to the nearest value, rounding ties away from zero. Since the decimal fraction 2.675 is exactly halfway between 2.67 and 2.68, you might expect the result here to be (a binary approximation to) 2.68. It’s not, because when the decimal string 2.675 is converted to a binary floating-point number, it’s again replaced with a binary approximation, whose exact value is

2.67499999999999982236431605997495353221893310546875

Since this approximation is slightly closer to 2.67 than to 2.68, it’s rounded down.

Stefan van den Akker
  • 6,661
  • 7
  • 48
  • 63
Roman Bodnarchuk
  • 29,461
  • 12
  • 59
  • 75
  • Although the docs nor the tutorial didn't get updated, in Python 2.7.4 `round(2.675, 2)` will now give `2.68` as expected. – Stefan van den Akker Sep 30 '13 at 08:26
  • @Neftas: What do you base that claim on? On my machine with Python 2.7.6, `round(2.675, 2)` rounds down, just as described in the documentation. There haven't been any significant changes to the `round` algorithm since Python 2.7.0. – Mark Dickinson Mar 03 '14 at 20:29
  • You're right, @MarkDickinson. At the time I wrote that, I tried it out of course, but now my new installation of Python 2.7.3 rounds down. So it was probably a mistake on my side. – Stefan van den Akker Mar 03 '14 at 20:32
  • @Neftas: Okay, that makes sense. The history of the `round` function is quite a mess: it *mostly* rounds halfway cases up in Python 2.6, *always* rounds halfway cases up in Python 2.7, and *always* rounds halfway cases to the nearest even result in Python >= 3.1. Except that of course thanks to the underlying binary representation, things that *look* like halfway cases in decimal aren't necessarily actual halfway cases. – Mark Dickinson Mar 03 '14 at 20:42
  • Not something you would want to rely on then in your code, obviously. It's probably best to always use the `decimal` module for this kind of division (as recommended in the Python reference). – Stefan van den Akker Mar 05 '14 at 07:07
6

If you need exact arithmetic, you could use the decimal module:

import decimal
D=decimal.Decimal

x=D('32.50')*D('0.19')
print(x)
# 6.1750
print(x.quantize(D('0.01'),rounding=decimal.ROUND_UP))
# 6.18

y=D('32.50')*D('0.19')*D('3')
print(y)
# 18.5250
print(y.quantize(D('0.01'),rounding=decimal.ROUND_UP))
# 18.53
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
3

Use the Decimal Module from python to do accurate floating arithmatic

from decimal import Decimal, ROUND_UP

value = Decimal(32.50 * 0.19 * 3)
print (value.quantize(Decimal('.01'), rounding=ROUND_UP))

Output: 18.53
Serdalis
  • 10,296
  • 2
  • 38
  • 58
  • He doesn't really need `Decimal` though, he just doesn't understand how floating point works. – agf Sep 22 '11 at 13:27
  • The OP asked how to fix it (`Decimal`). The Link also explains why the OP is having this problem. – Serdalis Sep 22 '11 at 13:29
2

You're doing nothing wrong, and it isn't Python's fault either. Some decimal numbers just cannot be precisely represented as binary floats.

Just like you can't write 1/3 in decimal (0.33333....), you can't write decimal 0.1 in binary (0.0001100110011001100110011001100110011001100110011...).

Solution A:

Use print 32.5 * 0.19 - it will automatically round the result.

Solution B:

Use the Decimal module if you actually need this precision, for example when calculating with monetary values.

Solution C:

Use Python 3.2 or Python 2.7 which will automatically round the result in an interactive session.

Python 2.7.2 (default, Jun 12 2011, 14:24:46) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 32.50 * 0.19
6.175
Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
1

http://docs.python.org/library/functions.html#round

Creshal
  • 493
  • 1
  • 4
  • 15
0

I don't think that is wrong. Take this from the Python interpreter:

>>> round(18.524999999999999,2)
18.52
>>> round(6.1749999999999998,2)
6.17
>>> 

In both cases, the number being rounded was less than 5, so it rounded down. 18.52, and 6.17.

That is correct.

One thing I don't get is why you are getting 6.18, and I get 6.17. I am using Python 3.2.2 (the latest version)

Musaab
  • 1,574
  • 3
  • 18
  • 37
  • 1
    Because he doesn't have exactly that number, that is just the `repr` of the number he's really got. – agf Sep 22 '11 at 13:23
0

You are not doing anything wrong. This is due to the internal representation of the numbers:

For example, try this:

0.1 + 0.1 +  0.1 + 0.1 +  0.1 + 0.1 +  0.1 + 0.1 +  0.1 + 0.1

If you need more precision use the decimal representation

Hernan
  • 5,811
  • 10
  • 51
  • 86