web-dev-qa-db-ja.com

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

これはbashで浮動小数点から整数への変換を行う正しい方法ですか?他の方法はありますか?

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

bash

bashでは、おそらくそれで十分です。組み込みのシェルを使用します。変数の結果が必要な場合は、コマンド置換またはbash固有のものを使用できます(現在はzshでもサポートされています)。

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

あなたがすることができます:

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

しかし、これは最も近い整数を与える代わりに小数部分を削除し、たとえば$float1.2e9などの.12の値に対しては機能しません。

また、浮動小数点数の内部表現に起因する可能性のある制限にも注意してください。

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

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

また、@ BinaryZebraによって指摘されているように、いくつかのprintf実装(bash、ksh93、yash、GNUではなく、zsh、dash)では、ロケール(小数点記号として.または,)の影響を受けます。

したがって、浮動小数点が常にピリオドを小数点として使用して表現されており、スクリプトを呼び出しているユーザーのロケールに関係なくprintfによってそのように処理されるようにしたい場合は、ロケールを修正する必要があります。 C:

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

yashを使用すると、次のこともできます。

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

(下記参照)。

POSIX

printf "%.0f\n" 1.1

%fはPOSIXでサポートされる必要がないため、POSIXではありません。

POSIXly、あなたがすることができます:

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

その1つはロケールの影響を受けません(コンマはawkで小数点記号にすることはできません。これは、そこの構文ではすでに特殊文字であるためです(print 1,2printに2つの引数を渡すprint 1, 2と同じ) )

zsh

zsh(浮動小数点演算をサポートします(小数点は常にピリオドです))では、rint()数学関数を使用して、最も近い整数を浮動小数点数として取得できます(C)およびint()を使用すると、floatから整数を取得できます(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

ksh93

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

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

フォークしません。またはさらに良い:

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

どちらもforkしませんが、偽のサブシェル環境を作成するという面倒なこともすべて行いません。

あなたも行うことができます:

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/zshrint()などの数学関数はありません。たとえばbinary or演算子を使用して、数値を整数に変換できます(zshでも機能しますが、ksh93では機能しません)。ただし、小数部は切り捨てられ、最も近い整数は得られないことに注意してください。

$ echo "$((0.237e2 | 0))"
23
$ echo "$((1e19))"
-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
74

bc-任意精度の計算機言語

int(float)は次のようになります。

$ echo "$float/1" | bc 
1234

よりよく丸めるには、これを使用します。

$ echo "($float+0.5)/1" | bc 

例:

$ float=1.49
$ echo "($float+0.5)/1" | bc 
1
$ float=1.50
$ echo "($float+0.5)/1" | bc 
2
23
innocent-world

提出された前回の回答はほぼ正しいものでした。「できること:

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

しかし、これは最も近い整数を与える代わりに小数部分を削除し、1.2e9や.12などの$ floatの値に対しては機能しません... "

${float%%.*}

echo ${float%%.*}
1
6
Jay Mayers

次のコマンドでビーププログラムをインストールします。

aptitude install beep
or
apt-get install beep

そして、このような正弦関数を聞いてください:

1a。 bashで関数を定義します。

$ function sinus () 
{ 
    a=$1;
    b=$2;
    n=$3;
    f=$4;
    d=$(echo "scale=$f; ($b-$a)/$n"|bc);
    for m in $(seq 0 $n);
    do
        x=$(echo "scale=$f;$a+$m*$d"|bc);
        y=$(echo "scale=$f;s($x)"|bc -l);
        #printf "%0.${f}f\t" "$x";
        #printf "%0.${f}f\n" "$y";
        z=$(echo "scale=$f; 2300+2000*$y" | bc);
        beep -f "$z" -l 2 -d 0;
    done | column -t
}

2a。この関数を次のように呼び出します。

$ sinus 1 20 300 4

: 'sinus abnf'は、aからb間隔をn + 1で分割するf小数。プロットやその他のものに使用できるため、関数には必要以上のものがあります。初期化の代わりにread a b n fと書くこともできます。

また、非常に面白いことに、プログラムが耐えられなくなるまで、正弦関数のサイクルをどんどん壊していきます。

1b。定義:

$ function sinus-inv () 
{ 
    a=$1; b=$2; n=$3; f=$4;
    d=$(echo "scale=$f; ($b-$a)/$n"|bc);
    for m in $(seq 1 $n);
    do
        x=$(echo "scale=$f;$a+$m*$d"|bc);
        y=$(echo "scale=$f;s(8000/($b-$x))"|bc -l);
        z=$(echo "scale=$f; 2300+2000*$y" | bc);
        beep -f "$z" -l 1 -d 0;
    done;
}

2b。呼び出し例:

$ sinus-inv 1 100 1000 8
4
Robert

非常にシンプルなハックは

function float_to_int() { 
  echo $1 | cut -d. -f1    # or use -d, if decimals separator is ,
}

出力例

$ float_to_int 32.333
32
$ float_to_int 32
32
4
GMaster

関連:

  1. awkで浮動小数点を整数に変換する方法
  2. シェルで浮動小数点数を丸める方法は?

補足 @StéphaneChazelasawk回答:

float_to_integer_rounding_nearst() {
    awk 'BEGIN{for (i=1; i<ARGC;i++) printf "%.0f", ARGV[i]}' "$@";
}

float_to_integer_rounding_floor() {
    awk 'BEGIN{for (i=1; i<ARGC;i++) printf "%d", int( ARGV[i] )}' "$@";
}
0
user