我有一个简单的程序来计算函数。
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 :(得分:2)
请注意,此处简单地用浮点数替换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返回的值基本相同,因此我们可以确信它们是正确的。
相比之下,使用“常规”浮点算法返回的值几乎是一个随机数。
答案 1 :(得分:1)
对于要在结果中预期为十进制值的数学表达式的求值,将函数中的数字值特别定义为浮点数很重要:
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.)
。
答案 2 :(得分:-1)
这需要使用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')
您会看到2到n
的幂仍然是整数。似乎发生了简单的移位,当结果不再可以包含在整数数据类型中时,结果为全零。
修复很简单,使用n.astype(float)
代替n
。