Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does "-1" represent in the value range for unsigned int and signed int?

Tags:

c

I am learning C and have a dumb question regarding the "-1" in the value range for unsigned int and signed int. I can't seem to find an explanation for it anywhere.

The paragraph below explains the data range. However, it does not explain the "-1". What does "-1" represent/mean? Is it -1 because it skips 0 and 0 has no value?

In 32-bit integers, an unsigned integer has a range of 0 to 2^32 -1 = 0 to 4,294,967,295 or about 4 billion. The signed version goes from -2^31 -1 to 2^31, which is –2,147,483,648 to 2,147,483,647 or about -2 billion to +2 billion. The range is the same, but it is shifted on the number line.

like image 811
biscuit Avatar asked Aug 29 '19 05:08

biscuit


People also ask

What is the range of signed and unsigned int?

A signed integer is a 32-bit datum that encodes an integer in the range [-2147483648 to 2147483647]. An unsigned integer is a 32-bit datum that encodes a nonnegative integer in the range [0 to 4294967295].

What is the range of unsigned number?

The range of unsigned binary number is from 0 to (2n-1). Example-1: Represent decimal number 92 in unsigned binary number. Simply convert it into Binary number, it contains only magnitude of the given number. It's 7 bit binary magnitude of the decimal number 92.

What is unsigned int vs int?

An int is signed by default, meaning it can represent both positive and negative values. An unsigned is an integer that can never be negative. If you take an unsigned 0 and subtract 1 from it, the result wraps around, leaving a very large number (2^32-1 with the typical 32-bit integer size).

How do you represent unsigned int?

The signed integer is represented in twos complement notation. The most significant byte is 0 and the least significant is 3. The unsigned integer is represented by an unsigned binary number whose most significant byte is 0; the least significant is 3. See the Signed Integer and Unsigned Integer figure (Figure 1).


5 Answers

Consider the values you can achieve with 2 bits:

00 : 0
01 : 1
10 : 2
11 : 3

There are 4 of them, 2 to the power of 2.
But the highest value is not 4, it is 3.
The highest value is 2 to the power of 2 minus 1. I.e. in your representation

2^2-1
or 22-1

Add a bit and you get twice the number, by adding

100 : 4
101 : 5
110 : 6
111 : 7

Total number 8, but highest number 7.

So the "-1" is because always the first of the total of 2n is used for 0,
the 2nd is used for 1, the 3rd is used for 2.
In the end (2n)th one is not available for 2n, it is already used for 2n-1.

like image 148
Yunnosch Avatar answered Oct 12 '22 01:10

Yunnosch


n bits can represent 2n different values. (The first bit can have two values * the second bit can have two values * the third bit can have two values * ...)

For example, 3 bits can form 23 = 8 different bit patterns, and thus up to 8 different values.

000
001
010
011
100
101
110
111

If each bit pattern represents an integer, then an n-bit integer can represent 2n different integers. For example,

  • It could represent the integers from 0 to 2n-1 inclusively
    (because (2n-1) - (0) + 1 = 2n different values).

    For example,

    000   0
    001   1
    010   2
    011   3
    100   4
    101   5
    110   6
    111   7
    
  • It could represent the integers from -2n-1 to 2n-1-1 inclusively
    (because (2n-1-1) - (-2n-1) + 1 = 2n different values).

    For example,

    100  -4
    101  -3
    110  -2
    111  -1
    000   0
    001   1
    010   2
    011   3
    

You could assign any meaning to these values, but the previously stated ranges are the ones understood by twos'-complement machines for unsigned integers and signed integers respectively.[1]


  1. On a ones'-complement machine, there are two ways of writing zero (0000...00002 and 1000...00002), so the range is only -2n-1-1 to 2n-1-1. I think all modern machines are twos'-complement machines, though.
like image 21
ikegami Avatar answered Oct 12 '22 01:10

ikegami


Adding to @Yunnosch's excellent explanation on unsigned numbers, almost all modern computers use "two's complement" to represent signed binary integers. In two's complement, the most significant bit is used as the "sign bit" and bits are the complement of absolute value of the number + 1. So for the 3 bit example, while the range for unsigned values is 0 to 7, the range for signed values is -4 to 3:

100 : -4
101 : -3
110 : -2
111 : -1
000 :  0
001 :  1
010 :  2
011 :  3

Notice that for signed numbers the range of negative numbers is one greater than the range of positive numbers. That's because, while in number theory, 0 is neither positive or negative, in binary representation, 0 has to be either negative or positive. Because it has the most significant bit cleared, 0 is part of the positive number domain, so that leaves one less positive number available.

like image 24
daShier Avatar answered Oct 12 '22 00:10

daShier


For an unsigned integer type, the value -1 is out of range and cannot be represented in a variable of that type. If you try to assign -1 to an unsigned int a conversion occurs according to the rules of the C standard.

The conversion of a signed value to an unsigned integer type is specified in section 6.3.1.3p2 of the C standard:

Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.60

...

60) The rules describe arithmetic on the mathematical value, not the value of a given type of expression

Assuming as in your example that unsigned int has a value range of 0 to 4,294,967,295 the value -1 is converted by adding -1 + 4,294,967,296 = 4,294,967,295. Note that this conversion happens regardless of how negative numbers are represented on the given system. It is the same for two's complment, ones' compliment, or sign-and-magnitude.

Note that this means that the representation of the converted value need not be the same as the representation of -1.

Using a 4-bit type as an example, converting the value -1 to an unsigned type results in the value 15. The representation of these numbers is as follows:

                sign-and magnitude    ones' complement   two's complement
  -1   (signed)               1001                1110               1111
  15 (unsigned)               1111                1111               1111

While in the two's complement case the result of the conversion keeps the same representation, it changes in the other two cases. For one's complement the representation of -1 is the same as for 14, and for sign-and-magnitude the representation of -1 is the same as for 9.

So what other answers have described regarding two's complement is most likely how those implementations do it (i.e. reinterpreting the representation of -1 as an unsigned value), however from the perspective of C language as an abstract machine what I've described is the only correct way of performing this conversion.

like image 22
dbush Avatar answered Oct 12 '22 00:10

dbush


Where did you find this incorrect paragraph? It appears to be about 2's complement but has the -1 in the wrong place.

For C implementations using one's complement or sign/magnitude signed integers, the range is symmetric around zero (with 2 bit patterns that both represent 0, so the positive range and the negative range are the same size).

Basically nothing ever uses that these days, but the ISO C standard specifies that signed integers are binary and use either two's complement, one's complement, or sign/magnitude.


In 2's complement (nearly universal these days), the range of representable values using n bits is [- 2n-1 , 2n-1 - 1 ]. One bit-pattern (all bits zero) represents the value zero. Every bit has a place-value of 2^i, except the final one which has a place value of -2^(n-1).

The bit-pattern with all bits set represents -1 because sum(2^i, i=0..n-1) is one less than 2^n.

With only the sign bit set, we get the most-negative number: -INT_MIN is signed overflow (undefined behaviour) because it's not representable as an int; it requires a wider integer. Or with wrapping, -INT_MIN = INT_MIN. This is the "2's complement anomaly". https://en.wikipedia.org/wiki/Two%27s_complement#Most_negative_number

You can avoid widening if you're doing an absolute value operation: e.g.
unsigned abs = i >= 0 ? i : -(unsigned)i;

(Converting a negative value to unsigned in C has well-defined behaviour of modulo-reducing until it's in the representable range. In C this is independent of the signed-integer encoding; what matters is the value. So (uint8_t)-1 is always 255. For 2's complement it just copies the bit-pattern. For sign/magnitude or one's complement a C implementation would have to do some math to cast from signed to signed. Notice that I did this before negation, which means 0 - i with the usual unsigned wrapping.)

like image 21
Peter Cordes Avatar answered Oct 12 '22 01:10

Peter Cordes