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

Rah*_*til 62 bash numeric-data floating-point

这是在 bash 中进行浮点到整数转换的正确方法吗?有没有其他方法?

flotToint() {
    printf "%.0f\n" "$@"
}
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 89

猛击

在 中bash,这可能是最好的。那使用内置的shell。如果您需要变量中的结果,您可以使用命令替换或bash特定的(虽然现在也支持zsh):

printf -v int %.0f "$float"
Run Code Online (Sandbox Code Playgroud)

你可以这样做:

float=1.23
int=${float%.*}
Run Code Online (Sandbox Code Playgroud)

但这会删除小数部分,而不是为您提供最接近的整数,并且这不适用于$floatlike1.2e9.12example 的值。

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

$ printf '%.0f\n' 1e50
100000000000000007629769841091887003294964970946560
Run Code Online (Sandbox Code Playgroud)

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

此外,正如@BinaryZebra 所指出的,在几个printf实现(bash、ksh93、yash,而不是 GNU、zsh、dash)中,它受语言环境(小数点分隔符可以是.,)的影响。

因此,如果您的浮点数始终用句点表示为小数点分隔符,并且您希望它被视为这样,printf而不管调用脚本的用户的语言环境如何,则需要将语言环境固定为 C:

LC_ALL=C printf '%.0f' "$float"
Run Code Online (Sandbox Code Playgroud)

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

printf '%.0f' "$(($float))"
Run Code Online (Sandbox Code Playgroud)

(见下文)。

POSIX

printf "%.0f\n" 1.1
Run Code Online (Sandbox Code Playgroud)

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

POSIXly,你可以这样做:

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

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

zsh

zsh(支持浮点运算(小数点分隔符始终是句点))中,您可以使用rint()数学函数为您提供最接近的整数作为浮点数(如 in C)并int()为您提供浮点数中的整数(如 in awk)。所以你可以这样做:

$ zmodload zsh/mathfunc
$ i=$((int(rint(1.234e2))))
$ echo $i
123
Run Code Online (Sandbox Code Playgroud)

或者:

$ integer i=$((rint(5.678e2)))
$ echo $i
568
Run Code Online (Sandbox Code Playgroud)

但是请注意,虽然doubles 可以表示非常大的数字,但整数的限制要大得多。

$ printf '%.0f\n' 1e123
999999999999999977709969731404129670057984297594921577392083322662491290889839886077866558841507631684757522070951350501376
$ echo $((int(1e123)))
-9223372036854775808
Run Code Online (Sandbox Code Playgroud)

ksh93

ksh93 是第一个支持浮点运算的类似 Bourne 的 shell。当命令只是内置命令时,ksh93 通过不使用管道或分叉来优化命令替换。所以

i=$(printf '%.0f' "$f")
Run Code Online (Sandbox Code Playgroud)

不分叉。或者甚至更好:

i=${ printf '%.0f' "$f"; }
Run Code Online (Sandbox Code Playgroud)

它既不会分叉,也不会费心去创建一个假的子 shell 环境。

你也可以这样做:

i=$((rint(f)))
Run Code Online (Sandbox Code Playgroud)

但要注意:

$ echo "$((rint(1e18)))"
1000000000000000000
$ echo "$((rint(1e19)))"
1e+19
Run Code Online (Sandbox Code Playgroud)

你也可以这样做:

integer i=$((rint(f)))
Run Code Online (Sandbox Code Playgroud)

但喜欢zsh

$ integer i=1e18
$ echo "$i"
1000000000000000000
$ integer i=1e19
$ echo "$i"
-9223372036854775808
Run Code Online (Sandbox Code Playgroud)

请注意,ksh93浮点算术遵循语言环境中的小数点分隔符设置(即使,是其他数学运算符($((1,2))在法语/德语...语言环境中为 6/5,$((1, 2))在英语语言环境中为 2) .

亚什

yash 也支持浮点运算,但没有像ksh93/zsh的数学函数rint()。例如,您可以使用二进制或运算符将数字转换为整数(也适用于zsh但不适用于 in ksh93)。但是请注意,它会截断小数部分,它不会为您提供最接近的整数:

$ echo "$((0.237e2 | 0))"
23
$ echo "$((1e19 | 0))"
-9223372036854775808
Run Code Online (Sandbox Code Playgroud)

yash 在输出中使用语言环境的小数点分隔符,但不适用于其算术表达式中的浮点文字常量,这可能会导致意外:

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

这在某种程度上很好,因为您可以在使用句点的脚本中使用浮点常量,而不必担心它会在其他语言环境中停止工作,但仍然能够处理用户表示的数字,只要正如你记得做的那样:

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
Run Code Online (Sandbox Code Playgroud)


小智 27

bc - 任意精度的计算器语言

int(float) 应该是这样的:

$ echo "$float/1" | bc 
1234
Run Code Online (Sandbox Code Playgroud)

为了更好地使用这个:

$ echo "($float+0.5)/1" | bc 
Run Code Online (Sandbox Code Playgroud)

例子:

$ float=1.49
$ echo "($float+0.5)/1" | bc 
1
$ float=1.50
$ echo "($float+0.5)/1" | bc 
2
Run Code Online (Sandbox Code Playgroud)

  • 但是`float=-2; echo "($float+0.5)/1" | bc` 给出 `-1`。 (5认同)
  • 这被称为朝向+inf 的舍入。这是[四种可能的舍入方式](https://www.gnu.org/software/libc/manual/html_node/Rounding.html)之一。 (3认同)

小智 7

之前提交的答案几乎是正确的:“你可以这样做:

float=1.23
int=${float%.*}
Run Code Online (Sandbox Code Playgroud)

但这会删除小数部分而不是给你最接近的整数,并且这不适用于 $float 的值,例如 1.2e9 或 .12 ......”

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

echo ${float%%.*}
1
Run Code Online (Sandbox Code Playgroud)


GMa*_*ter 7

一个非常简单的hacky是

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

样本输出

$ float_to_int 32.333
32
$ float_to_int 32
32
Run Code Online (Sandbox Code Playgroud)