Bashで浮動小数点数を有効数字2桁にフォーマットする方法は?

Bashで浮動小数点数を有効数字2桁にフォーマットする方法は?

bashで2つの有効数字を持つ浮動小数点数を印刷したいです(awk、bc、dc、perlなどの一般的なツールを使用することもできます)。

例:

  • 76543は76000として印刷する必要があります。
  • 0.0076543は0.0076として印刷する必要があります。

どちらの場合も、有効な数字は7と6です。次のような同様の質問に対する回答を読んだ。

シェルで浮動小数点数を丸める方法は?

Bash は浮動小数点変数の精度を制限します。

ただし、答えは有効数字ではなく、小数点以下の桁数(bcコマンドscale=2printfコマンドなど)を制限することに焦点を当てています。%.2f

数値の形式を正確に2桁の有効数字として指定する簡単な方法はありますか?それとも関数を直接書く必要がありますか?

ベストアンサー1

この回答最初の関連質問の最後には、ほぼ破棄された行があります。

%g指定された有効数字に丸めを参照してください。

だから簡単に書けばいいです

printf "%.2g" "$n"

(ただし、小数点区切り文字とロケールについては、以下のセクションを参照し、Bash以外の場合とprintfサポートする必要はありません。)%f%g

例:

$ printf "%.2g\n" 76543 0.0076543
7.7e+04
0.0077

もちろん、純粋な10進数の代わりに歌手指数表現があるので、再変換する必要があります。

$ printf "%0.f\n" 7.7e+06
7700000

$ printf "%0.7f\n" 7.7e-06
0.0000077

これらすべてを集めて関数にまとめます。

# Function round(precision, number)
round() {
    n=$(printf "%.${1}g" "$2")
    if [ "$n" != "${n#*e}" ]
    then
        f="${n##*e-}"
        test "$n" = "$f" && f= || f=$(( ${f#0}+$1-1 ))
        printf "%0.${f}f" "$n"
    else
        printf "%s" "$n"
    fi
}

(注 - この関数は移植可能な(POSIX)シェルで書かれていますが、浮動printf小数点変換を処理していると仮定します。Bashには浮動小数点変換を処理する組み込み関数があるため、printfここでは問題ありません。GNU実装はうまくいきます。 LinuxシステムでもDashを安全に使用できます。

テストケース

radix=$(printf %.1f 0)
for i in $(seq 12 | sed -e 's/.*/dc -e "12k 1.234 10 & 6 -^*p"/e' -e "y/_._/$radix/")
do
    echo $i "->" $(round 2 $i)
done

試験結果

.000012340000 -> 0.000012
.000123400000 -> 0.00012
.001234000000 -> 0.0012
.012340000000 -> 0.012
.123400000000 -> 0.12
1.234 -> 1.2
12.340 -> 12
123.400 -> 120
1234.000 -> 1200
12340.000 -> 12000
123400.000 -> 120000
1234000.000 -> 1200000

小数点区切り記号とロケール設定に関する注意事項

上記のすべてのタスクは次のように仮定します。枢機卿キャラクター(小数点区切り記号とも呼ばれます)は、.ほとんどの英語ロケールと同様です。他のロケールは逆の方法を使用し、一部のシェルには,ロケールを尊重する機能が組み込まれています。printfこれらのシェルでは、デフォルトの文字としてLC_NUMERIC=C強制的に有効にするか、組み込みバージョンを無効にする必要があるかもしれません。後者は(少なくとも一部のバージョンでは)解析引数が常に使用されているように見えますが、印刷は現在のロケールを使用して実行されるという事実によって複雑です。./usr/bin/printf.

おすすめ記事