壳

我正在根据数字计算长宽比高度x,在这个例子中我使用 4:3 的比例,宽度为 800,结果(高度)应该是 600,但 bash 返回 800,我不知道为什么。

我尝试过其他语言,大多数似乎也有问题,php 似乎是少数可以工作的语言之一。

PHP(返回 600)

php -r 'echo 800/(4/3);'

Python(返回 800)

python -c "print(800/(4/3))"

bc -l有点有效(返回 600.00000000000000000150)

-l是“定义标准数学库”,不确定这意味着什么,但它似乎让我更接近我的目标,但是额外的 0 和 150 来自哪里?

echo '800 / (4 / 3)' | bc -l

我猜这与浮点处理或截断3/4.

现在我可以使用php, 就到此为止了,但对于相对简单的计算来说似乎有点矫枉过正。知道这里发生了什么吗?

答案1

Bash 算术仅是整数。所以 4/3 返回 1。800/1 就是 800。

如果您可以控制输入,那么您可以重构并在除法之前进行乘法

$ echo $(( 800*3/4 ))
600

你的其他例子也是“整数”。例如,如果您通过替换4来强制 python 浮点,4.0那么您会得到不同的答案(Python 3 不需要这个)

$ python -c "print(800/(4.0/3))"
600.0

bc -l加载标准数学库(带有诸如s()正弦、l()自然对数等函数),但更重要的是,这里设置scale为 20。scale定义在除法中生成基数后有多少位小数,因此4/3将会有1.33333333333333333333(实际上133333333333333333333/1e+20),并且这解释了为什么你会得到600.00000000000000000150.

echo 'scale=1000; 800/(4/3)' | bc

将为您提供更高的精度(无需加载数学库),但您永远无法达到目标,600因为4/3无法以十进制表示。

答案2

一般来说,在 shell 中,您需要一个外部程序来执行一般数学运算。

$ bc -l <<<'800/(4/3)'
$ bc -l <<<'scale=200;800/(4/3)'
$ awk 'BEGIN{print 800/(4/3)}'
$ awk 'BEGIN{printf "%.60f\n",800/(4/3)}'
$ python3 -c 'print(800/(4/3))'
$ python3 -c 'print(format(800/(4/3),".60f"))'

为什么

这是两个问题的共同结果:

  • 个体操作精准。
  • 操作顺序。

个体精度

如果按整数进行运算,(4/3)则的值为1

即使在 Python 中(Python 2 的意思是/“整数除法”):

$ python2 -c 'print(4/3)'
1

但在 Python3 中则不然:

$ python3 -c 'print(4/3)'
1.3333333333333333

这就是为什么 a800/(4/3)变成800/1并导致800。 (在Python2中)

$ python2 -c 'print(800/(4/3))'
800

$ python3 -c 'print(800/(4/3))'
600.0

Bash(与大多数 shell 一样)类似于 python2(整数):

$ bash -c 'echo (800/(4/3))'
800

命令

您可以重新排序数学以避免整数转换问题。

$ python2 -c 'print(800*3/4)'
600

或者告诉 python 使用浮点数:

$ python2 -c 'print(800/(float(4)/3))'
600.0

限制

但不要误以为这个数字是精确的。它当然可能看起来像这样:

python2 -c 'print(format(800/(4.0/3),".80f"))'
600.00000000000000000000000000000000000000000000000000000000000000000000000000000000

并且一个2^-50(或 55)值可以精确地用二进制表示:

$ python2 -c 'print(format(2**-50,".80f"))'
0.00000000000000088817841970012523233890533447265625000000000000000000000000000000

$ python2 -c 'print(format(2**-55,".80f"))'
0.00000000000000002775557561562891351059079170227050781250000000000000000000000000

但是一旦你混合整数和浮点数(或者进行一般的数值数学),你一定会得到“超出限制”的结果:

$ python2 -c 'print(format(1 + 2**-50,".80f"))'
1.00000000000000088817841970012523233890533447265625000000000000000000000000000000

$ python2 -c 'print(format(1 + 2**-55,".80f"))'
1.00000000000000000000000000000000000000000000000000000000000000000000000000000000

一般来说:超过 53 位二进制数字的数字会在双精度浮点数中被截断。

相关内容