如何在shell中四舍五入浮点数?


13

如何在命令行上正确舍入IEEE 754浮点数?

我想指定输出数字的精度-小数位数。

例如,舍入6.66到精度1应给出6.7。下表中的更多内容:

Value   Precision  Rounded
6.66    0          7
6.66    1          6.7
6.66    2          6.66
6.66    3          6.660
6.666   3          6.666
6.6666  3          6.667

它应该可以在交互式Shell中使用,但理想情况下要足够健壮,以便在生产Shell脚本中使用它。


我会用awk
同构

Answers:


30

四舍五入浮点数

“舍入浮点数”是什么意思?
显然,这很容易...我上学的数学书在哪里...

不,我们已经知道与浮点数无关的任何事情都不容易:

首先,有多种舍入模式:

向上舍入?
向下舍入?
舍入为零?
四舍五入到最接近的-平整的关系?
四舍五入到最接近的-领带距离零?

如何处理极端情况?如何找出哪些极端情况?

好的,看起来我们最好使用IEEE 754标准的实现,然后让我们的系统来处理。

要基于标准浮点算法在外壳中舍入一个浮点数,我们需要三个步骤:

  • 将输入文本从命令行参数转换为标准浮点数。
  • 使用常规IEEE 754实现对浮点数取整。
  • 将数字格式化为字符串以输出。

事实证明,shell命令printf可以完成所有这一切。它可以根据中所述的格式规范来打印数字man 3 printf。如果输出格式需要数字,则以标准方式隐式舍入数字:

命令

使用输入作为命令行参数xp精度舍入为数字:

printf "%.*f\n" "$p" "$x"

或在Shell管道中,使用x标准输入p作为参数输入:

echo "$x" | xargs printf "%.*f\n" "$p"

例子:

$ printf '%.*f\n' 0 6.66
7
$ printf '%.*f\n' 1 6.66
6.7
$ printf '%.*f\n' 2 6.66
6.66
$ printf '%.*f\n' 3 6.66
6.660
$ printf '%.*f\n' 3 6.666
6.666
$ printf '%.*f\n' 3 6.6666
6.667

陷阱陷阱

当心语言环境!.如您所料,它指定了整数部分和分数部分之间的分隔符- 。
但是看看自己在德国语言环境中会发生什么,例如:

$ LC_ALL=de_DE.UTF-8 printf '%.*f\n' 3 6.6666
6,667

是的,没错6,667-六个逗号六个六七个。那肯定会弄乱您的脚本。
(但仅适用于德国的两个客户。除了目前正在为这些客户进行调试的开发人员的机器。)

更坚固

要使其更强大,请使用:

LC_ALL=C /usr/bin/printf "%.*f\n" "$p" "$x"

要么

echo "$x" | LC_ALL=C xargs /usr/bin/printf "%.*f\n" "$p"

这也可以/usr/bin/printf代替内置的shell bashzsh解决printf变体实现中的细微不一致,并防止在德国语言环境LC_ALL中设置但未导出时产生非常脏的效果。然后,内置的用途,/usr/bin/printf使用. ...


另请参见%g有关四舍五入到指定数量的有效数字的信息。


0

以下对我有用。

#!/bin/bash
function float() {
bc << EOF
num = $1;
base = num / 1;
if (((num - base) * 10) > 1 )
    base += 1;
print base;
EOF
echo ""
}

float 3.2
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.