对浮点数进行四舍五入

对浮点数进行四舍五入

如何在命令行上正确舍入 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 脚本中使用它。

答案1

对浮点数进行四舍五入

“对浮点数进行四舍五入”是什么意思?
显然,这很简单......我学校的数学书在哪里......

不,我们已经知道与浮点数相关的事情并不容易:

首先,有多种舍入模式:

向上舍入?
向下舍入?
四舍五入到零?
四舍五入到最接近的值 - 是否为偶数?
四舍五入到最接近的值 - 远离零?

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

好的,看来我们最好使用 IEEE 754 标准的实现,并让我们的系统来处理这个问题。

要在 shell 中对浮点数进行舍入,基于标准浮点运算,我们需要三个步骤:

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

原来是shell命令printf可以做到这一切。它可用于根据格式规范打印数字,如中所述man 3 printf。如果输出格式需要,数字将以标准方式隐式舍入:

命令

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

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 内置的bashorzsh来解决printf变体实现中的微小不一致,并防止在德语语言环境中LC_ALL设置但未导出时出现非常脏的效果。然后,内置使用,,并/usr/bin/printf使用....


另请参阅%g舍入到指定有效数字位数。

答案2

我发现的最简单的干净阅读方式是:

$ print "%.2f" $(bc <<< "0.10765432*100)
10.77

现在,5改为4

10.76

它易于阅读且简短,易于维护。

答案3

以下对我有用。

#!/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

相关内容