3

I was just using python as a calc and I saw this

Python 2.7.3 (default, Aug  1 2012, 05:14:39) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 62 * 41.2 * 2 / 250
20.435200000000002
>>> 62 * 4.12 * 2 / 25
20.4352
>>>

Just to be sure I fired the following code through gcc but that did not show me the above behaviour. I understand this is potentially something with rounding off, but it should then be uniform. Why is python adding up the trailing 00000000002 when mathematically it is not supposed to be there.

C/C++ code

#include <stdio.h>
int main () {
  printf ("%lf %lf \n", 62 * 41.2 * 2 / 250, 62 * 4.12 * 2 / 25);
}

results in

20.435200 20.435200

If someone is curious about the particular numbers they belong to some engine displacement computation comparisons :)

batfan47
  • 97
  • 1
  • 6
  • 2
    Floating point arithmetic, it works like this in most languages: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html Python applies some rounding to the print output as you can see here http://docs.python.org/2/tutorial/floatingpoint.html but the number stored in both cases is only as accurate as floating point allows it to be. – Michael Greene Apr 10 '13 at 15:41
  • It's floating point differences. `41.2/10 != 4.12` due to the internal representation. – mgilson Apr 10 '13 at 15:44

5 Answers5

8

Aside from @Ashwini Chaudhary answer,

Question :

Why is python adding up the trailing 00000000002 when mathematically it is not supposed to be there

Answer :

Because value in the machine is not exact. It's not a bug in Python or the bug in your code either. You will see this exact same problem in all languages that support binary floating-point arithmetic. However, different languages may display it differently (round-off).

Try this:

0.1 + 0.2

You will get

0.30000000000000004

This is because 0.1 can't be represent in Binary form exactly. In base 2, or Binary, 0.1 is the infinity repeating numbers

0.0001100110011001100110011001100110011001100110011...

So, Python decided to round this off instead.

I suggest you read more here.

Thanakron Tandavas
  • 5,615
  • 5
  • 28
  • 41
4

Don't worry, C actually does the same, you're just not printing it because you show too few digits:

#include <stdio.h>
int main () {
    printf ("%.16lf %.16lf \n", 62 * 41.2 * 2 / 250, 62 * 4.12 * 2 / 25);
}

gives

20.4352000000000018 20.4351999999999983
Elmar Peise
  • 14,014
  • 3
  • 21
  • 40
3

use print in python too.

In [87]: print 62 * 41.2 * 2 / 250
20.4352

In [88]: print 62 * 41.2 * 2 / 25
204.352

Python shell uses repr to show the output, that's why you're getting that weird output:

In [89]: print repr(62 * 41.2 * 2 / 250)
20.435200000000002

Whereas print uses str:

In [90]: print str(62 * 41.2 * 2 / 250)
20.4352
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
2

Try using Decimal

>>> from decimal import Decimal
>>> dec = Decimal('41.2')
>>> 62 * dec * 2 / 250
Decimal('20.4352')

Please note that you must use a string as parameter. If you use float as parameter it will fail.

>>> dec1 = Decimal(41.2)
>>> dec2 = Decimal('41.2')
>>> dec1 == dec2
False
>>> print dec1, dec2
41.2000000000000028421709430404007434844970703125 41.2
Pancho Jay
  • 490
  • 5
  • 10
0

You are being exposed to the usual oddities of working with binary floating point numbers; these are common to most computer languages. Different rounding strategies on output can hide these problems, but they exist nonetheless. The usual reference for understanding these is "What Every Computer Scientist Should Know About Floating-Point Arithmetic", but there's also a Python specific guide at "Floating Point Arithmetic: Issues and Limitations"

Python has a couple of solutions that can be used to get more exact results when needed. The first is the decimal module which works with decimal numbers rather than binary numbers.

>>> from decimal import Decimal
>>> Decimal(62) * Decimal("41.2") * Decimal(2) / Decimal(250)
Decimal('20.4352')
>>> Decimal(62) * Decimal("4.12") * Decimal(2) / Decimal(25)
Decimal('20.4352')

There is also the fractions module which keeps track of a separate numerator and denominator, so any possible fraction can be represented.

>>> from fractions import Fraction
>>> Fraction("41.2")
Fraction(206, 5)
>>> Fraction(62) * Fraction("41.2") * Fraction(2) / Fraction(250)
Fraction(12772, 625)
>>> Fraction(62) * Fraction("4.12") * Fraction(2) / Fraction(25)
Fraction(12772, 625)
>>> float(Fraction(12772, 625))
20.4352
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622