Python 将numpy数组与标量传递给函数会产生不一致的结果
我有一个简单的程序来计算一个函数Python 将numpy数组与标量传递给函数会产生不一致的结果,python,numpy,Python,Numpy,我有一个简单的程序来计算一个函数 import numpy as np def fn(n, x0): return (np.sin(np.arcsin(x0**0.5)*2**n))**2 n = np.arange(100) x0 = 0.3 print(fn(n, x0)) print(fn(50, x0)) 结果如下: [0.3 0.84 0.5376 0.99434496 0.02249224 0.08794536 0.32084391
import numpy as np
def fn(n, x0):
return (np.sin(np.arcsin(x0**0.5)*2**n))**2
n = np.arange(100)
x0 = 0.3
print(fn(n, x0))
print(fn(50, x0))
结果如下:
[0.3 0.84 0.5376 0.99434496 0.02249224 0.08794536
0.32084391 0.87161238 0.44761695 0.98902407 0.04342185 0.16614558
0.55416492 0.98826465 0.04639054 0.17695382 0.58256466 0.97273231
0.10609667 0.37936067 0.94178461 0.21930545 0.68484228 0.86333333
0.47195556 0.99685404 0.01254426 0.04954761 0.18837059 0.61154843
0.95022779 0.18917976 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. ]
0.9931071163166798
这两个结果是不一致的,因为fn(n,x0)
结果中的索引50(其中n=50)元素为零,而对50
的函数进行评估会导致非零值。为什么会这样
为什么结果数组中的大多数元素都是
f(n,x0)
0?根据数学,情况不应该是这样。对于计算结果中预期有十进制值的数学表达式,必须将函数中的数值具体定义为浮点数:
def fn(n, x0):
return (np.sin(np.arcsin(x0**0.5)*2.**n))**2.
然后,对于(fn(n,x0))
我得到结果:
[0.3 0.84 0.5376 0.99434496 0.02249224 0.08794536
0.32084391 0.87161238 0.44761695 0.98902407 0.04342185 0.16614558
0.55416492 0.98826465 0.04639054 0.17695382 0.58256466 0.97273231
0.10609667 0.37936067 0.94178461 0.21930545 0.68484228 0.86333333
0.47195556 0.99685404 0.01254426 0.04954761 0.18837059 0.61154843
0.95022779 0.18917976 0.61356311 0.94841368 0.19570069 0.62960771
0.93280737 0.25071114 0.75142025 0.74715144 0.75566467 0.7385423
0.77239028 0.70321414 0.83481605 0.55159286 0.98935271 0.04213571
0.16144118 0.5415117 0.99310712 0.02738149 0.10652697 0.38071589
0.9430852 0.21470202 0.67442025 0.87831031 0.42752525 0.97898964
0.08227569 0.3020256 0.84322454 0.52878765 0.99668508 0.01321571
0.05216421 0.19777242 0.63463397 0.92749478 0.26899286 0.78654281
0.67157288 0.88225099 0.41553673 0.97146383 0.11088744 0.39436567
0.95536555 0.17056885 0.56590047 0.98262851 0.06827888 0.25446749
0.75885515 0.73197605 0.78474845 0.67567327 0.8765556 0.43282351
0.98194928 0.07089957 0.26349128 0.7762545 0.69473381 0.84831498
0.51470671 0.99913485 0.0034576 0.01378259]
而(fn(n,x0))[50]
的计算结果为0.993107116317
虽然我使用
n=np.arange(100)
获得这些结果,但最好将所有内容都保持为浮动,并使用n=np.arange(100)
这需要一些调试,这在使用numpy
时非常典型。两个常见的原因是
nan
或inf
的计算会传播到后续步骤>>> x0 = 0.3
>>> x0**0.5
0.5477225575051661
没问题。这并不奇怪,因为此步骤与n
无关。下一步
>>> 2**n
array([ 1, 2, 4,
8, 16, 32,
64, 128, 256,
512, 1024, 2048,
4096, 8192, 16384,
32768, 65536, 131072,
262144, 524288, 1048576,
2097152, 4194304, 8388608,
16777216, 33554432, 67108864,
134217728, 268435456, 536870912,
1073741824, 2147483648, 4294967296,
8589934592, 17179869184, 34359738368,
68719476736, 137438953472, 274877906944,
549755813888, 1099511627776, 2199023255552,
4398046511104, 8796093022208, 17592186044416,
35184372088832, 70368744177664, 140737488355328,
281474976710656, 562949953421312, 1125899906842624,
2251799813685248, 4503599627370496, 9007199254740992,
18014398509481984, 36028797018963968, 72057594037927936,
144115188075855872, 288230376151711744, 576460752303423488,
1152921504606846976, 2305843009213693952, 4611686018427387904,
-9223372036854775808, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0,
0])
清楚地显示了有问题的行为。有一堆零,前面有一个大的负数。更仔细地观察结果
>>> (2**n).dtype
dtype('int64')
您可以看到,第n次幂的2仍然是一个整数。似乎发生了一个简单的位移位,当结果不再包含在整数数据类型中时,会导致全零
修复方法很简单,请使用
n.astype(float)
而不是n
请注意,简单地用float替换int不是合适的解决方案。事实上,对于较大的n
,此方法返回的值完全是假的
让我使用bigfloat
一个提供任意精度浮点的库来演示这一点
使用float64,返回n=99,x0=0.3的值
>>> fn(99., 0.3)
0.013782590413701074
为~0.0138
现在,我们将使用1000位的高精度计算正确的值
>>> def fnbig(n, x0):
... n, x0 = map(bigfloat.BigFloat, (n, x0))
... return bigfloat.pow(bigfloat.sin(bigfloat.asin(bigfloat.sqrt(x0))*bigfloat.pow(2, n)), 2)
...
>>>
>>> bigfloat.setcontext(bigfloat.Context(1000))
请注意,0.3必须作为字符串输入,因为从文本0.3生成的float64已经带有一个太大的错误,无法得到正确的答案
>>> fnbig('99', '0.3')
BigFloat.exact('0.363780859940401348053691101648398065131477584225708461696799538248050278540782181716110363889498612214432889606382752875154011855764448898240841915231368492158238806206980341185053867226372528105024157964509865633147960964164133657255856469376571664623973084231004713906743471127849494395877727320492003', precision=1000)
返回约0.364
为了确保这是正确的,让我们将精度加倍到2000位
>>> bigfloat.setcontext(bigfloat.Context(2000))
>>>
>>> fnbig('99', '0.3')
BigFloat.exact('0.3637808599404013480536911016483980651314775842257084616967995382480502785407821817161103638894986122144328896063827528751540118557644488982408419152313684921582388062069803411850538672263725281050241579645098656331479609641641336572558564693765716646239730842310047139067975945820088206827783571320258628882284629795545097600685961974610320482001970915733612836861863674071009032317962504679512051859460424746278292327826581975723619660002116915303723311156451829258099225827808017028059470793304713100650332080089174169114171398280313842625628566029927379227478504732491009738418661061753082431884081337', precision=2000)
返回的精度为1000和2000的值基本相同,因此我们可以确信它们是正确的
相比之下,使用“普通”浮点运算返回的值几乎是一个随机数。因为
np.arange(100)
与50
不同?我真正想知道的是,为什么生成的numpy数组与数学结果不符。大多数元素都是零,不应该是零。我用n=50来检查,只是为了确保它们不应该是零,但是元素中没有一个应该是零。我用n=90来检查,结果仍然不是零。这个函数是一个映射x_n=4x(1-x)的解析解,这是一个混沌映射,所以f(n,x0)
的元素都不应该是零…当我们得到不同的结果时,它更令人困惑,然而,后面的元素都是零,这不应该是这种情况哦,我想我已经发现了原因。与浮点/整数相关。仍然不确定我们之间最初的结果为何不同。修改我的答案…哦,问题解决了,谢谢!我以前遇到过一些问题,因为我还没有用浮点数来指定数字,我真的应该记住这一点。这篇文章(Sarra&Meador,2011)看起来是一个很好的关于这个问题的参考文献:本文中的等式2与我们正在处理的等式相同: