フロートの非決定的合計


10

明らかなこぶしを述べさせてください。浮動小数点型は10進数値を正確に表すことができないことを完全に理解しています。これはそれについてではありません!それにもかかわらず、浮動小数点計算は決定論的であることになっています

これが邪魔にならないところで、今日私が観察した奇妙なケースを紹介しましょう。浮動小数点値のリストがあり、それらを合計したいと思います。

CREATE TABLE #someFloats (val float);
INSERT INTO #someFloats (val) VALUES (1), (1), (1.2), (1.2), (1.2), (3), (5);

SELECT STR(SUM(#someFloats.val), 30, 15) FROM #someFloats;

DROP TABLE #someFloats;

-- yields:
--   13.600000000000001

これまでのところ、とても良いです-ここに驚きはありません。1.2バイナリ表現で正確に表現できないことは誰でも知っているので、「不正確な」結果が予想されます。

ここで、別のテーブルを左結合すると、次の奇妙なことが起こります。

CREATE TABLE #A (a int);
INSERT INTO #A (a) VALUES (1), (2);

CREATE TABLE #someFloats (val float);
INSERT INTO #someFloats (val) VALUES (1), (1), (1.2), (1.2), (1.2), (3), (5);

SELECT #A.a, STR(SUM(#someFloats.val), 30, 15)
  FROM #someFloats LEFT JOIN #A ON 1 = 1
 GROUP BY #A.a;

DROP TABLE #someFloats;
DROP TABLE #A;

-- yields
--   1   13.600000000000001
--   2   13.599999999999998

sql fiddle、そこに実行プランも表示されます)

私が持っている同じの総和と同じ値が、異なる浮動小数点エラーを。テーブル#Aに行を追加すると、値が2つの値の間で交互に表示されることがわかります。この問題を再現できたのはLEFT JOIN; INNER JOINここで期待どおりに動作します。

これはDISTINCTGROUP BYまたはPIVOTを別の値と見なすことを意味するため、これは不便です(実際にこの問題を発見した方法です)。

明白な解決策は値を丸めることですが、私は興味があります:この動作について論理的な説明はありますか?

回答:


15

実際、あなたが参照しているリンクは、浮動小数点算術計算が常に確定的であることを示していません。実際、回答の1つでは、加算は連想的ではない(つまり、(a + b) + c必ずしも等しいとは限らないa + (b + c))と述べられていますこれは、この回答でも述べられています

ストリーム集約が各グループの行を異なる順序で処理した場合-通常、SQL Serverはこれを自由に実行できます。ORDER BY適切な句がない場合、オプティマイザは追加を実行する順序に関係なく、スキャンまたはシークまたは他のクエリ演算子が最も高速になるものを選択します。これにより、観察される動作が説明される可能性があります。

加算は常に決定論的です。同じ2つのフロートを入れると、同じフロートが得られます。しかし、フロートを異なる順序で一緒に追加すると、異なる結果が得られる可能性があります。


連想性は決定論とは関係がないので、そのビットは誤解を招くものです。
Mooing Duck

浮動小数点加算の非関連性により、SQL Server集計関数の非決定的な動作が発生しますSUM()。@ MooingDuckに同意しますか?
mustaccio

番号?整数除算は明確な反例です。関連付けはありませんが、完全に確定的です。同様に、浮動小数点除算は、結合的でなく、なおかつ確定的でなければなりません。そのことから、追加が非結合的であり、なおかつ確定的であることは合理的であると結論付けます。つまり、追加の順序が確定的でない場合、結果も同様に確定的ではないため、最初と最後の文は関係なく正しいです。
Mooing Duck

整数除算は、SUM()浮動小数点引数に対するSQL Serverの反例ですが、どのように正確ですか?
mustaccio

1
整数除算は、関連性がなく、確定的です。したがって、算術演算の結合性は決定論とは関係ありません。したがって、の非関連性は、そのSUM()決定論とは無関係である必要があります。これはSUM非決定的であるように見えますが、関連性がないため、関連性の記述は削除する必要があります。
Mooing Duck
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.