我正在根据数字计算长宽比高度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 位二进制数字的数字会在双精度浮点数中被截断。