bc 算术错误

Posted

技术标签:

【中文标题】bc 算术错误【英文标题】:bc arithmetic Error 【发布时间】:2015-02-05 02:03:24 【问题描述】:

我正在尝试解决这个 bash 脚本,该脚本从用户读取算术表达式并将其回显到输出屏幕,最后四舍五入到小数点后 3 位。

样本输入

5+50*3/20 + (19*2)/7

样本输出

17.929

我的代码是

read x
echo "scale = 3; $x" | bc -l

当有输入时

5+50*3/20 + (19*2)/7

**我的输出是**

17.928

机器希望它是什么

17.929

因此我得到了错误的解决方案。有什么想法吗?

【问题讨论】:

你的问题很模糊。你怎么称呼“样本输出”?你叫什么“我的输出”?你怎么称呼“机器想要它”?实际上,您希望脚本生成什么输出:截断或舍入? 样本输入是机器生成的用于检查我的脚本是否正确的输入,它期望输出是样本输出的输出。我的输出是我的脚本生成的输出,我需要的是我的输出类似于示例输出@YvesDaoust 也许我不确定说你没有让解释变得不那么晦涩是错误的。截断还是舍入? 【参考方案1】:

我完全同意 jherran 的观点,即您没有将数字四舍五入,而是将其截断。我会继续说,规模可能根本没有按照你想要的方式运行,可能是没有人希望它运行的方式。

> x="5+50*3/20 + (19*2)/7"
> echo "$x" | bc -l
17.92857142857142857142
> echo "scale = 3; $x" | bc -l
17.928

此外,because of the behaviour of scale,您将每个乘法/除法与加法分开舍入。让我用一些例子来证明我的观点:

> echo "scale=0; 5/2" | bc -l
2
> echo "scale=0; 5/2 + 7/2" | bc -l
5
> echo "5/2 + 7/2" | bc -l
6.00000000000000000000

但是,没有任何操作的缩放也不起作用。有一个丑陋的解决方法:

> echo "scale=0; 5.5" | bc -l
5.5
> echo "scale=0; 5.5/1" | bc -l
5

由此产生了两件事。

如果您想使用 bc 的比例,请仅针对已计算的最终结果执行此操作,即便如此,也要小心。

请记住,舍入与截断数字 + 所需精度的一半相同。

让我们以四舍五入到最接近的整数为例,如果您将 0.5 添加到应该四舍五入的数字上,其整数部分将采用下一个整数值,截断将给出所需的结果。如果该数字应该向下舍入,则添加 0.5 不会改变其整数值,并且截断将产生与​​不添加任何内容时相同的结果。

因此我的解决方案如下:

> y=$(echo "$x" | bc -l)
> echo "scale=3; ($y+0.0005)/1" | bc -l # scale doesn't apply to the +, so we get the expected result
17.929

再次,请注意以下内容不起作用(如上所述),因此确实需要将其分解为两个操作:

> echo "scale=3; ($x+0.0005)/1" | bc -l
17.928

【讨论】:

实际上它起作用了,我在下面标记了一个答案,它起作用了。无论如何,我非常感谢您花时间和解释,我理解了基本概念,谢谢@Climbali【参考方案2】:

这里的关键是确保使用具有“%.3f”格式规范的 printf,只要 bc 为“scale=4”,printf 就会按照您的意愿进行舍入。

这是一个有效的脚本:

echo -e "please enter math to calculate: \c"
read x
printf "%.3f\n" $(echo "scale=4;$x" | bc -l)

您可以了解上述解决方案的情况,如果您在命令行中运行此命令:echo "scale=4;5+50*3/20 + (19*2)/7" | bc,结果将是 17.9285。当将该结果作为参数提供给 printf 时,该函数会考虑小数点后第四位并将值四舍五入,以使格式化结果显示为精确到小数点后三位且值为 17.929。

另外,通过将此处的文档重定向为 bc 的输入,这也可以在没有管道的情况下工作,如下所示,这避免了创建子 shell:

echo -e "please enter math to calculate: \c"
read x
printf "%.3f\n" $(bc -l <<< "scale=4;$x")

【讨论】:

最好是一致的printf "%.3f" $(printf "scale=4;5+50*3/20 + (19*2)/7\n" | bc):) 在这两个地方都不需要 printf 的格式化功能。我故意使用 echo b/c 在该特定部分中没有任何要格式化的内容。另一方面,对于四舍五入 printf "%.3f" 是有道理的。您可能希望在 ***.com/questions/2395284/... 上查看已接受的答案 – 请不要以为我说混合两者是错误的。但是你必须在思考时考虑到对方的困惑(“现在为什么她在这里使用printf而在那里使用echo而不是printf?”)你上面的解释是完美的。 如果你用 printf 做四舍五入,你可以去掉讨厌的scale 感谢分享。通过省略 'scale' 值 17.92857142857142857142 在 64 位框中为 printf() 结果然后舍入和显示。通过使用'scale',printf() 只需要对17.9285 进行四舍五入。【参考方案3】:

您不是在四舍五入,而是在截断它。

$ echo "5+50*3/20 + (19*2)/7" | bc -l
17.92857142857142857142
$ echo "scale = 3; 5+50*3/20 + (19*2)/7" | bc -l
17.928

我知道对数字进行四舍五入的唯一方法是使用awk

$ awk  'BEGIN  rounded = sprintf("%.3f", 5+50*3/20 + (19*2)/7); print rounded '
17.929

所以,在你的例子中:

read x
awk  'BEGIN  rounded = sprintf("%.3f", $x; print rounded '

【讨论】:

以上是关于bc 算术错误的主要内容,如果未能解决你的问题,请参考以下文章

算术运算

算术运算

Shell脚本编程算术运算和条件测试

脚本编程之一

1.2shell脚本运算基础

[shell基础]——算术运算