web-dev-qa-db-ja.com

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

コマンドラインでIEEE 754浮動小数点数を正しく丸めるにはどうすればよいですか?

出力数の精度-小数桁の数を指定したいのですが。

丸め6.66から精度16.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

対話型シェルで使用できる必要がありますが、本番シェルスクリプトで使用するには十分に堅牢であることが理想的です。

11
Volker Siegel

浮動小数点数の丸め

「浮動小数点数の丸め」とはどういう意味ですか?
明らかに簡単です...学校の数学の本はどこにありますか...

いいえ、浮動小数点数に関連するものは何も簡単ではないことがすでにわかっています。

まず、複数の丸めモードがあります。

上向きに丸めますか?
下向きに丸めますか?
ゼロに丸める?
最も近いものに丸める-偶数に関係ありますか?
最も近い値に丸める-ゼロから離れているか?

コーナーケースの扱い方は?コーナーケースはどのようにして見つけるのですか?

はい、IEEE 754標準の実装を使用した方がよいようです。システムで処理してください。

シェルで浮動小数点数を丸めるには、標準の浮動小数点演算に基づいて、3つのステップが必要です。

  • 入力テキストをコマンドライン引数から標準の浮動小数点数に変換します。
  • 通常のIEEE 754実装を使用して浮動小数点数を丸めます。
  • 数値を出力用の文字列としてフォーマットします。

シェルコマンド printf がこれをすべて実行できることがわかります。 man 3 printf で説明されている形式仕様に従って数値を出力するために使用できます。出力形式で必要な場合、数値は標準的な方法で暗黙的に丸められます。

コマンド

コマンドライン引数として入力を使用して、xp桁に丸めます。

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も参照してください。

28
Volker Siegel

以下は私のために働いた。

#!/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
0
xs2rashid