如何将浮点数转换为整数?


Answers:


69

重击

在中bash,这可能和它一样好。那使用内置的外壳。如果您需要变量中的结果,则可以使用命令替换或bash特定的命令替换(尽管现在也支持zsh):

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

您可以这样做:

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

但这将删除小数部分,而不是为您提供最接近的整数,并且对于$floatlike 1.2e9.12例如的值不起作用。

还要注意由于浮点数的内部表示而可能存在的限制:

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

您确实得到了一个整数,但是很可能您将无法在任何地方使用该整数。

而且,正如@BinaryZebra指出的那样,在几种printf实现中(bash,ksh93,yash,而不是GNU,zsh,破折号),它受语言环境(可以是.或的十进制分隔符,)的影响。

因此,如果浮点数始终以句点作为小数点分隔符来表示,并且printf无论用户调用脚本的语言环境如何,都希望将其视为此类,则需要将语言环境固定为C:

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

使用yash,您还可以执行以下操作:

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

(见下文)。

POSIX

printf "%.0f\n" 1.1

不是POSIX,因为POSIX %f不需要支持。

POSIXly,您可以执行以下操作:

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

该位置不受语言环境的影响(逗号不能是小数点分隔符,awk因为它已经是该语法中的特殊字符(print 1,2,与print 1, 2将两个参数传递给一样print

sh

zsh(支持浮点运算(小数分隔符始终为句点))中,您具有rint()math函数,可以为您提供最接近的整数作为浮点数(如中的C),并int()为您提供浮点数中的整数(如中的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"; }

这既不会派生,也不会解决创建伪造的subshel​​l环境的所有麻烦。

您也可以这样做:

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 一样)) 。

ash

yash还支持浮点运算,但没有像ksh93/ zsh的数学函数rint()。您可以使用二进制或运算符将数字转换为整数(也可以在中使用,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

int=${float%.*}在Mac(版本10.13.4(17E199))上的bash(版本3.2.57(1)-发行版)脚本中工作得很好。
TelamonAegisthus

你先配方GNU的bash 4.4.19,如失败:```$回声$ 32.800最大的printf $ -v INT到%.0f “$最大”的bash:printf的:32.800:无效的数字```
路易斯·德索萨

@LuísdeSousa,您的语言环境可能具有,小数点基数。请参阅有关的部分LC_ALL=C
斯特凡Chazelas

请注意,此答案回答了一个不同的问题:如何删除点后的数字而不是询问什么float转换为integer 正确方法是什么
以撒

这种方法应该应用于任意数量的浮点数吗?浮点数为23位或128位尾数应该相同吗?
以撒

21

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

4
但是float=-2; echo "($float+0.5)/1" | bc-1
斯特凡Chazelas

2
这称为朝+ inf的回合。那是四舍五入四种可能方法之一。

5

之前提交的答案几乎是正确的:“您可以:

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

但这将删除小数部分,而不是为您提供最接近的整数,并且不适用于$ float的值,例如1.2e9或.12。...”

只需使用${float%%.*}

echo ${float%%.*}
1

3

一个非常简单的hacky是

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

可以使用sed,但是cut解决方案更简单。我喜欢sedcut因为他们恕我直言,在比嵌入式目标更多的可用awk(这仍然是相当普遍通过busyboxbc)。
佩维克

0

有关:

  1. 如何在awk中将float转换为整数
  2. 如何在shell中四舍五入浮点数?

补充@StéphaneChazelas awk答案:

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] )}' "$@";
}

在我的awk中,后一个取整为零,而不是减为无穷大(因为“地板”可以表示)。此外,第一轮减半为偶数。我不确定这与Bash的功能printf是否有所不同,或者是否有其他原因更喜欢awk而不是内置的printf
ilkkachu
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.