3

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.

karthikr
  • 97,368
  • 26
  • 197
  • 188
user3484521
  • 39
  • 1
  • 2
  • 3
    are you sure? I cannot reproduce the issue you are demonstrating. – karthikr Jul 08 '14 at 14:41
  • Why can't it be a string? Just convert it again to float later. – aIKid Jul 08 '14 at 14:41
  • @karthikr Maybe different processors? – aIKid Jul 08 '14 at 14:42
  • 1
    possible duplicate of [python limiting floats to two decimal points](http://stackoverflow.com/questions/455612/python-limiting-floats-to-two-decimal-points) – roippi Jul 08 '14 at 14:44
  • http://stackoverflow.com/questions/455612/python-limiting-floats-to-two-decimal-points – jumbopap Jul 08 '14 at 14:44
  • Right I've tried on a different machine where I have Python 2.7.5 and it is working. In the example I used Python 2.5.4 – user3484521 Jul 08 '14 at 14:46
  • 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. – David Heffernan Jul 08 '14 at 14:48
  • I seriously think python should drop float support as a base type and make you have to import it. Too many people get confused on what exactly a float is. – cmd Jul 08 '14 at 14:48

4 Answers4

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.
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 1
    how is it not possible? – Padraic Cunningham Jul 08 '14 at 14:48
  • @PadraicCunningham Because `981.32` cannot be represented exactly as a binary floating point value – David Heffernan Jul 08 '14 at 14:48
  • @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? – Padraic Cunningham Jul 08 '14 at 14:52
  • 2
    @PadraicCunningham I cannot do that. You cannot do that. Nobody can do that. Not in binary floating point. It is impossible. – David Heffernan Jul 08 '14 at 14:53
  • @PadraicCunningham, you can't round the actual stored representation, only the printed version of it. I think that a float can only be precisely stored if, looking at the float as a fraction, the denominator is a power of 2. – TheSoundDefense Jul 08 '14 at 14:54
  • @PadraicCunningham The problem is not fp math. The problem is that number can not be represented exactly in a floating point data type – cmd Jul 08 '14 at 14:55
  • I know what floats are but I'm working with fits files that should comply to a standard in which the data type is set and required even for the header keywords values. I just need to have only significant digits – user3484521 Jul 08 '14 at 14:55
  • @user3484521 then use decimal data type – cmd Jul 08 '14 at 14:56
  • @user3484521, you'll want to use the `decimal` package for that instead of a `float`. – TheSoundDefense Jul 08 '14 at 14:56
  • I've tried on a different machine where I have Python 2.7.5 and it is working. In the example I used Python 2.5.4 – user3484521 Jul 08 '14 at 14:57
  • 2
    @user3484521 what you are seeing on the machine that is "working" is a simplified display of the number, not its actual content. – cmd Jul 08 '14 at 14:58
  • @user3484521 Floating point values have the form `k/2^n` where `k` and `n` are integers. Which value if `k` and `n` is such that `k/2^n` equals `981.32`? – David Heffernan Jul 08 '14 at 15:00
  • another link they may help from the python doc https://docs.python.org/2/tutorial/floatingpoint.html – cmd Jul 08 '14 at 15:03
  • @PadraicCunningham Imagine trying to exactly store 1/3 in 5 (base 10) digits - you can't do it. It is the same for a computer, just with base 2 and significantly more than 5 digits. – rlms Jul 08 '14 at 15:05
  • @sweenyrod, I was on about displaying the number rounded not how the value is stored. The OP was using an older version of Python that is why it was not displayed rounded. – Padraic Cunningham Jul 08 '14 at 15:06
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

Ludovic Aphtes
  • 385
  • 1
  • 3
  • 8
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

niitsuma
  • 117
  • 1
  • 4
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.

TheSoundDefense
  • 6,753
  • 1
  • 30
  • 42