脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|shell|

服务器之家 - 脚本之家 - Python - 基于np.arange与np.linspace细微区别(数据溢出问题)

基于np.arange与np.linspace细微区别(数据溢出问题)

2022-12-24 12:32鬼扯子 Python

这篇文章主要介绍了基于np.arange与np.linspace细微区别(数据溢出问题),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

太长不看的简洁版本

1.x = np.arange(start, end, steps)

Values are generated within the half-open interval [start, stop)
(in other words, the interval including start but excluding stop).

  • 即区间是左闭右开的,不包含end的取值

2.x = np.linspace(start, end, num, endpoint=True)

There are num equally spaced samples in the closed interval [start, stop] or the half-open interval [start, stop) (depending on whether endpoint is True or False).

  • 即endpoint=True区间是左闭右闭的,包含end的取值
  • 即endpoint=False区间是左闭右开的,不包含end的取值

最终结论:

  • 当linspace函数指定参数endpoint=False时,两个函数的效果等价。
  • 当steps和num指定参数都是整数时,arrange会返回numpy.int32数据类型,
  • 而linspace会返回numpy.float数据类型,对应于 C 语言数据类型,每种“整数”有自己的区间,会遇到数据溢出的问题,数值分析中函数绘制曲线将得不到正确的答案。

解决方案:

  • 使用 np.linspace比np.arange好,可以预防数据溢出的问题
  • 使用np.arange时,将步长steps设置为小数,比如1.0

绘制曲线代码:

x = np.arange(0,100,1.0)                           #自变量的范围
x = np.linspace(0, 100, 100,endpoint=False)       # 两者效果等价
y = alpha*(T-x) + beta*(T**4-x**4) + gamma*(u**2)  #因变量
plt.plot(x, y, y*0.0)                              #曲线绘制

问题前夕

数值分析课程作业用python的matplotlib一直得不到正确的曲线图,后用Matlab就可以,明明是一样的函数,但是两者绘制出来的曲线图显示零点不一致,差距很大。

作为一枚不会matlab的学渣,为了得到正确的答案,难道真的必须啃下matlab的语法吗…又问了一下同门,他居然用python得出了正确的答案,排查两个小时一无所获转战Matlab的我留下了羡慕的泪水,赶紧要来了他的代码进行对比实验,终于找出了问题的关键了,预知后事如何请继续往下看…

我的代码

u = 21.0
T = 293.15
alpha = 50.0
beta = 2*(10**(-7))
gamma = 800.0
x = np.arange(0,10000,1)                           #自变量的范围
y = alpha*(T-x) + beta*(T**4-x**4) + gamma*(u**2)  #因变量
plt.plot(x, y, y*0.0)

效果图

基于np.arange与np.linspace细微区别(数据溢出问题)

从图中可以看出函数的零点在[7000,8000]这个范围。

那么问题来了,为什么表达式不是一次函数绘制出来的图形却是一条直线,x^4怎么也不能是一条直线吧???带着这个疑惑,我找了同学要了他的答案来对照,发现零点只有一个,在[1000,1200]这个范围内。我仔细对照了函数方程,苦苦思索了两个小时也没找到答案。

同门的代码

u = 21.0
T = 293.15
alpha = 50.0
beta = 2*(10**(-7))
gamma = 800.0
start = 1000
end = 1500
step = 1
num = (end - start) // step
x = np.linspace(start, end, num)
y = alpha*(T-x) + beta*(T**4-x**4) + gamma*(u**2)
fig = plt.figure(figsize=(6, 6))
plt.plot(x, y, label='Numerical Analysis')
plt.grid(True)
plt.xlim((800, 1500))  # 显示的x的范围(不设置则由程序自动设置)
plt.ylim((-10, 10))  # 显示的y的范围
plt.legend()           # 显示旁注
plt.show(fig)          # 没有输入值默认展示所有对象

效果图

基于np.arange与np.linspace细微区别(数据溢出问题)

从图中可以看出同门的代码跑出来的结果是正确的,并且这条线还是弯的…我以为是plt叠加导致的buff加成,然后我把作图的代码copy到我的代码里,仍然是错误的!!!在逐步分析后,我发现导致这个现象的原因居然只是一行代码的差距!!!展示如下:

代码对比【区别只体现在自变量x】

u = 21.0
T = 293.15
alpha = 50.0
beta = 2*(10**(-7))
gamma = 800.0
x = np.arange(1000,1500,1)           #区别只体现在自变量x所用的函数
#x = np.linspace(1000, 1500, 500)    #区别只体现在自变量x所用的函数
y = alpha*(T-x) + beta*(T**4-x**4) + gamma*(u**2)
plt.plot(x, y)

x = np.arange(1000,1500,1)的效果图

[<matplotlib.lines.Line2D at 0x29e40ceff10>]

基于np.arange与np.linspace细微区别(数据溢出问题)

x = np.linspace(1000, 1500, 500)的效果图

[<matplotlib.lines.Line2D at 0x29e40da97c0>]

基于np.arange与np.linspace细微区别(数据溢出问题)

x = np.arange(1000,1500,0.1)的效果图

基于np.arange与np.linspace细微区别(数据溢出问题)

咦,此时我不禁疑惑,我使用的np.arange也是1000-1500,以1为间隔,自变量取值为

[1000, 1001, 1002,…, 1499]

使用的np.linspace也是把1000-1500切分为500份,

[1000, 1001.00200401, 1002.00400802, …, 1498.99799599, 1500]

效果理应是差不多的。

但是为什么我用arange函数的时候需要将精度设为0.1,才能实现linspace精度为1的效果呢???

官方API解析

x = np.arange(0,10,1)
#输出: [0 1 2 3 4 5 6 7 8 9]
x1 = np.linspace(0, 10, 10, endpoint=False)
#输出:[0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]
x1 = np.linspace(0, 10, 10)
#输出:[ 0.          1.11111111  2.22222222  3.33333333  4.44444444  5.55555556
6.66666667  7.77777778  8.88888889 10.        ]

上面的例子表明:当指定endpoint为False时,两个函数的效果等价。此时,我似乎发现了一点不对劲,一个输出的是整数,一个输出的是小数???会不会这个对结果造成了影响呢?怀着想都不敢想的梦想,我尝试了一下将整数设置为浮点数…

x = np.arange(1000,1500,1.0)的效果图

基于np.arange与np.linspace细微区别(数据溢出问题)

我的天呀,居然把取样间隔从1设置为1.0效果居然有这么大的不同,此时我的疑惑非但没有减轻,反而更加疑惑了,整数和浮点数作图效果的天差地别,又是什么原因导致的呢?我想了想,毕竟我学的这门课叫做《数值分析》啊,那我毕竟也得有点这方面的一点见解?…也许这个表达式太过于复杂,整数输进去再经过七七七八八的加减乘除后,自变量为整型+1、-1差别很细微可以忽略不计。最主要是我的因变量的范围是10^5,微小的变化也许体现不出来???但是我的常量设置的时候特地全都设置为浮点数了。

通过MATLAB已知零点在[1118,1119]之间,我特地打印出x=1118和x=1119对应因变量的值:

x1 = 1118;      #对应因变量y=572.5297745541902
x2 = 1119;      #对应因变量y=-596.9030544458074
x = np.arange(1110,1120,1.0)  

输出:

[9820.44892975 8674.86472155 7526.31814255 6374.80385755 5220.31652655
4062.85080475 2902.40134255 1738.96278555 572.52977455 -596.90305445]
x = np.arange(1110,1120,1)

输出:

[313045.14002735 313617.54273755 313327.98961775 313035.46879195
313598.96837935 313300.49611675 312999.04011375 312694.59501595
313246.14892335 312935.70955355]

由x1,x2可以看出零点确实在这个范围内,但是自变量为整型时,很有可能是溢出了,导致计算值与真实值天差地别。不但正数数值不对,而且零点也消失了。但是我单独输入1119也是整型,为什么可以得到正确值?python最新版本对整型没有限制了,原来能表示的最大整型为9223372036854775807。Numpy 中的整数类型对应于 C 语言的数据类型,每种“整数”有自己的区间,要解决数据溢出问题,需要指定更大的数据类型(dtype)!!!

原来我单独输入x的值,此时用的是python的版本表示的整型,是源码里自带了溢出防止办法,所以函数值能正确输出,但是x = np.arange(1110,1120,1),对应的每一个自变量的类型输出为:

<class ‘numpy.int32’>

只能表示数据范围整数(-2147483648 to 2147483647),当x取值为10^3时,对应四次方结果为1000000000000,已经超出可以表示的范围了。到这里已经把我的坑解释的很清楚了。

解决办法

大家以后要作图绘制曲线最好使用np.linspace,会自动把自变量取值设置为浮点型,或者np.arange(start,end,1.0),步长设置为浮点型!!!这样的话才不会出现溢出等问题!!!!

花了半天的时间终于把这个坑给解决了,给自己

基于np.arange与np.linspace细微区别(数据溢出问题)

以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/qq_44722174/article/details/115632368

延伸 · 阅读

精彩推荐