コマンドラインでIEEE 754浮動小数点数を正しく丸める方法は?
出力数字の精度(小数点以下の桁数)を指定したいと思います。
たとえば、6.66
精度に合わせて丸める1
必要があります。6.7
詳細については、下の表を参照してください。
Value Precision Rounded
6.66 0 7
6.66 1 6.7
6.66 2 6.66
6.66 3 6.660
6.666 3 6.666
6.6666 3 6.667
これは対話型シェルで機能する必要がありますが、理想的には本番シェルスクリプトで使用できるほど強力です。
答え1
丸い浮動小数点数
「浮動小数点数の丸め」とはどういう意味ですか?
簡単なようです…私たちの学校の数学の本はどこにありますか…
いいえ、我々は浮動小数点数に関連することは容易ではないことをすでに知っています。
まず、さまざまな丸めモードがあります。
集める?
四捨五入しますか?
ゼロに丸めますか?
最も近い値に丸め - 偶数ですか?
最も近い値に丸め - 0から離れていますか?
極端な状況に対処する方法は?どのようなケースが極端な場合であるかをどうやって知ることができますか?
いいですね。 IEEE 754標準実装を使用し、システムにそれを処理させる方が良いと思います。
標準浮動小数点算術に基づいてシェル内の浮動小数点数を四捨五入するには、次の 3 つのステップが必要です。
- コマンドライン引数の入力テキストを標準浮動小数点数に変換します。
- 浮動小数点数は、一般的なIEEE 754実装を使用して丸められます。
- 出力のために数値を文字列にフォーマットします。
シェルコマンドで判明しましたprintf
すべてを行うことができます。で説明されているように、フォーマットの仕様に従って数値を印刷するために使用できます。man 3 printf
。出力形式で必要な場合、数値は標準的な方法で暗黙的に丸められます。
注文する
入力をコマンドライン引数として使用してx
数値精度に丸めます。p
printf "%.*f\n" "$p" "$x"
または、シェルパイプラインでx
標準入力を入力とp
引数として使用します。
echo "$x" | xargs printf "%.*f\n" "$p"
例:
$ printf '%.*f\n' 0 6.66
7
$ printf '%.*f\n' 1 6.66
6.7
$ printf '%.*f\n' 2 6.66
6.66
$ printf '%.*f\n' 3 6.66
6.660
$ printf '%.*f\n' 3 6.666
6.666
$ printf '%.*f\n' 3 6.6666
6.667
悪い罠
領土に注意してください!.
予想どおり、整数部分と小数部分の間の区切り記号を指定します。
しかし、ドイツ語のロケールでは何が起こるのかを確認してください。たとえば、次のようになります。
$ LC_ALL=de_DE.UTF-8 printf '%.*f\n' 3 6.6666
6,667
はい、そうです。6,667
カンマ6 6 6 7。これは間違いなくスクリプトを台無しにします。
(しかし、ドイツの2人の顧客にのみ適用されます。現在、その顧客のためにデバッグしている開発者コンピュータは例外です。)
より強く
より強力にするには、以下を使用してください。
LC_ALL=C /usr/bin/printf "%.*f\n" "$p" "$x"
または
echo "$x" | LC_ALL=C xargs /usr/bin/printf "%.*f\n" "$p"
また、バリアント実装のマイナーな不一致を解決し、ドイツ語のロケールに設定してもエクスポートできない場合は、非常に汚れた効果を防ぐために組み込み/usr/bin/printf
シェルの代わりにbash
ORを使用します。その後、組み込みを使用して...zsh
printf
LC_ALL
,
/usr/bin/printf
.
%g
指定された有効数字に丸めを参照してください。
答え2
私が見つけたものをきれいに読む最も簡単な方法は次のとおりです。
$ print "%.2f" $(bc <<< "0.10765432*100)
10.77
それでは5
、次に変更してください。4
10.76
読みやすく短いのでメンテナンスが簡単です。
答え3
次は私のために働いた。
#!/bin/bash
function float() {
bc << EOF
num = $1;
base = num / 1;
if (((num - base) * 10) > 1 )
base += 1;
print base;
EOF
echo ""
}
float 3.2