4

I would need to have a float variable rounded to 2 significant digits and store the result into a new variable (or the same of before, it doesn't matter) but this is what happens:

>>> a    
981.32000000000005    
>>> b= round(a,2)    
>>> b
981.32000000000005

I would need this result, but into a variable that cannot be a string since I need to insert it as a float...

>>> print b    
981.32

Actually truncate would also work I don't need extreme precision in this case.

8
  • 3
    are you sure? I cannot reproduce the issue you are demonstrating. Commented Jul 8, 2014 at 14:41
  • Why can't it be a string? Just convert it again to float later. Commented Jul 8, 2014 at 14:41
  • @karthikr Maybe different processors? Commented Jul 8, 2014 at 14:42
  • 1
    possible duplicate of python limiting floats to two decimal points Commented Jul 8, 2014 at 14:44
  • 3
    @user3484521 The value is just the same on 2.7.5, there's just some magic going on in the way the value is printed. Commented Jul 8, 2014 at 14:48

4 Answers 4

10

What you are trying to do is in fact impossible. That's because 981.32 is not exactly representable as a binary floating point value. The closest double precision binary floating point value is:

981.3200000000000500222085975110530853271484375

I suspect that this may come as something of a shock to you. If so, then I suggest that you read What Every Computer Scientist Should Know About Floating-Point Arithmetic.

You might choose to tackle your problem in one of the following ways:

  1. Accept that binary floating point numbers cannot represent such values exactly, and continue to use them. Don't do any rounding at all, and keep the full value. When you wish to display the value as text, format it so that only two decimal places are emitted.
  2. Use a data type that can represent your number exactly. That means a decimal rather than binary type. In Python you would use decimal.
Sign up to request clarification or add additional context in comments.

15 Comments

how is it not possible?
@PadraicCunningham Because 981.32 cannot be represented exactly as a binary floating point value
@DavidHeffernan, I understand the floating point arithmetic problems, what I meant is I don't understand why you cannot round the OP's input to 981.32 when I can?
@PadraicCunningham I cannot do that. You cannot do that. Nobody can do that. Not in binary floating point. It is impossible.
@user3484521 what you are seeing on the machine that is "working" is a simplified display of the number, not its actual content.
|
1

Try this :

Round = lambda x, n: eval('"%.' + str(int(n)) + 'f" % ' + repr(x))

print Round(0.1, 2)
0.10
print Round(0.1, 4)
0.1000
print Round(981,32000000000005, 2)
981,32

Just indicate the number of digits you want as a second kwarg

Comments

1

I wrote a solution of this problem. Plz try

from decimal import *
from autorounddecimal.core import adround,decimal_round_digit


decimal_round_digit(Decimal("981.32000000000005")) #=> Decimal("981.32")
adround(981.32000000000005) # just wrap decimal_round_digit

More detail can be found in https://github.com/niitsuma/autorounddecimal

1 Comment

Nice, but bringing in a lisp interpreter for this is arguably not what most people want.
0

There is a difference between the way Python prints floats and the way it stores floats. For example:

>>> a = 1.0/5.0
>>> a
0.20000000000000001
>>> print a
0.2

It's not actually possible to store an exact representation of many floats, as David Heffernan points out. It can be done if, looking at the float as a fraction, the denominator is a power of 2 (such as 1/4, 3/8, 5/64). Otherwise, due to the inherent limitations of binary, it has to make do with an approximation.

Python recognizes this, and when you use the print function, it will use the nicer representation seen above. This may make you think that Python is storing the float exactly, when in fact it is not, because it's not possible with the IEEE standard float representation. The difference in calculation is pretty insignificant, though, so for most practical purposes it isn't a problem. If you really really need those significant digits, though, use the decimal package.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.