Numpy dot は、コンパイル時にリンクする (または独自にビルドする) BLAS ライブラリを呼び出すルーチンの 1 つです。これの重要性は、BLAS ライブラリが、計算が実行する丸めの数を制限する積和演算 (通常は Fused-Multiply Add) を利用できることです。
次のようにします。
>>> a=np.ones(1000,dtype=np.float128)+1E-14
>>> (a*a).sum()
1000.0000000000199948
>>> np.dot(a,a)
1000.0000000000199948
正確ではありませんが、十分に近いです。
>>> a=np.ones(1000,dtype=np.float64)+1E-14
>>> np.dot(a,a)
1000.0000000000176 #off by 2.3948e-12
>>> (a*a).sum()
1000.0000000000059 #off by 1.40948e-11
ナイーブが行う浮動小数点丸めのnp.dot(a, a)
約半分の数を使用するため、2 つのうちより正確になります(a*a).sum()
。
Nvidia の本には、4 桁の精度の次の例があります。rn
は、最も近い 4 桁に四捨五入することを表します。
x = 1.0008
x2 = 1.00160064 # true value
rn(x2 − 1) = 1.6006 × 10−4 # fused multiply-add
rn(rn(x2) − 1) = 1.6000 × 10−4 # multiply, then add
もちろん、浮動小数点数は基数 10 で小数点第 16 位に丸められませんが、おわかりでしょう。
np.dot(a,a)
上記の表記法に追加の疑似コードを配置すると、次のようになります。
out=0
for x in a:
out=rn(x*x+out) #Fused multiply add
ながら(a*a).sum()
:
arr=np.zeros(a.shape[0])
for x in range(len(arr)):
arr[x]=rn(a[x]*a[x])
out=0
for x in arr:
out=rn(x+out)
(a*a).sum()
このことから、と比較してを使用すると、数値が 2 倍丸められることが簡単にわかりnp.dot(a,a)
ます。これらの小さな違いを合計すると、答えが微妙に変わる可能性があります。追加の例はここにあります。