Shell Arithmetic says:
Evaluation is done in fixed-width integers with no check for overflow, though division by 0 is trapped and flagged as an error.
Example:
$ echo $(( 1 << 32 ))
4294967296
$ echo $(( (1 << 64) - 1 ))
0
What are integer limits in shell arithmetic in bash?
@rici pointed out that POSIX shell guarantees signed long integer range (as defined by ISO C):
-2**31+1 to +2**31-1
@John Zwinck pointed out that bash
source code indicates that intmax_t
is used:
All arithmetic is done as
intmax_t
integers with no checking for overflow
Does bash guarantee in its documentation that it uses intmax_t
or some other C type for integers?
Bash does not document the precise size of integers, and the size may vary from platform to platform.
However, it does make an attempt to conform to Posix, which specifies that arithmetic expansion uses signed long arithmetic, which must be at least 32 bits including the sign bit.
Posix does not require integer arithmetic to be modulo 2k for any value of k
[but see Note 1], although bash
on common platforms will do so, and it particularly does not guarantee that arithmetic operators will behave exactly as though the values were signed longs. Posix even allows the simulation of integer arithmetic with floating point, provided that the floating point values have sufficient precision:
As an extension, the shell may recognize arithmetic expressions beyond those listed. The shell may use a signed integer type with a rank larger than the rank of signed long. The shell may use a real-floating type instead of signed long as long as it does not affect the results in cases where there is no overflow. (XSH §2.6.4)
That would permit the use of IEEE-754 floating point doubles (53 bits of precision) on a platform where long
was only 32 bits, for example. While bash
does not do so -- as documented, bash
uses a fixed-width integer datatype -- other shell implementations might, and portable code should not make assumptions.
Notes:
Posix generally defers to the ISO C standard, but there are a number of places where Posix adds an additional constraint, some of which are marked as extensions (CX):
POSIX.1-2008 acts in part as a profile of the ISO C standard, and it may choose to further constrain behaviors allowed to vary by the ISO C standard. Such limitations and other compatible differences are not considered conflicts, even if a CX mark is missing. The markings are for information only.
One of these additional constraints is the existence of exact-width integer types. Standard C requires the types int_{least,fast}{8,16,32,64}_t
and their unsigned analogues. It does not require the exact-width types, such as int32_t
, unless some integer type qualifies. An exact-width type must have exactly the number of bits indicated in its name (i.e. no padding bits) and must have 2's-complement representation. So INT32_MIN
, if it is defined, must be exactly -231 (§7.20.2.1).
However, Posix does require the exact-width types int{8,16,32}_t
(as well as the unsigned analogues), and also int64_t
if such a type is provided by the implementation. In particular, int64_t
is required if the "implementation supports the _POSIX_V7_LP64_OFF64
programming environment and the application is being built in the _POSIX_V7_LP64_OFF64
programming environment." (XBD, §13, stdint.h
) (These requirements are marked as CX.)
Despite the fact that int32_t
must exist, and therefore there must be some 2's complement type available, there is still no guarantee that signed long
is 2's-complement, and even if it is, there is no guarantee that integer overflow wraps around rather than, for example, trapping.
Most relevant to the original question, though, is the fact that even if signed long
is the same type as int64_t
and even if signed integer overflow wraps around, the shell is not under any obligation to actually use signed long
for arithmetic expansion. It could use any datatype "as long as it does not affect the results in cases where there is no overflow." (XSH, §2.6.4)
Bash uses intmax_t
in its C implementation of arithmetic. You can see it here: http://www.opensource.apple.com/source/bash/bash-30/bash/expr.c
This means it will be the "largest" integer type on your platform. Keep in mind that some platforms have "even larger" integers, e.g. 128 bit ints on some 64 bit platforms, but those "extraordinary" types are not included here, so most systems will see Bash using 32 or 64 bit math for now.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With