![Bash 中的大数除法返回错误结果](https://linux22.com/image/1183380/Bash%20%E4%B8%AD%E7%9A%84%E5%A4%A7%E6%95%B0%E9%99%A4%E6%B3%95%E8%BF%94%E5%9B%9E%E9%94%99%E8%AF%AF%E7%BB%93%E6%9E%9C.png)
我正在尝试将大量字节转换为千兆字节。
echo $(( 41003021288998461440 / 1073741824 ))
这将返回 3827300985。这是不正确的。正确答案应该是 38187039354。11 位数字对 10 位数字。
使用不同的“scale = 30”或通过 bc 管道不会改变答案。我做错了什么?
作为替代方案,我尝试了这个:
awk -v var1=41003021288998461440 -v var2=1073741824 'BEGIN { print ( var1 / var2 ) }' OFMT='%25g'
它返回“3.8187e+10”,这似乎在数字上是正确的,但我不知道如何不采用科学计数法。 Printf“%12d”没有帮助,因为它似乎无法处理传递参数中的除法。
我怀疑修复 awk 科学计数法问题可能更容易,但我仍然想知道为什么使用 echo 进行长除法会返回完全错误的结果。这非常令人担忧,而且由于我经常以这种方式进行计算,我想知道我需要做什么才能让 echo 准确计算。
我也知道我以前解决过这个问题......但我忘记是怎么解决的了,现在也记不起来了,唉。
答案1
Bash 整数不是任意精度:
评估以固定宽度的整数进行,不检查溢出,但除以 0 会被捕获并标记为错误。
现代系统中有符号整数的可能上限是 2^63:
$ echo $(( 2**63 - 1 ))
9223372036854775807
$ echo $(( 2**63 ))
-9223372036854775808
$ echo $(( 2**62 ))
4611686018427387904
您的数字太大了(~4x)。如果您想以交互方式执行随机任意精度算术,请使用 Python:
>>> 41003021288998461440 / 1073741824
38187039353.88332
答案2
我发现最好使用 dc 来实现这一点:
V=$(echo "8 k 41003021288998461440 1073741824 / p" | dc)
echo $V
将精度设置为 8,除以接下来的两个值,然后将其从堆栈中弹出。
答案3
最后重建了如何使其准确计算。是的,它确实涉及使用“比例”。
BYTECOUNT=$(echo "scale=0; (( $BYTECOUNT / 1073741824 )) " | bc )
上述方法有效(之前将 BYTECOUNT 设置为非常大的初始数字)。奇怪的是 scale=0 是必需的,因为我认为这应该是默认值,但为了使计算正确,似乎有必要将其明确化。