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
363 views
in Technique[技术] by (71.8m points)

python - Inconsistent behavior in np.arange?

When I run:

import numpy as np
np.arange(14.1,15.1,0.1)

I get:

array([14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15. ])

yet when I run:

np.arange(15.1,16.1,0.1)

I get:

array([15.1, 15.2, 15.3, 15.4, 15.5, 15.6, 15.7, 15.8, 15.9, 16. , 16.1])

What is up with the missing 15.1? Why does the output in one case show the final number and in the other case not?

I have read the documentation on numpy-arange. It states that the "interval does not include stop value, except in some cases where step is not an integer and floating point round-off affects the length of out."

My question is: How to get the code to behave consistent?

I am iterating over a list of paired numbers (e.g. 4 and 15, or 44.2 and 46.4) and for each pair, I want to create a list with steps of 0.1 between the pairs (e.g 4 and 4.5 would be: 4.1, 4.2, 4.3, 4.4, 4.5). But it is important that the code behaves consistent.

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

This is due to floating point precision. Taking a look at the actual decimal representation of the floats without any rounding will make it clearer:

15.1%1
# 0.09999999999999964

16.1%1
# 0.10000000000000142

Note that just like python's range, np.arange does not include the end in the created range, hence unless the floating point error results in a value greater than the step in the end of the range, it will not be included. That is the case of the first float, which has a decimal part lower than 0.1.

The docs do suggest using np.linspace when using a non-integer step, since the results can be inconsistent, precisely for the above reason. Moreover it includes a endpoint parameter, which allows you to do:

np.linspace(14.1,15.1, 11, endpoint=True)
# array([14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15. , 15.1])

And, as @divakar suggests, to generalize you can set num as:

start = 14.1
stop = 15.1
step = 0.1
num = 1+int((stop-start)/step)

np.linspace(start, stop, num, endpoint=True)
# array([14.1, 14.2, 14.3, 14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15. , 15.1])

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

...