これはbashで浮動小数点から整数への変換を行う正しい方法ですか?他の方法はありますか?
flotToint() {
printf "%.0f\n" "$@"
}
bash
では、おそらくそれで十分です。組み込みのシェルを使用します。変数の結果が必要な場合は、コマンド置換またはbash
固有のものを使用できます(現在はzsh
でもサポートされています)。
printf -v int %.0f "$float"
あなたがすることができます:
float=1.23
int=${float%.*}
しかし、これは最も近い整数を与える代わりに小数部分を削除し、たとえば$float
や1.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))"
(下記参照)。
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,2
、print
に2つの引数を渡すprint 1, 2
と同じ) )
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
ただし、double
sは非常に大きな数を表すことができますが、整数はさらに制限されます。
$ printf '%.0f\n' 1e123
999999999999999977709969731404129670057984297594921577392083322662491290889839886077866558841507631684757522070951350501376
$ echo $((int(1e123)))
-9223372036854775808
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
/zsh
のrint()
などの数学関数はありません。たとえば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
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
提出された前回の回答はほぼ正しいものでした。「できること:
float=1.23
int=${float%.*}
しかし、これは最も近い整数を与える代わりに小数部分を削除し、1.2e9や.12などの$ floatの値に対しては機能しません... "
${float%%.*}
。
echo ${float%%.*}
1
次のコマンドでビーププログラムをインストールします。
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
非常にシンプルなハックは
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
関連:
補足 @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] )}' "$@";
}