Armen Babakanian
Armen Babakanian

Reputation: 2345

shell bit shifting producing different numbers

in my local machines bash when I run:

echo $((192 << 24))
3221225472

but on my embedded targets busy box SHELL I get something else:

echo $((192 << 24))
-1073741824

it works when I left shift by a smaller number though. The embedded device is 64bit, where my local host is 32 bit.

Just to be clear, on the 32bit machine, the value is positive, on the 64 bit machine it's negative.

EDIT: This is on the embedded device which is 64 bit machine with SHELL. It doesn't happen when left shifting by 23.

echo $((192 << 23))
1610612736
echo $((192 << 24))
-1073741824

On the local host, which is a 32 machine with BASH:

echo $((192 << 55))
6917529027641081856
echo $((192 << 56))
-4611686018427387904

Upvotes: 5

Views: 13920

Answers (6)

pepeR0ni
pepeR0ni

Reputation: 11

Got the same on on my native embedded android shell but after starting busybox shell it works correctly.

# echo $((192 << 23))
1610612736
# echo $((192 << 23))
1610612736
# echo $((192 << 24))
-1073741824

# busybox sh
/ # echo $((192 << 23))
1610612736
/ # echo $((192 << 24))
3221225472
/ # busybox

using BusyBox v1.19.3

Upvotes: 1

loreb
loreb

Reputation: 1357

POSIX (here) says "Only signed long integer arithmetic is required", and in C a long is at least 32 bits; that being said, some shells explicitly choose a fixed width, eg mksh uses 32 bits arithmetic, and peeking at the busybox' source (math.h) it seems like they only use 64 bits is ENABLE_SH_MATH_SUPPORT_64 is #define'd, regardless of whether the underlying system is 32/64 bits. If anyone knows better, speak up!

Upvotes: 2

devnull
devnull

Reputation: 123608

It's apparent that the result is overflowing on your embedded device. Some calculations based on your findings seem to substantiate the hypothesis:

$ echo 3221225472 - 1073741824 | bc -l
2147483648

$ echo 2^31 | bc -l
2147483648

If you try with more on your local machine, you'd figure that it'd overflow too!

$ echo $((192 << 56))
-4611686018427387904

EDIT: As you've commented that you're Busybox 1.13.2, there's a chance that you're running into this issue. Upgrading might help!

Upvotes: 1

Digital Trauma
Digital Trauma

Reputation: 16016

I think you almost answered your own question - the shell in the 32bit machine presumably uses 32bit signed integers for this kind of arithmetic, whereas the shell in the 64bit machine presumably uses 64bit signed integers. With 32bit signed integers, the max possible value is 2^31, so 3221225472 would result in an overflow.

Upvotes: 1

konsolebox
konsolebox

Reputation: 75568

Well it simply because of the number of bits the number is represented. 192 (0xc0) when shifted becomes 0xc0000000. On a 32 bit machine, it's already a negative number whereas on a 64bit machine, it's still on the range of a positive number.

Upvotes: 1

Dan
Dan

Reputation: 10786

The binary representation of 192 is 11000000. When you shift it left 24 places, the only two bits which are set are the two most significant bits - the representation is 11000000 00000000 00000000 00000000. When a 32 bit system sees the most significant bit set, it interprets it as a negative number in "two's complement" format. For a 64 bit system, the most significant bit is still zero, so it is interpreted as a positive number.

This is simply an integer overflow on the 32 bit machine. You could expect the same behavior in C or any other language when using 32 vs 64 bit signed integer types.

Upvotes: 3

Related Questions