Shell
In general, in shells, you need an external program to perform general math.
$ 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"))'
Why
It's a common result of two issues:
- Individual operation precision.
- Order of operations.
Individual precision
If the operations are carried out as integer, the value of (4/3)
is 1
.
Even in Python (well, Python 2 as the /
means "Integer Division" there):
$ python2 -c 'print(4/3)'
1
But not in Python3:
$ python3 -c 'print(4/3)'
1.3333333333333333
That is why a 800/(4/3)
becomes 800/1
and result in 800
. (in Python2)
$ python2 -c 'print(800/(4/3))'
800
$ python3 -c 'print(800/(4/3))'
600.0
Bash (as most shells) is similar to python2 (integer):
$ bash -c 'echo (800/(4/3))'
800
Order
You can re-order the math to avoid the integer conversion problem.
$ python2 -c 'print(800*3/4)'
600
Or tell python to use floats:
$ python2 -c 'print(800/(float(4)/3))'
600.0
Limit
But don't fall into the illusion that such number is exact. It certainly may look like that:
python2 -c 'print(format(800/(4.0/3),".80f"))'
600.00000000000000000000000000000000000000000000000000000000000000000000000000000000
And a 2^-50
(or 55) value might be exactly represented in binary:
$ python2 -c 'print(format(2**-50,".80f"))'
0.00000000000000088817841970012523233890533447265625000000000000000000000000000000
$ python2 -c 'print(format(2**-55,".80f"))'
0.00000000000000002775557561562891351059079170227050781250000000000000000000000000
But as soon as you mix integers and floats (or do general numeric math) you are bound to get "out of limits" results:
$ python2 -c 'print(format(1 + 2**-50,".80f"))'
1.00000000000000088817841970012523233890533447265625000000000000000000000000000000
$ python2 -c 'print(format(1 + 2**-55,".80f"))'
1.00000000000000000000000000000000000000000000000000000000000000000000000000000000
In general: Numbers with more than 53 binary digits get truncated in double precision floats.
python3 -c "print(800/(4/3))"
, it prints600.0
. – Sylvester Kruin - try Codidact Feb 01 '22 at 21:22python
means Python 2 on my system. I've got Python 3 installed, just not the default. – Mint Feb 02 '22 at 19:32600.00000000000000000150
is a rounding error, similar to that (1/3)*3 is 0.9999999 and not 1. – Thorbjørn Ravn Andersen Feb 02 '22 at 22:20python
as call forpython3
, and still access the legacy with (then explicit) callpython2
. See this answer of mine on stackoverflow for an example. – Buttonwood Feb 03 '22 at 15:20800 * (3 / 4)
, and you can do it all in integers as800 * 3 / 4
. – Toby Speight Feb 10 '22 at 15:31