Does the C++ standard mandate that the non-negative range of a standard signed integer type is at least as big as the negative range?
EDIT: Please note that I am referring to the non-negative range here, not the positive range which is obviously one smaller than the non-negative range.
EDIT: If we assume C++11, the answer is "Yes". See my clarifications below. From the point of view of C++03, the answer is probably "No".
The same question can be posed as follows: Does the standard guarantee that the result of a - b
is representable in a standard signed integer type T
assuming that both a
and b
are negative values of type T
, and that a ≥ b
?
I know that the standard allows for two's complement, ones' complement, and sign magnitude representation of negative values (see C++11 section 3.9.1 [basic.fundamental] paragraph 7), but I am not sure whether it demands the use of one of those three representations. Probably not.
If we assume one of these three representations, and we assume that there is no "spurious" restrictions on either of the two ranges (negative, and non-negative), then it is indeed true that the non-negative range is at least as big as the negative one. In fact, with two's complement the size of the two ranges will be equal, and with the two other representations, the size of the non-negative range will be one greater than the size of the negative one.
However, even if we assume one of the mentioned representations, it is really not enough to guarantee anything about the size of either range.
What I am seeking here, is a section (or set of sections) that unambiguously provides the desired guarantee.
Any help will be appreciated.
Note that something like the following would suffice: Every bit within the "storage slot" of the integer has one, and only one of the following functions:
- Unused
- Sign bit (exclusively, or mixed sign/value bit)
- Value bit (participating in the value)
I have a vague memory that C99 says something along those lines. Anyone that knows anything about that?
Alright, C99 (with TC3) does provide the necessary guarantees in section 6.2.6.2 "Integer types" paragraph 2:
For signed integer types, the bits of the object representation shall be divided into three groups: value bits, padding bits, and the sign bit. There need not be any padding bits; there shall be exactly one sign bit. Each bit that is a value bit shall have the same value as the same bit in the object representation of the corresponding unsigned type (if there are M value bits in the signed type and N in the unsigned type, then M ≤ N ). If the sign bit is zero, it shall not affect the resulting value. If the sign bit is one, the value shall be modified in one of the following ways:
- the corresponding value with sign bit 0 is negated (sign and magnitude);
- the sign bit has the value −(2N ) (two’s complement);
- the sign bit has the value −(2N − 1) (ones’ complement ).
Which of these applies is implementation-defined, as is whether the value with sign bit 1 and all value bits zero (for the first two), or with sign bit and all value bits 1 (for ones’ complement), is a trap representation or a normal value. In the case of sign and magnitude and ones’ complement, if this representation is a normal value it is called a negative zero.
Can someone confirm that this part of C99 is also a binding part of C++11?
I have taken another careful look at both the C99 and the C++11 standards, and it is clear that the guarantees in C99 section 6.2.6.2 paragraph 2 are binding in C++11 too.
C89/C90 does not provide the same guarantees, so we do need C99, which means that we do need C++11.
In summary, C++11 (and C99) provides the following guarantees:
Negative values in fundamental signed integers types (standard + extended) must be represented using one of the following three representations: Two's complement, ones' complement, or sign magnitude.
The size of the non-negative range is one greater than, or equal to the size of the negative range for all fundamental signed integers types (standard + extended).
The second guarantee can be restated as follows:
-1 ≤ min<T> + max<T> ≤ 0
for any fundamental signed integers type T
(standard + extended) where min<T>
and max<T>
are shorthands for std::numeric_limits<T>::min()
and std::numeric_limits<T>::max()
respectively.
Also, if we assume that a
and b
are values of the same, or of different fundamental signed integer types (standard or extended), then it follows that a - b
is well defined and representable in decltype(a - b)
as long as a
and b
are either both negative or both non-negative.