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

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

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

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

答案1

巴什

在 中bash,这可能已经是最好的了。它使用 shell 内置函数。如果您需要变量中的结果,则可以使用命令替换或bash特定命令(尽管现在 也支持zsh):

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

你可以这样做:

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

$float但这会删除小数部分,而不是给您最接近的整数,并且这对于like1.2e9.12example的值不起作用。

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

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

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

此外,正如 @BinaryZebra 所指出的,在几种printf实现中(bash、ksh93、yash,而不是 zsh、dash 或旧版本的 GNU printf),它受到区域设置(小数点分隔符可能是.,,٫)的影响。

因此,如果您的浮点数始终使用句点作为小数分隔符来表示,并且您希望无论调用脚本的用户的区域设置如何,都将其视为这样printf,则需要将区域设置修复为 C:

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

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

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

(见下文)。

POSIX

printf "%.0f\n" 1.1

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

POSIXly,你可以这样做:

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

请注意,虽然awk语言语法中的文字数字始终使用.as 十进制基数字符(,用于分隔参数,因此不能在数字中使用),但在像此处这样从输入中获取数字时ARGV,某些实现会遵循区域设置的十进制基数特点。对于 GNU 来说,只有在环境中awk时才是这样。$POSIXLY_CORRECT

桀骜

zsh(支持浮点算术(小数分隔符始终是句点))中,您可以使用rint()数学函数为您提供最接近的整数作为浮点(如在 中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

克什93

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

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

不分叉。或者甚至更好:

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

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

您还可以这样做:

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()。您可以使用以下方法将数字转换为整数二进制或例如运算符(也适用于zsh但不适用于ksh93)。但请注意,它会截断小数部分,但不会给出最接近的整数:

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

答案2

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

答案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

答案4

有关的:

  1. awk中如何将浮点数转换为整数,
  2. shell中如何对浮点数进行四舍五入?

互补@斯特凡·查泽拉斯 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] )}' "$@";
}

相关内容