Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the width of fixed-width integers in bash?

Tags:

bash

limit

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?

like image 904
jfs Avatar asked Sep 29 '22 18:09

jfs


2 Answers

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:

  1. 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)

like image 83
rici Avatar answered Dec 16 '22 11:12

rici


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.

like image 27
John Zwinck Avatar answered Dec 16 '22 11:12

John Zwinck