0

Possible Duplicate:
Python rounding error with float numbers

I created an array with numpy as a = numpy.arange(0,1e5,1,dtype=int). a[18645] is 18645 as expected. When I create another array b=a*10e-15, b[18645] is 186.4999999999e-12. b[18644] is 186.44e-12. Why does Python create these trailing 9s?

This issue came up when I was trying to search for an element in the array with numpy.where. With the trailing 9s, the numpy.where function failed to find 184.45e-12 in b.

Community
  • 1
  • 1
greywanderer
  • 31
  • 1
  • 4
  • Obviously 9 is period (i dont know precisely how it be on english) and you can set count of signs after point or round it – Denis Aug 24 '12 at 16:00
  • Related: [python maths is wrong](http://stackoverflow.com/questions/11950819/11950951#11950951) – Martijn Pieters Aug 24 '12 at 16:15

2 Answers2

5

That's because it is converting to floating points, which aren't exact. Due to rounding errors, the result you get isn't 186.44 - it's a apparently number slightly less than 186.5, hence all the 9s being printed out.

There are actually several sources of error here. First off 1e-15 cannot be exactly represented as a floating point. Second, the multiplication may introduce further errors. Lastly, the result have to be converted back to decimal, but it helpfully truncates the result when printing it.

Some trivia - 1e-15 converted to a double is exactly 0.00000000000000100000000000000007770539987666107923830718560119501514549256171449087560176849365234375

Multiplying this number by 18644 gives 0.0000000000186440000000000017406180102322435293213387375033107673516497015953063 96484375

As you can see this is still fairly accurate. It appears that Numpy is using single floats which would magnify the error exponentially.

Antimony
  • 37,781
  • 10
  • 100
  • 107
  • Antimony is correct, some numbers cannot be represented floating point just as you can't represent 1/3 as a decimal exactly in decimal. – Aaron S Aug 24 '12 at 16:02
  • 1
    Also see [this answer](http://stackoverflow.com/a/2891805/748858) for a way to make the arrays appear 'nicely' when printing. – mgilson Aug 24 '12 at 16:06
  • @AaronS maybe an easier analogy would be trying to represent 2.5 as an integer (it has to be either 2 or 3)... – Andy Hayden Aug 24 '12 at 16:06
  • The floating point conversion makes sense if it is consistent across the board. But it is not, as mention above, between b[18644] and b[18645]. In fact between 18641 and 18646 only 18645 has trailing 9s. I modified the numpy.where expression to work around it though(n.where(n.abs(b - 186.45e-15) < 1e-15)). 'mgilson': The 'nice' printing example is quite helpful. Thanks. – greywanderer Aug 24 '12 at 16:37
0

This representation is caused by the floating point representation.

This issue came up when I was trying to search for an element in the array with numpy.where

You don't test for equality on floating points. You test if the difference is lower than a given precision. And you do this precisely because floating points operations may give unexcpected results.

As a matter of fact, numpy is based on a BLAS called ATLAS which is able to choose from a range of implementations to do a specific type of operation (based on the state of your machine). Therefor if you run twice the same program, you may obtain different results (if you print the full representation of the floats and look at the last numbers).

This is just an example to show that equality testing will almost never work the expected way on floats.

Simon Bergot
  • 10,378
  • 7
  • 39
  • 55