24

数学的に同等の算術演算が、数値エラー (たとえば、浮動小数点数を異なる順序で合計するなど) によって異なる結果になる可能性があることを理解しています。

ただし、ゼロを追加するsumと結果が変わる可能性があることに驚きました。これは、何があってもフロートに常に当てはまると思いました: x + 0. == x

これが例です。すべての行が正確にゼロになると予想していました。なぜこれが起こるのか誰か説明してもらえますか?

M = 4  # number of random values
Z = 4  # number of additional zeros
for i in range(20):
    a = np.random.rand(M)
    b = np.zeros(M+Z)
    b[:M] = a
    print a.sum() - b.sum()

-4.4408920985e-16
0.0
0.0
0.0
4.4408920985e-16
0.0
-4.4408920985e-16
0.0
0.0
0.0
0.0
0.0
0.0
0.0
0.0
2.22044604925e-16
0.0
4.4408920985e-16
4.4408920985e-16
0.0

Mとの値が小さい場合は発生しないようですZ

私も確認しa.dtype==b.dtypeました。

もう 1 つの例を次に示します。これは、Python のビルトインsumが期待どおりに動作することも示しています。

a = np.array([0.1,      1.0/3,      1.0/7,      1.0/13, 1.0/23])
b = np.array([0.1, 0.0, 1.0/3, 0.0, 1.0/7, 0.0, 1.0/13, 1.0/23])
print a.sum() - b.sum()
=> -1.11022302463e-16
print sum(a) - sum(b)
=> 0.0

numpy V1.9.2 を使用しています。

4

1 に答える 1

10

短い答え:あなたは違いを見ています

a + b + c + d

(a + b) + (c + d)

浮動小数点の不正確さのため、これは同じではありません。

長い答え: Numpy は、速度 (ベクトル化が容易になります) と丸め誤差の両方の最適化として、ペアごとの合計を実装します。

numpy sum-implementation はここにあります(function pairwise_sum_@TYPE@)。基本的に次のことを行います。

  1. 配列の長さが 8 未満の場合、通常の for ループの合計が実行されます。これが、あなたの場合、奇妙な結果が観察されない理由ですW < 4-同じforループの合計が両方のケースで使用されます。
  2. 長さが 8 ~ 128 の場合、合計を 8 つのビンに累積し、 で合計しr[0]-r[7]ます((r[0] + r[1]) + (r[2] + r[3])) + ((r[4] + r[5]) + (r[6] + r[7]))
  3. それ以外の場合は、配列の 2 つの半分を再帰的に合計します。

したがって、最初のケースでは が得a.sum() = a[0] + a[1] + a[2] + a[3]られ、2 番目のケースb.sum() = (a[0] + a[1]) + (a[2] + a[3])では が得られa.sum() - b.sum() != 0ます。

于 2015-06-26T11:57:47.367 に答える