2

I want to round the number below to two decimal places. The result must be 33.39 but Python gives 33.38 because the 5 rounds to even and hence to 8.

round(33.385, 2)
Fisseha Berhane
  • 2,533
  • 4
  • 30
  • 48

4 Answers4

2

This actually has nothing to do with round-to-nearest/even. 33.385 is a decimal number, but is represented in your hardware as an approximation in binary floating point. The decimal module can show you the exact decimal value of that binary approximation:

>>> import decimal
>>> decimal.Decimal(33.385)
Decimal('33.38499999999999801048033987171947956085205078125')

That's why it rounds to 33.38: the exact value stored is slightly closer to 33.38 than to 33.39.

If you need exact decimal results, don't use your hardware's binary floating point. For example, you could use the decimal module for this with the ROUND_HALF_UP rounding mode.

For example,

>>> from decimal import Decimal as D
>>> x = D("33.385")
>>> x
Decimal('33.385')
>>> twodigits = D("0.01")
>>> x.quantize(twodigits) # nearest/even is the default
Decimal('33.38')
>>> x.quantize(twodigits, rounding=decimal.ROUND_HALF_EVEN) # same thing
Decimal('33.38')
>>> x.quantize(twodigits, rounding=decimal.ROUND_HALF_UP) # what you want
Decimal('33.39')
>>> float(_) # back to binary float
33.39
>>> D(_)  # but what the binary 33.39 _really_ is
Decimal('33.3900000000000005684341886080801486968994140625')
Tim Peters
  • 67,464
  • 13
  • 126
  • 132
1

Actually round() rounds to the closest decimal point you specified. There are some incosistencies with floating point numbers in programming languages, because the computer can't create specific enough decimals with the given bits, so the programming language already shows you what you need to see, but not the real number. You can see the real number by using the decimal library. That way you can see why sometimes numbers that end in 5 round either up or down.

If you want to round down then you can use the math module to do it easily.

import math

math.floor(33.385 * 100) / 100 

And if you want to round up then you can do the same with math.ceil

import math

math.ceil(33.385 * 100) / 100

Or if you wanted you could still use the round() function, but change it a bit

Round up:

decimal_point = 2
change = 0.3 / 10**decimal_point
round(33.385 + change, decimal_point)

Round down:

decimal_point = 2
change = 0.3 / 10**decimal_point
round(33.385 - change, decimal_point)
Filip
  • 898
  • 1
  • 8
  • 24
0

You can do the following:

import math

math.ceil(33.385 * 100.0) / 100.0

Reference: Round up to Second Decimal Place in Python

Rfroes87
  • 668
  • 1
  • 5
  • 15
0

Just a result of floating-point approximation by computers. Computers understand binary and not all floating point values have accurate binary rep. A famous example:

print(0.1 + 0.2 == 0.3)
False

Wonder why? The result is 0.30000000000000004 and it's because 0.2 in binary goes as in 0.00110011001100...

Use @Rfroes87's suggestion to convert your numbers into an integer-precision scale and then round off to nearest integer)

Abhilash
  • 2,026
  • 17
  • 21