コマンドラインで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
対話型シェルで使用できる必要がありますが、本番シェルスクリプトで使用するには十分に堅牢であることが理想的です。
「浮動小数点数の丸め」とはどういう意味ですか?
明らかに簡単です...学校の数学の本はどこにありますか...
いいえ、浮動小数点数に関連するものは何も簡単ではないことがすでにわかっています。
まず、複数の丸めモードがあります。
上向きに丸めますか?
下向きに丸めますか?
ゼロに丸める?
最も近いものに丸める-偶数に関係ありますか?
最も近い値に丸める-ゼロから離れているか?
コーナーケースの扱い方は?コーナーケースはどのようにして見つけるのですか?
はい、IEEE 754標準の実装を使用した方がよいようです。システムで処理してください。
シェルで浮動小数点数を丸めるには、標準の浮動小数点演算に基づいて、3つのステップが必要です。
シェルコマンド 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"
これは、bash
またはzsh
の組み込みシェルの代わりに/usr/bin/printf
を使用して、printf
バリアントの実装における軽微な不整合を回避し、非常にダーティな影響を防ぎますドイツ語ロケールでLC_ALL
が設定されているがエクスポートされていない場合。次に、組み込み関数は,
を使用し、/usr/bin/printf
は.
...を使用します。
指定された有効桁数への丸めについては、%g
も参照してください。
以下は私のために働いた。
#!/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