20

I'm curious as to what happens when a numeric variable in bash is incremented up without purposely stopping it. How large can the number get? Will it overflow and become negative and just continue to increment forever? Will it break and skid to a stop at some point?

I am using an x86_64 AMD processor, but I would be happy to hear 32bit answers as well, just specify which you are talking about. I am running Fedora21 64bit.

I've googled far and wide but haven't found this specific tidbit for some odd reason. It seems like it would be a basic piece of info in all the manuals and such.

  • 3
    How about printing out some powers of 2 as a starter: for i in {0..70}; do echo 2 to the power of $i = $((2**i)); done – mpy Jan 22 '16 at 21:19
  • 1
    If you want big numbers, you might switch to ksh which does floating point arithmetics, not integer one like bash: ksh -c 'echo $((2**1023))'8.98846567431157954e+307 – jlliagre Jan 22 '16 at 21:36
  • I will keep ksh in mind if I need floating point or values in the stratosphere, floating point can be quite useful. But this question is simply so that I know the limits of my system, it is not because I need to exceed its limits. I will do something like mpy suggests, I didn't to start with because I didn't want risk causing a system crash. – Max Power Jan 23 '16 at 0:27
24

It may come down to your version of bash, your OS, and your CPU architecture. Why don't you try it yourself? Set a variable to (2^31)-1, then increment it, set it to 2^32, then increment it, set it to 2^64, then increment it, etc.

Here, I just tried it myself on my Core i7 Mac running OS X "El Capitan" v10.11.3, and it looks like bash is using signed 64-bit integers.

$ uname -a
Darwin Spiff.local 15.3.0 Darwin Kernel Version 15.3.0: Thu Dec 10 18:40:58 PST 2015; root:xnu-3248.30.4~1/RELEASE_X86_64 x86_64
$ bash --version
bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15)
Copyright (C) 2007 Free Software Foundation, Inc.
$
$ ((X=2**16)); echo $X
65536                        <-- okay, at least UInt16
$ ((X=2**32)); echo $X
4294967296                   <-- okay, at least UInt32
$ ((X=2**64)); echo $X
0                            <-- oops, not UInt64
$ ((X=(2**63)-1)); echo $X
9223372036854775807          <-- okay, at least SInt64
$ ((X++)); echo $X
-9223372036854775808         <-- overflowed and wrapped negative. Must be SInt64
| improve this answer | |
3

I set up a loop. while return status is 0 increment a variable with addition and print the variable to stdout I started it just under 2^31, I let it pass both 2^31 and 2^32 with no issue, stopped it, then set the initial value to just under 2^63. The result was that it seamlessly rolled over from 9.22e18 to -9.22e18 and continued to increment positively. (toward zero)

Just to check that my while [ $? -eq 0 ] was actually using the exit status of the commands within the while loop, not using the exit status of the previous script or some oddity, I also ran it with an extra command inside the loop designed to create a non zero exit status at particular increments.

So it is signed, it will roll over rather than stop at max value, and it does so without any error message. So it is possible to end up in a truly infinite loop. It does not limit the 64bit hardware and 64bit linux OS to an old 16 or 32bit standard.

| improve this answer | |
2

bash use 64-bit integer. So if you increase after variable reaching its max number, variable will overflow. Below is my test with unsigned int and signed integer.

MAX_UINT = 18446744073709551615
MAX_INT = 9223372036854775807

$ printf "%llu\n" $((2**64))
0
$ printf "%llu\n" $((2**64-1))
18446744073709551615

$ printf "%lld\n" $((2**63-1))
9223372036854775807
$ printf "%lld\n" $((2**63))
-9223372036854775808
$ printf "%lld\n" $((2**64-1))
-1
| improve this answer | |
  • 2
    please add some text explaining how this answers the question. It looks like you are trying to demonstrate the upper limits via code - can you explain why this code will achieve the required outcome? – Sir Adelaide Jul 13 '18 at 6:15
  • I think the point is that we dont know that we can use 64 and we need to figure it out (unless you can link to a spec?). To get rid of this you can use these two; printf "%llu\n" $(((~0))) for unsigned and printf "%llu / 2\n" $(((~0))) | bc -l | grep -oP '^\d+' for signed MAX's. But now the point becomes "how did I know my system supported %llu?" – Hashbrown Apr 20 at 10:34
0

I improved and automated @Spiff 's answer:

MAX_INT=0
for ((x=1,y=1; x<<=y; y<<=1))
do
    if ((x>0))
    then
        MAX_INT=$x
        continue
    fi

    if (((x=~x)>0))
    then
        MAX_INT=$x
    fi
    break
done
echo $MAX_INT
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.