これら 2 つの sum コマンドに違いがあるのはなぜですか?

これら 2 つの sum コマンドに違いがあるのはなぜですか?

シナリオがある

ここでは、以下の2つのコマンドを使用して特定の列の合計を計算しています。

実際にコマンドが何を実行しているのか詳しく説明してくれる人はいますか?

最初のコマンド [特定の列の合計を計算する場合]

awk -F '"?\\|"?' '{T+=$(2)*1000} END {printf "%.2f\n",T/1000}' demofile.txt

2番目のコマンド[特定の列の合計を計算する場合]

awk -F '"?\\|"?' '{T+=$(2)} END {printf "%.2f\n",T}' demofile.txt

両方のコマンドを使用して計算された合計が異なります。なぜそうなるのでしょうか?

出力は次のようになります: ここに画像の説明を入力してください これは計算に使用されるファイルです [ダウンロードしてテストしてください] (セキュリティ上の懸念があるため、モデレーターによってリンクが削除されました)

答え1

その違いは、gawkマニュアル状態:

2 進浮動小数点表現と演算は不正確です。 のような単純な値は0.1、2 進浮動小数点数を使用して正確に表現することはできません。また、浮動小数点数の精度が限られているため、演算の順序や中間ストレージの精度がわずかに変わると、結果が変わる可能性があります。さらに悪いことに、任意精度の浮動小数点演算では、計算を開始する前に精度を設定できますが、最終結果の有効な小数点桁数を確実に把握することはできません。

gawkGNU ですawk-M:

-M
--bignum

gawk数値に対して任意精度の演算を選択します。このオプションは、GNU MPFR および MP ライブラリを使用するようにコンパイルされていない場合は効果がありません。

awkと同等かもしれませんし、そうでないかもしれませんgawk。私の Debian 9 では、次の 2 つのコマンドはそれぞれ を生成します25396577843.76

LC_NUMERIC=C gawk -M -v PREC=60 -F '"?\\|"?' '{T+=$(2)*1000} END {printf "%.2f\n",T/1000}' demofile.txt
LC_NUMERIC=C gawk -M -v PREC=60 -F '"?\\|"?' '{T+=$(2)} END {printf "%.2f\n",T}' demofile.txt

それでもprintf "%.4f\n",Tまだ違いがわかります。PRECより良い結果を得るには増やしてください。

根本的な問題はこのサイトで説明されています:
すべてのプログラマが浮動小数点演算について知っておくべきこと

関連情報