1

I wanted values like - 1,1.02,1.04,1.06,1.08 etc... So used numpy in python:

y = [x for x in numpy.arange(1,2,0.02)]

I got the values-

1.0,
1.02,
1.04,
1.0600000000000001,
1.0800000000000001,

I have three questions here:

  1. How do I get exactly values 1,1.02,1.04,1.06,1.08 etc....

  2. Why correct values for 1.02, and 1.04, and not for 1.0600000000000001,

  3. How reliable our programs can be when we can't trust such basic operations in programs that can run into thousands of lines of code, and we do so many calculations in that? How do we cope with such scenario?

There are very similar questions that address problems with floating points in general and numpy library in particular -

Is floating point math broken?

Why Are Floating Point Numbers Inaccurate?

While they address why such a thing happens, here I'm concerned more about how do I deal with such scenario in everyday programming, particularly in numpy python? Hence I've these questions.

Community
  • 1
  • 1

1 Answers1

3
  • First pitfall : do not confuse accuracy and printing policies.

In your example :

In [6]: [x.as_integer_ratio() for x in arange(1,1.1,0.02)]
Out[6]: 
[(1, 1),
 (2296835809958953, 2251799813685248),
 (1170935903116329, 1125899906842624),
 (2386907802506363, 2251799813685248),
 (607985949695017, 562949953421312),
 (2476979795053773, 2251799813685248)]

shows that only 1 has an exact float representation.

In [7]: ['{:1.18f}'.format(f) for f in arange(1,1.1,.02)]
Out[7]: 
['1.000000000000000000',
 '1.020000000000000018',
 '1.040000000000000036',
 '1.060000000000000053',
 '1.080000000000000071',
 '1.100000000000000089']

shows intern accuracy.

In [8]: arange(1,1.1,.02)
Out[8]: array([ 1.  ,  1.02,  1.04,  1.06,  1.08,  1.1 ])

shows how numpy deals with printing, rounding to at most 6 digits, discarding trailing 0.

In [9]: [f for f in arange(1,1.1,.02)]
Out[9]: [1.0, 1.02, 1.04, 1.0600000000000001, 1.0800000000000001, 1.1000000000000001]

shows how python deals with printing, rounding to at most 16 digits, discarding trailing 0 after first digit.

  • Some advise for How do I deal with such scenario in everyday programming ?

Furthermore, each operation on floats can deteriorate accuracy.
Natural float64 accuracy is roughly 1e-16, which is sufficient for a lot of applications. Subtract is the most common source of precision loss, as in this example where exact result is 0. :

In [5]: [((1+10**(-exp))-1)/10**(-exp)-1 for exp in range(0,24,4)]
Out[5]: 
[0.0,
 -1.1013412404281553e-13,
 -6.07747097092215e-09,
 8.890058234101161e-05,
 -1.0,
 -1.0]
B. M.
  • 18,243
  • 2
  • 35
  • 54
  • Hey, thanks for detailed answer. Explanation using method - as_integer_ratio() is really great. I just feel like "welcome to world of floats".. :) – tired and bored dev Apr 03 '16 at 09:53