浮動小数点数を整数に変換するには?

浮動小数点数を整数に変換するには?

これはbashで浮動小数点を整数に変換する正しい方法ですか?別の方法がありますか?

flotToint() {
    printf "%.0f\n" "$@"
}

ベストアンサー1

強く打つ

ではbashこれはすでに最高かもしれません。シェル組み込み関数を使用します。変数に結果が必要な場合は、コマンドの置き換えまたはbash特定のコマンドを使用できます(現在もサポートされていますzsh)。

printf -v int %.0f "$float"

次のことができます。

float=1.23
int=${float%.*}

$floatただし、これは最も近い整数を提供する代わりに小数部を削除するか、1.2e9exampleなどの.12値では機能しません。

また、浮動小数点数の内部表現によって発生する可能性がある制限に注意してください。

$ printf '%.0f\n' 1e50
100000000000000007629769841091887003294964970946560

整数を得ることができますが、その整数はどこでも使用できない可能性があります。

また、@BinaryZebraが指摘したように、いくつかのprintf実装(bash、ksh93、yash、zsh、dash、または以前のバージョンのGNUを除くprintf)では、ロケールの影響を受けます(小数点区切りは.,または可能性があります٫)。

したがって、浮動小数点が常にピリオドを小数点区切り文字として使用して表示され、スクリプトを呼び出すユーザーのロケールに関係なく、浮動小数点がそのように処理されるようにするには、printfロケールをCに変更する必要があります。

LC_ALL=C printf '%.0f' "$float"

を使用すると、yash次の操作も実行できます。

printf '%.0f' "$(($float))"

(下記参照)。

POSIX

printf "%.0f\n" 1.1

%fPOSIXはサポートを必要としないため、POSIXではありません。

POSIXlyでは、次のことができます。

f2i() {
  LC_ALL=C awk -- '
    BEGIN {
      for (i = 1; i < ARGC; i++)
        printf "%.0f\n", ARGV[i]
    }' "$@"
}

awk言語構文のリテラル数は常に.小数点文字(,引数を区切るために使用されるため、数値には使用できません)として使用されますが、ARGV一部の実装では、ここで示すように入力から数字を取得するときにロケール設定を尊重します。 GNUの場合、これはawk環境内でのみ適用されます。$POSIXLY_CORRECT

扱いにくい

(浮動小数点算術サポート(小数点区切り記号は常にピリオドです))では、最も近い整数を浮動小数点として提供し(のように)、浮動小数点で整数を提供する数学関数をzsh使用できます(middleのように)。だからあなたはこれを行うことができます:rint()Cint()awk

$ zmodload zsh/mathfunc
$ i=$(( int(rint(1.234e2)) ))
$ echo $i
123

または:

$ integer i=$(( rint(5.678e2) ))
$ echo $i
568

しかし、doublesは非常に大きな数を表すことができますが、整数ははるかに制限的です。

$ printf '%.0f\n' 1e123
999999999999999977709969731404129670057984297594921577392083322662491290889839886077866558841507631684757522070951350501376
$ echo $((int(1e123)))
-9223372036854775808

クッシュ 93

ksh93は、浮動小数点演算をサポートする最初のBourne様シェルです。 ksh93は、コマンドが組み込まれている場合にパイプやフォークを使用しないことでコマンドの置き換えを最適化します。だから

i=$(printf '%.0f' "$f")

分割終了はありません。または、より良い方法は次のとおりです。

i=${ printf '%.0f' "$f"; }

偽のサブシェル環境を作成するのに苦労したり、フォークしたりすることはありません。

次のようにすることもできます。

i=$(( rint(f) ))

しかし注意してください:

$ echo "$(( rint(1e18) ))"
1000000000000000000
$ echo "$(( rint(1e19) ))"
1e+19

次のようにすることもできます。

integer i=$(( rint(f) ))

しかし、次のようになりますzsh

$ integer i=1e18
$ echo "$i"
1000000000000000000
$ integer i=1e19
$ echo "$i"
-9223372036854775808

浮動小数点演算は、ksh93ロケールの小数点区切り記号の設定に従います(,数学演算子($((1,2))フランス語/ドイツ語...ロケールの場合は6/5、$((1, 2))英語のロケールの2と同じ))。

ヤッシュ

yashは浮動小数点演算もサポートしますが、ksh93/ zshetcの数学関数はサポートしませんrint()。以下を使用して数値を整数に変換できます。バイナリまたは例:演算子(これも機能しますzshが、適用されませんksh93)。しかし、小数部は切り捨てられますが、最も近い整数は提供しません。

$ echo "$(( 0.237e2 | 0 ))"
23
$ echo "$(( 1e19 | 0 ))"
-9223372036854775808

yash出力ではロケールの小数点区切りを考慮しますが、算術式の浮動小数点リテラル定数は考慮しません。これは予期しない結果を引き起こす可能性があります。

$ LC_ALL=fr_FR.UTF-8 ./yash -c 'a=$((1e-2)); echo $(($a + 1))'
./yash: arithmetic: `,' is not a valid number or operator

ピリオドを使用するスクリプトでは、他のロケールで操作が中断されることを心配することなく浮動小数点定数を使用できますが、次のように覚えている限り、ユーザーが表示した数字を処理し続けることができるため、いくつかの点で良いです。

var=$((10.3)) # and not var=10.3
... "$((a + 0.1))" # and not "$(($a + 0.1))".

printf '%.0f\n' "$((10.3))" # and not printf '%.0f\n' 10.3

おすすめ記事