Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
383 views
in Technique[技术] by (71.8m points)

python - numpy arange: how to make "precise" array of floats?

In short, the problem I encounter is this:

aa = np.arange(-1., 0.001, 0.01)
aa[-1]
Out[16]: 8.8817841970012523e-16

In reality, this cause a series problem since my simulations doesn't allow positive value inputs.

I can sort of get around by doing:

aa = np.arange(-100, 1, 1)/100.
aa[-1]
Out[21]: 0.0

But this is a pain. Practically you can't do this every time.

This seems like such a basic problem. There's gotta be something I am missing here. By the way, I am using Python 2.7.13.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This happens because Python (like most modern programming languages) uses floating point arithmetic, which cannot exactly represent some numbers (see Is floating point math broken?).

This means that, regardless of whether you're using Python 2, Python 3, R, C, Java, etc. you have to think about the effects of adding two floating point numbers together.

np.arange works by repeatedly adding the step value to the start value, and this leads to imprecision in the end:

>>> start = -1
>>> for i in range(1000):
...    start += 0.001
>>> start
8.81239525796218e-16

Similarly:

>>> x = np.arange(-1., 0.001, 0.01)
>>> x[-1]
8.8817841970012523e-16

The typical pattern used to circumvent this is to work with integers whenever possible if repeated operations are needed. So, for example, I would do something like this:

>>> x = 0.01 * np.arange(-100, 0.1)
>>> x[-1]
0.0

Alternatively, you could create a one-line convenience function that will do this for you:

>>> def safe_arange(start, stop, step):
...    return step * np.arange(start / step, stop / step)

>>> x = safe_arange(-1, 0.001, 0.01)
>>> x[-1]
0

But note that even this can't get around the limits of floating point precision; for example, the number -0.99 cannot be represented exactly in floating point:

>>> val = -0.99
>>> print('{0:.20f}'.format(val))
-0.98999999999999999112

So you must always keep that in mind when working with floating point numbers, in any language.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...