Large number division in bash returns wrong result

I'm trying to convert a very large number of bytes into gigabytes.

echo $(( 41003021288998461440 / 1073741824 ))

This returns 3827300985. That is incorrect. The correct answer would be 38187039354. 11 digits versus 10.

Using different 'scale = 30' or piping through bc doesn't change the answer. What am I doing wrong?

As an alternative I tried this:

awk -v var1=41003021288998461440 -v var2=1073741824 'BEGIN { print ( var1 / var2 ) }' OFMT='%25g'

Which returns "3.8187e+10", which seems to be numerically correct, but I then can't figure out how not to get in scientific notation. Printf "%12d" isn't helping because it can't seem to handle the division in a passed parameter.

I suspect fixing the awk scientific notation issue would probably be easier, but I'd still like to know why the long division with echo just returns a completely wrong result. That's very concerning, and since I do calculations in that way frequently, I'd like to know what I need to do to get echo to calculate accurately.

I also know that I fixed the problem once before... but I lost how I did it and can't recall now, sigh.


Solution 1:

Bash integers are not arbitrary precision:

Evaluation is done in fixed-width integers with no check for overflow, though division by 0 is trapped and flagged as an error.

A likely upper limit in modern systems would be 2^63 for signed integers:

$ echo $(( 2**63 - 1 ))
9223372036854775807
$ echo $(( 2**63 ))
-9223372036854775808
$ echo $(( 2**62 ))
4611686018427387904 

Your number is waaaay too large (~4x) for that. If you want to do random arbitrary precision arithmetic interactively, use Python:

>>> 41003021288998461440 / 1073741824
38187039353.88332