丸め誤差が発生しています。デフォルトでarray()
は、 を含むオブジェクトを返しますdtype=float64
。r
どんどん大きくしていくと、配列積を正確に表すための仮数スペースが不足しています。これをテストする方法は次のとおりです。
def testcross(r, dt):
a = array([1, 2, 3], dtype=dt)*r
b = array([-1, 2, 1], dtype=dt)*r
c = cross(a/norm(a), b/norm(b))
return dot(c, a)
for rr in logspace(4, 15, 10):
print "%10.2f %10.2f %g" % (testcross(rr, float32), testcross(rr, float64)
結果:
-0.00 0.00 10000
0.00 -0.00 166810
0.00 0.00 2.78256e+06
-4.00 0.00 4.64159e+07
-64.00 0.00 7.74264e+08
1024.00 0.00 1.29155e+10
0.00 0.00 2.15443e+11
-524288.00 0.00 3.59381e+12
0.00 -0.02 5.99484e+13
-134217728.00 0.00 1e+15
でさえ「完璧」ではないことに注意しfloat64
てr=5.99484e13
ください。これは、 に到達するずっと前に精度が低下し始めていることを示していr=1e15
ますfloat64
。予想通り、精度が低いと事態はさらに悪化しfloat32
ます。
OPの提案に従ってください。32ビットと64ビットの浮動小数点表現の仮数フィールドは、それぞれ24ビットと53ビットです(暗黙のビットを含む)。を取るlog10([2**24, 2**53])
と、これはそれぞれ約 7 桁と 16 桁に相当することがわかります。これは、最初に指摘されたように、およびの周りr=4.6e7
に表示される表形式のエラーに対応しています。丸めは、内積によって基礎となる行列計算が大きな数を減算する場合に発生し、その差はいずれかの大きな数の仮数で表すことができません。float32
r=1e16