Bash – Find the Largest Number Bash Arithmetic Can Handle

arithmeticbash

How can I let my script determine the largest number for itself?

I looked through my environment variables, and I found these two that looked promising:

~# declare -p BASH_VERSINFO HOSTTYPE
declare -ar BASH_VERSINFO=([0]="5" [1]="0" [2]="11" [3]="1" [4]="release" [5]="x86_64-slackware-linux-gnu")
declare -- HOSTTYPE="x86_64"

…but could I really trust parsing those, in order to draw a conclusion about what the largest number in Bash arithmetic would be? There must be a better way, programmatically. Any suggestions?

Best Answer

Bash arithmetic uses signed numbers.

So the quick answer would be:

((MAX=(1<<63)-1))

But since you want your script to not know about the bitness of the system it's running on, then let's keep going.

Brute force would be, keep adding 1 in a loop, until you hit the point where it will overflow unto a negative number. But that could take years! :-) A quicker and more elegant way to do it is with a simple bit-shift.

Let's find the sign bit, i.e., let's find the number that has 1 in the most signifficant bit, and zeros in all the other bits, however many they may be. Once we have that number, we'll simply subtract 1 from it, and we'll get the largest signed number.

# MIN -- the smallest signed number 0x8000...00  (it equals MAX+1)
# MAX -- the largest signed number  0x7Fff...FF  <-- what we are looking for

MIN=1; until (( (MIN<<=1) < 0 )) ;do :;done
((MAX=MIN-1))

echo $MAX

Result:
9223372036854775807

Or, here's a one-liner, without a loop. We put the hex representation of a number in a variable, and then mask the sign bit through the variable expantion when passing it to the printf builtin:

printf -v MAX %x -1 && printf -v MAX %d 0x${MAX/f/7}

echo $MAX

Result:
9223372036854775807

On a machine with a different bitness than mine, the result will be a different number.

And just for illustration, in my case:

printf "MAX %X  %d\nMIN %X %d\n" $MAX $MAX $MIN $MIN
MAX 7FFFFFFFFFFFFFFF  9223372036854775807
MIN 8000000000000000 -9223372036854775808

A little side note about MIN: You may want to constrain yourself to using ((MIN=-MAX)), otherwise you will occasionally run into problems with some arithmetic operations.

((MIN=-MAX)) ; printf "MIN %X %d\n" $MIN $MIN
MIN 8000000000000001 -9223372036854775807
Related Question