浮動小数点値を合計するより良い方法は何ですか - Unix で 8 から 9 のスケールまでの値を合計すると、合計が不正確になります

浮動小数点値を合計するより良い方法は何ですか - Unix で 8 から 9 のスケールまでの値を合計すると、合計が不正確になります

シナリオがある

UNIX の合計が 8 から 9 のスケールまでで間違った合計が表示されるため、問題が発生しています。これを修正するにはどうすればよいでしょうか。

使用したコマンド

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

これは前回投稿された質問へのリンクです これら 2 つの sum コマンドに違いがあるのはなぜですか?

正確な合計を得るために、これに対処するより良い方法はありますか

awk、bc、dcを使用して

デモデータ

1|"12.8"|demo1
2|"13.5678341234567"|demo1
3|"14.578"|demo1
4|"15.58"|demo1
5|"16.56784"|demo1
6|"17.578"|demo1
7|"18.678"|demo1
8|"19.568890123"|demo1
9|"20.588792"|demo1

答え1

ファイル サイズ (つまり、追加する行数) は示されていません。ダウンロードは 18.3 MB で、サイトが「危険」および「詐欺警告」と表示される前に表示されました。行の平均長が 18 であれば、100 万個の浮動小数点数が追加されることになり、値の範囲はわかりません。質問に示されている合計は 13.2 桁なので、1 行あたりの平均値は約 7 桁で、変動性は不明です。

27.865326635297 のような値を、13 桁の整数に近づいている実行中の合計に追加し続けると、.00532... が 15 桁または 16 桁の結果範囲外にあるため、27.87 (四捨五入) の部分のみが合計に含まれます。これらの誤差は相殺される場合もあれば、相殺されない場合もあります。これがモンテ カルロ演算です。

awk --version の出力を確認してください。MPFR と MP が記述されている場合、awk は拡張精度演算でコンパイルされています。awk コマンドに -M 113 を追加するだけです。これは、4 倍精度の実数演算 (33 桁の精度) を実現する仮数部の長さです。

www.gnu.org/software/gawk/manual/gawk.html#任意精度演算

答え2

これは、直流コマンド (十分な精度がコンパイルされていると仮定)。2 番目の列を dc コマンドで装飾し、60 桁 (200 ビット) の精度で動作します。

これは、前に提供された 10 行のデータと、いくつかの極端な値に対して実行されます。中間の合計が表示されます。これらを削除するには、awk が $2 を出力する \n の直前の 'p' を削除します。

Paul--) cat awkToDc
#! /bin/bash

function Data { cat <<'EOF'
1|"12.8"|demo1
2|"13.5678341234567"|demo1
3|"14.578"|demo1
4|"15.58"|demo1
5|"16.56784"|demo1
6|"17.578"|demo1
7|"18.678"|demo1
8|"19.568890123"|demo1
9|"20.588792"|demo1
10|"55555555555555555555000000000000"|demo1
11|"20.588792"|demo1
12|"0.000000000000000000077777777777"|demo1
EOF
}

function dataDC {

    AWK='
BEGIN { FS = "\042"; printf ("60 k 0\n"); }
{ printf ("%s + p\n", $2); }
END { printf ("p q\n"); }
'
    awk "${AWK}"
}

発行された dc コマンドの説明 (逆ポーランド記法)

'60 k' は算術精度を設定し、'0' は合計を初期化します。
' +' は $2 の値を合計に追加します。'p' は説明のために実行中の合計を出力します。'p
q' は最終合計を出力して終了します。

    Data | dataDC | dc

Paul--) ./awkToDc
12.8
26.3678341234567
40.9458341234567
56.5258341234567
73.0936741234567
90.6716741234567
109.3496741234567
128.9185642464567
149.5073562464567
55555555555555555555000000000149.5073562464567
55555555555555555555000000000170.0961482464567
55555555555555555555000000000170.096148246456700000077777777777
55555555555555555555000000000170.096148246456700000077777777777
Paul--) 

これで、4 つのテスト済み手法 (722277 行のテスト ファイルに対して) と精度評価ができました。

精度 200 ビットの gawk と精度 60 桁の dc を使用すると、両方とも同じ 33 桁の合計値に一致し、これは正確であると思われます。

25396577843.7560139069641121618832

gawk を標準 IEEE 精度 (15 桁または 16 桁) で使用すると、最初の 12 桁のみが一致します。指数がばらばらになるにつれて、100 万回の加算で精度が低下すると想定します。

25396577843.7769622802734375

標準 awk にも再帰加算アルゴリズムがあることを発見しました。これは最初に NR の最後の 5 桁に従って値を加算し、100,000 個の小計を作成します。次に、それらを合計し、桁数を 4、3、2、1 に減らし、最後に 1 つの合計にします。したがって、各数値には 60 回だけ加算されます。この結果は、高精度のものの最初の 16 桁と一致しており、期待どおりの良好な結果です。

25396577843.756011962890625

答え3

チェックアウトカハン総括、丸め誤差を追跡して補正しようとします。このような巨額の金額には必須です。

答え4

およびcvstoolbc:

$ csvtool -t '|' col 2 A | paste -sd + - | bc
149.5073562464567

関連情報