# How do computers represent integers

Time：2021-8-12

[TOC]

In a computer, any data is represented by binary: 0 and 1. Integers are no exception. In life10, expressed in an 8-byte integer as00001010。 But this can only represent positive numbers and zero. How to express negative numbers? So there is the concept of sign bit. In an 8-byte integer, the highest bit is the sign bit, 0 represents a positive number and 1 represents a negative number. therefore-10You can use it10001010To show. However, the direct use of sign bits brings a series of problems:

• 00000000and10000000Expressed as0and-0, then use that0, or are they all zero?

On the addition problem, try the operation1 - 1Value of:

1. take1 - 1convert to1 + (-1)
2. Convert to binary:00000001 + 10000001
3. The operation result is10000010Convert to decimal-2

Obviously, the result is wrong. In order to solve this problem, 2’s complement is introduced into the computer. To explain why complement is used, start with unsigned integers.

For ease of understanding and convenience, I use 3-byte integers to explain. However, since the minimum of C language is 8 bytes, 8 bytes are used in code verification.

## Unsigned integer

In a 3-byte unsigned integer, 2 ^ 3 ^ = 8 numbers can be represented:

000 = 2^2 * 0 + 2^1 * 0 + 2^0 * 0 = 0+0+0 = 0
001 = 2^2 * 0 + 2^1 * 0 + 2^0 * 1 = 0+0+1 = 1
010 = 2^2 * 0 + 2^1 * 1 + 2^0 * 0 = 0+2+0 = 2
011 = 2^2 * 0 + 2^1 * 1 + 2^0 * 1 = 0+2+1 = 3
100 = 2^2 * 1 + 2^1 * 0 + 2^0 * 0 = 4+0+0 = 4
101 = 2^2 * 1 + 2^1 * 0 + 2^0 * 1 = 4+0+1 = 5
110 = 2^2 * 1 + 2^1 * 1 + 2^0 * 0 = 4+2+0 = 6
111 = 2^2 * 1 + 2^1 * 1 + 2^0 * 1 = 4+2+1 = 7

Since it is an integer, it is inevitable to add, subtract, multiply and divide.

In a computer, four operations of integers that can be completed only by addition:

• Subtraction is to add a negative number.
• Division is constantly subtracting, and subtraction can be converted into addition.

But there are problems:

• What if the sum of two unsigned integers exceeds the range represented by 3 bytes? For example:3 + 7
• Subtract two unsigned integers. Convert to plus a negative number. Since it is an unsigned integer, where does it come from?

To solve this problem, look up at the clock on the wall.

### Clock system

Suppose it’s four o’clock:

But it’s actually six o’clock now. You have to set the pointer to six o’clock now. You can do this:

1. Adjust clockwise for 2 hours:

2. Adjust counterclockwise for 10 hours:

3. Adjust clockwise for 14 hours, counterclockwise for 22 hours

Mathematically express the above process: rotating clockwise for a few hours is equal to adding a few hours. Counterclockwise is minus a few hours. yes:

4 + 2 = 6
4 - 10 = 6
4 + 14 = 6
4 - 22 = 6

One lap of the clock is 12 hours. That is, in the clock system, the problem of upward overflow and downward overflow is solved by module 12

$$4 – 10 \equiv 4 + (-10) \equiv 4 + (-10 \bmod 12) \equiv 4 + 2 \equiv 6 \pmod{12} \\$$

It can be said that 4 and – 10congruence

### How to take the remainder of a negative number

We all know about integer remainder. We’ve beenRemaindersubtractremainderUntil it is less than 0. Similarly, we can take negative remainderRemainderaddremainderIt is enough to know that it is greater than 0.

According to the above ideas, we can write code soon:

/**
*Number is remainder
*Mod remainder
*/
int min_mod(int number, int mod)
{
if (number >= 0) {
while (number - mod >= 0) {
number = number - mod;
}
return number;
}
else {
while (number + mod < 0) {
number = number + mod;
}
return number + mod;
}
}

Although the above is easy to understand, the code execution efficiency is not high, and the time complexity isO(n)

We add the remainder to the division, including:

$$\frac{divident}{divisor} = quotient \dots remainder$$

Switch:

$$divident = quotient \times divisor + remainder \qquad 1$$

Exchange the order and the remainder is:

$$remainder = divident – quotient \times divisor \qquad 2$$

Where quotient is the result of dividing the divisor by the divisor and rounding down the floor:

$$quotient = \lfloor \frac{divident}{divisor} \rfloor$$

Note: $\ lfloor \ rfloor$is a symbol rounded down. For example, $\ lfloor 3.5 \ rfloor = 3$, $\ lfloor – 1.3 \ rfloor = 2$.

15/12be equal to1.25Round it down1-10/12be equal to0.833..Round down to-1。 Rounding down can be understood as taking an integer closer to negative infinity.

In C / C + + / Java, negative division is rounded up. that is-10/12be equal to0。 In Python, negative division is rounded down.

Combining Formula 1 and formula 2, it can be concluded that:

$$remainder = divident – divisor \times \lfloor \frac{divident}{divisor} \rfloor$$

Now the above code can be optimized into one sentence:

int one_step_mod(int number, int mod)
{
return number - (mod * (int)floor(number * 1.0 / mod));
}

Don’t forget to addmath.hHeader file.

Besides, try to think about it* 1.0What does it do? Can’t you add it?

### Solving the problem of unsigned integer with the implementation of clock

After understanding the operation of the clock, let’s look at two problems of unsigned:

• What if the sum of two unsigned integers exceeds the range represented by 3 bytes? For example:2 + 7
• Subtract two unsigned integers. Convert to plus a negative number. Since it is an unsigned integer, where does it come from?

If an unsigned integer of 3 bytes is regarded as a clock, it will look like this:

Then unsigned integers can also solve the above problems through congruence operation:

#### The addition exceeds the range, resulting in overflow

Add two unsigned integers. If it is out of range, directly modulo 2 ^ n ^:

$$2 + 7 \equiv 9 \bmod 8 \equiv 1 \pmod 8$$

Reflected in the clock, it is to rotate the pointer clockwise for 7 hours.

Subtracting an integer is equivalent to adding a negative number. First convert the negative number into the smallest integer under 2 ^ n ^ and perform addition operation:

$$2 – 7 \equiv 2 + (-7 \bmod 8) \equiv 2 + 1 \equiv 3 \pmod 8$$

Reflected in the clock, it is to rotate the pointer counterclockwise for 7 hours.

#### summary

The computer uses congruence operation to solve up overflow and negative numbers. The addition of unsigned integers is actually equivalent to the addition of modulo 2 ^ n ^.

### Code verification

talk is cheap, show me your code.

After all, verify the process through code:

It should be noted that the minimum data type in C language is 8 bytes, which is slightly different from the above 3 bytes.

int main()
{
uint8_t two = 2;
uint8_t last = 255;
printf("%d \n", two);  // 2
printf("%d \n", last); // 255
uint8_ t temp = two + last; //  Clockwise rotation
printf("%d \n", temp); // 1
temp = two - last; //  Counterclockwise rotation
printf("%d \n", temp); // 3
temp = -2;
printf("%d \n", temp); // 254
return 0;
}

Don’t forget to introducestdint.hHeader file.

After learning unsigned integers, see if you can give the correct answer to the following question:

int main()
{
uint8_t a = -128;
uint8_t b = a / -1;
printf("%d", b); // what is it?
return 0;
}

## Signed integer

If only sign bits are used to represent 3-byte signed integers, it can represent 2 ^ 3 ^ – 1 = 7 numbers:

000 = (2^1 * 0 + 2^0 * 0) *  1 =   0+0  =  0
001 = (2^1 * 0 + 2^0 * 1) *  1 =   0+1  =  1
010 = (2^1 * 1 + 2^0 * 0) *  1 =   2+0  =  2
011 = (2^1 * 1 + 2^0 * 1) *  1 =   2+1  =  3
100 = (2^1 * 0 + 2^0 * 0) * -1 = -(0+0) =  0
101 = (2^1 * 0 + 2^0 * 1) * -1 = -(0+1) = -1
110 = (2^1 * 1 + 2^0 * 0) * -1 = -(2+0) = -2
111 = (2^1 * 1 + 2^0 * 1) * -1 = -(2+1) = -3

As mentioned earlier, if only sign bits are used to represent signed integers, there will be the following problems:

• Representation of 0.
• Addition cannot work out the result.

If you look closely, you will find that it can only represent negative numbers, and nothing else can be done: four operations (that is, addition) will make mistakes, and two zeros.

If you want to know how it introduces this problem and convert this bad representation into a clock, you may understand:

From the above figure, we can find that it does not follow the congruence operation. Watch carefully101that is-1This place, in an unsigned integer, represents5。 In signed integers, since the highest bit is occupied by the sign bit, the maximum positive number is011that is3。 therefore101Can only be expressed as a negative number. To ensure congruence, just find another number and5about8Congruence is enough.

And5about8There are many congruences:13, 21, -3...。 This number also satisfies one condition: the maximum negative number. So it is:5 - 8 = -3

### Introduction of complement

In this way, the above bad clock is changed to the representation following congruence operation:

As you may have found, this standard is what we often call complement.

Because the congruence theorem is followed, there are no two problems in the complement system:

• There is only one 0 in the complement system, and there is no ambiguity.
• 1-1 => 1 + (-1) => 001 + 111 => 000 => 0, there is no problem with addition.

So why complement? Because the congruence operation should be guaranteed. Congruence operation is the core principle of integer operation.

### Representation of complement

According to the above figure, complement is well represented:

• Positive numbers and zero, no change, no modification.
• And negative numbers, for example-1, that is, rotate counterclockwise for one hour. According to the congruence theorem, rotating counterclockwise for one hour means rotating clockwise for seven hours:

$$-1 \equiv 7 \pmod 8$$

That is, when the symbol bit is1For example111，在正整数（7）的基础上逆时针旋转 8 个小时就是补码：

补码
----
000 = (2^2 * 0 + 2^1 * 0 + 2^0 * 0)     = 0+0 =  0
001 = (2^2 * 0 + 2^1 * 0 + 2^0 * 1)     = 0+1 =  1
010 = (2^2 * 0 + 2^1 * 1 + 2^0 * 0)     = 2+0 =  2
011 = (2^2 * 0 + 2^1 * 1 + 2^0 * 1)     = 2+1 =  3
100 = (2^2 * 1 + 2^1 * 0 + 2^0 * 0) - 8 = 4-8 = -4
101 = (2^2 * 1 + 2^1 * 0 + 2^0 * 1) - 8 = 5-8 = -3
110 = (2^2 * 1 + 2^1 * 1 + 2^0 * 0) - 8 = 6-8 = -2
111 = (2^2 * 1 + 2^1 * 1 + 2^0 * 1) - 8 = 7-8 = -1

$$f(补) = \begin{cases} x & 符号位 = 0\\ x-8 & 符号位 = 1 \end{cases}$$

int main()
{
int n;
puts("Please input a number, represent a few bytes: ");
scanf("%d", &n);
int count = 1 << n;

for (int i = 0; i < count; i++) {
if (i >= (1 << n - 1)) { // 如果这个数的符号位为 1
printf("%d ", i - count);
}
else printf("%d ", i);
}
return 0;
}

### 反码（1’s complement）的误区

原码  反码
---------
000 = 000 =  0
001 = 001 =  1
010 = 010 =  2
011 = 011 =  3
100 = 111 = -0
101 = 110 = -1
110 = 101 = -2
111 = 100 = -3

$$1 – 1 = 1 + (-1) = 001_{正} + 101_{正} = 001_{反} + 110_{反} = 111_{反} = -0 = 0$$

$$-1 + (-2) = 101_{正} + 110_{正} = 110_{反} + 101_{反} = 011_{反} = 3$$

### 反码加上一等于补码

$$f(原) = \begin{cases} 2^{1} \times b + 2^{0} \times c \\ (2^{1} \times b + 2^{0} \times c) \times (-1) \end{cases} = \begin{cases} 2b + c & a = 0\\ – (2b +c) & a = 1 \end{cases}$$

$$f(反) = \begin{cases} 2^{2} \times a + 2^{1} \times b + 2^{0} \times c \\ 2^{2} \times a + 2^{1} \times (1 – b) + 2^{0} \times (1 – c) \end{cases} = \begin{cases} 2b + c & a = 0\\ -(2b +c) + 7 & a = 1 \end{cases}$$

$$f(补) = \begin{cases} f(原) \\ f(原) + 8 \end{cases} = \begin{cases} 2b + c & a = 0\\ 8 – (2b + c) & a = 1 \end{cases}$$

$$f(反) + 1 = -(2b + c) + 8 = -(2b + c) \pmod 4 \qquad 3$$

$$f(补) = 8 – (2b + c) = -(2b + c) \pmod 4 \qquad 4$$

$$f(反) + 1 = f(补)$$

### 代码验证

int main()
{
int8_t two = 2;
int8_t last = 127;
printf("%d \n", two);      // 2
printf("%d \n", last);     // 127
int8_t temp = two + last; // 顺时针旋转
printf("%d \n", temp);     // -127
temp = two - last;         // 逆时针旋转
printf("%d \n", temp);     // -125
return 0;
}

int main()
{
int8_t a = -128;
int8_t b = a / -1;
printf("%d", b); // what is it?
return 0;
}

## 参考资料

https://zh.wikipedia.org/wiki…

https://www.cnblogs.com/zhang…

https://zh.wikipedia.org/wiki…

https://zh.wikipedia.org/wiki…

https://blog.csdn.net/woodpec…

http://www.ruanyifeng.com/blo…