Loading... # 如果页面打开时,数学公式显示为一些奇怪的数字和字符,请刷新页面,直到看到数学公式! ## 为什么要用补码? 我们有 **原码、反码、补码**这么多种码,那为什么signed型的许多类型数据,比如int、char,还有大量的二进制数据,是以补码的形式存放在寄存器里,而不是以简单明了的原码形势呢? ### 我们现在来用二进制做一个减法 64 + (-16) = ? ### 原码的减 <div class="tip inlineBlock warning"> 这里我们使用一个字节(8位)的标准__int8(char)类型,来表示带符号的二进制数 </div> 显然,十进制数64的二进制为: ```latex 01000000 ``` 而十进制-16的二进制为: ```latex 10010000 符号类型的首位数字为“符号位”,0代表正数,1代表负数。 ``` 做个减法 **原码符号位不参与计算,数值位进行加减。** $$ \begin{align} 01000000 \\ +\quad10010000 \\ ——————— \\ 11010000 \end{align} $$ なに!?二进制的1101000是十进制的 **-80**,显然这是错误的,原码不可以用于减法运算。于是有人发明了 **反码** ------ ### 反码的减 > 人为规定反码最高位为符号位,正数为0,负数为1, > > 反码正数与原码正数格式一致, > > 反码负数为负数绝对值的原码按位分别取反 ![反码][1] 所以,64的反码为 ```latex 01000000 ``` -16的反码为 ```latex 11101111 ``` 我们再来做一下减法,请注意,在反码中 **如果最高位(符号位)发生了溢位,则需要在最低位加上1** $$ \begin{align} 01000000 \\ +\quad11101111 \\ ——————— \\ (第九位溢位舍去,最低位加一)100101111 \\ +1 \\ ——————— \\ 00110000 \end{align} $$ 00110000代表十进制48,显然64+(-16)=48,减法运算正确。 不过这看起来很完美的方法却有一点小纰漏: | 二进制反码 | 十进制 | | :--------: | ------ | | 00000000 | +0 | | 10000000 | -0 | 你有听说过+0和-0的存在吗?反正我没有,虽然我可以容忍,但是反码减法的算法规则比较复杂,需要增加计算机内部逻辑组件额外判断溢位,会影响计算效率,在那个年代这是不能容忍的。于是就有了 **补码** ------ ### 补码的减 > 正数的补码与原码格式相同, > > 负数的补码,是将原码变为反码,再加上1 ![补码][2] 于是,64的补码还是: ```latex 01000000 ``` -16的补码是: ```latex 11110000 ``` 再来做一下减法,并且 **补码的加法更简单,直接丢弃溢位,不需要针对溢位单独处理** 或者说 **符号位要作为数的一部分一起参加运算,符号位产生的进位要丢掉** $$ \begin{align} 01000000 \\ +\quad11110000 \\ ——————— \\ (第九位的1溢位直接舍去)100110000 \\ ——————— \\ 00110000 \end{align} $$ やりますね 显然00110000变为48,那么问题来了 $$ 10000000\quad \& \quad00000000 \\ 现在各自表达什么意思? $$ | 二进制补码 | 十进制 | | :--------: | :----: | | 10000000 | -128 | | 00000000 | 0 | ん?为什么10000000变成-128了呢? 这其实是完成了一个数字上的闭环:**四位补码1000**为十进制的**-8**,八位补码**10000000**为十进制 **-128**, 其实就是把最高位符号位的数字,在用作**表示正负**的同时表示**数值位**。 然后最高位为1的负数的表示,就由这个最大负数加上后面的数值位,举个栗子:二进制补码的*10000001* $$ \begin{align} 10000001 \\ =\\ \quad10000000 \\ +\quad00000001\\ ——————— \\ (这里用十进制方便理解)-128 \\ +\quad1\\ ——————— \\ -127\\ \end{align} $$ 所以以此类推: | 二进制补码 | 十进制 | | :--------: | ------ | | 01111111 | 127 | | 10000000 | -128 | | 10000001 | -127 | | ········ | ··· | | 11000000 | -64 | | ········ | ·· | | 11111111 | -1 | | 00000000 | 0 | | 00000001 | | 这样就实现了一个闭环,只要不断加下去,数值就会不断变大,除了在01111111时再加一,最大正值会变成最小负值以外,只要不断+++,就可以从起点环绕一圈再回到起点. ![一个数据“地球”][3] 现在我们再来看看不同数据类型可以表现的数据范围: <div class="tip inlineBlock success"> signed\unsigned意味着有符号\无符号 一个字节为8bit,也就是占八位 </div> | 类型名称 | 字节 | 其他名称 | 值的范围 | | :--------------------- | :--- | :--------------------------------------------------- | :------------------------------ | | **`int`** | 4 | **`signed`** | -2,147,483,648 到 2,147,483,647 | | **`unsigned int`** | 4 | **`unsigned`** | 0 到 4,294,967,295 | | **`__int8`** | 1 | **`char`** | -128 到 127 | | **`unsigned __int8`** | 1 | **`unsigned char`** | 0 到 255 | | **`__int16`** | 2 | **`short`**, **`short int`**, **`signed short int`** | -32,768 到 32,767 | | **`unsigned __int16`** | 2 | **`unsigned short`**, **`unsigned short int`** | 0 到 65,535 | 现在可以看懂这个表了吗? [1]:https://image.oplin.cn/photo/oplin.cn/data_complement/two_complement1.jpg [2]:https://image.oplin.cn/photo/oplin.cn/data_complement/two_complement2.jpg [3]:https://image.oplin.cn/photo/oplin.cn/data_complement/one_complement.png 最后修改:2023 年 01 月 26 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 5 如果觉得我的文章对你有用,请随意赞赏
8 条评论
不错不错,我喜欢看 www.jiwenlaw.com
看的我热血沸腾啊https://www.ea55.com/
想想你的文章写的特别好https://www.jiwenlaw.com/
不错不错,我喜欢看
想想你的文章写的特别好
叼茂SEO.bfbikes.com
叼茂SEO.bfbikes.com
博主真是太厉害了!!!