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)
但这会删除小数部分,而不是为您提供最接近的整数,并且这不适用于$float
like1.2e9
或.12
example 的值。
还要注意由于浮点数的内部表示可能存在的限制:
$ 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)
(见下文)。
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
(支持浮点运算(小数点分隔符始终是句点))中,您可以使用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)
但是请注意,虽然double
s 可以表示非常大的数字,但整数的限制要大得多。
$ printf '%.0f\n' 1e123
999999999999999977709969731404129670057984297594921577392083322662491290889839886077866558841507631684757522070951350501376
$ echo $((int(1e123)))
-9223372036854775808
Run Code Online (Sandbox Code Playgroud)
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)
小智 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)
一个非常简单的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)