Unixの長い列に1行に1つの値を掛け、0.01秒間隔で増加する大きなファイルがあります。 1日分のデータの場合、これは864万行に相当します。
135699840000
135699840001
135699840002
135699840003
135699840004
このファイルの各行から各行のシリアル日付番号(参照年01/01/0000のmatlabの日付カウンタ)を計算するコマンドを実行したいと思います。
735235.0000000000
735235.0000001157
735235.0000002314
735235.0000003472
735235.0000004629
私はコーディングが初めてですが、whileループを使用して動作するようにしました。しかし、これは非常に非効率的で、実行には数時間かかります。
while read epochtimerange; do
echo "scale=10; (($epochtimerange/(100*86400))+719529)" |bc
done < epochtimerangetmp.txt > serialdaterangetmp.txt
私はawkを使って実行する方法があるはずですが、うまくいきません。重要なことは、出力で小数点以下10桁の精度を維持できることです。
誰でも私を助けることができますか?ありがとうございます。
ベストアンサー1
私たち全員が知っているように、シェルは非常に遅いです。
あなたが要求することは次のようにシェルで達成することができます:
#!/bin/bash
while read line; do
bc <<<"scale=10;($line/(100*86400))+719529"
done <datafile
1000行を処理するのに約1.1秒かかります。
864万枚の写真はすべて約2時間41分かかります。
また、bc の数値結果は正しく丸められません。
例の5行は次の値を生成します。
735235.0000000000
735235.0000001157
735235.0000002314
735235.0000003472
735235.0000004629
より多くの数字を表示するには、精度を20に変更してみましょう。
735235.00000000000000000000
735235.00000011574074074074
735235.00000023148148148148
735235.00000034722222222222
735235.00000046296296296296
たとえば、で終わる3番目の数字2314
は誤って丸められ、次の数字はに丸められなければならないこと4
が示されます。8
5
AWK
awkを使用すると、より高速なソリューションを得ることができます。 awkが要求したものを実装すると、次のようになります。
$ awk '{printf ("%.10f\n",($0/(100*86400))+719529)}' datafile
735235.0000000000
735235.0000001157
735235.0000002314
735235.0000003473
735235.0000004630
1000行を処理するには0.006(6ミリ秒)しかかかりません。 864万行すべてを約50秒で処理する必要があります。
しかし、awkは精度範囲を超えました。デフォルトでは、64ビット浮動小数点値を使用して表されます。これは精度は小数点以下15桁程度です。。データ結果の整数部分は6桁で、分数部分は8桁目まで正確に推定できます。
実際にビット数を拡張しようとすると、次のようになります。
awk '{printf ("%.20f\n",($0/(100*86400))+719529)}' datafile
私たちが得るのは騒音だけです。
735235.00000000000000000000
735235.00000011571682989597
735235.00000023143365979195
735235.00000034726690500975
735235.00000046298373490572
より正確なbc結果と比較:
735235.00000000000000000000
735235.00000000000000000000
735235.00000011571682989597
735235.00000011574074074074
735235.00000023143365979195
735235.00000023148148148148
735235.00000034726690500975
735235.00000034722222222222
735235.00000046298373490572
735235.00000046296296296296
この問題を実際に解決するには、より正確なawkが必要です。
多精度AWK
GNU awk(ここではgawkと呼びます)を使用してMPFR(Multiple Precision Floating Point Library)でコンパイルすると、はるかに高い精度が得られます。
あなたのawkにこのライブラリがあることを確認してください(バージョンにお問い合わせください):
$ awk --version
GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.5, GNU MP 6.1.1)
Copyright (C) 1989, 1991-2015 Free Software Foundation.
そして、使用可能な精度を使用するようにawkコマンドを変更します。
gawk -M -v PREC=100 '{printf ("%.20f\n",($0/(100*86400))+719529)}' datafile
735235.00000000000000000000
735235.00000011574074074074
735235.00000023148148148148
735235.00000034722222222222
735235.00000046296296296296
結果は高精度bcと同じです。
この場合、awkの速度とbcの精度が得られます。
10進数10桁で要求された最終コマンドは次のとおりです。
gawk -M -v PREC=100 '{printf ("%.10f\n",($0/(100*86400))+719529)}' datafile
735235.0000000000
735235.0000001157
735235.0000002315
735235.0000003472
735235.0000004630
すべての値は正しく丸められます。