首页 > 其他分享 >计算机的原码,反码,补码

计算机的原码,反码,补码

时间:2022-12-07 16:36:27浏览次数:65  
标签:反码 补码 负数 正数 原码 1000

我一直想为什么计算机中一定要规定有反码、补码?原码不能解决计算机的计算能力吗?反码,补码的出现解决哪些问题?

带着这个问题,我对计算机知识进行脑补。

原理

因为计算机的一切都是通过0和1来表示,也就是二进制。而数值又分为有符号数和无符号数,无符号数理解起来,则要相对简单一些,没有符号位,即所有的二进制位都参与值计算,也就是说无符号数表示的都是正数,比如c语言中的unsigned int。但是现实当中,数值是分有正数与负数区分。在计算机当中0表示正数,1表示负数。往往一串二进制表达数值时,一般取最高为的数来表达正负。无论unsigned int还是有符号的数,计算过程中都是在数值范围内进行计算才得到正确的值。

​有符号数:数值的最高位表示正负,1表示负,0表示正数,以8位的二进制数为例,10001010表示负数-10,而00000101则表示正数5;

无符号数:最高位是值的一部分,比如10001010换算成10进制就是138。

而有符号数的表示有3种方式:原码、反码和补码。

这里我们先只给出原码概念:

原码(十进制转二进制的值):即符号位用 0 表示正数,而用 1 表示负数,其他位表示数值本身。比如:10001010表示-10,00000101表示+5。

了解计算机底层计算逻辑

  • 计算机CPU硬件设计,CPU是没有减法运算器,两个数相减,a-b=a+(-b) 其中a为正数。
  • 数学中,数可以无限大,也可以无限小,但计算机容量有限,表示不了。故每一种数值类型的都是在一个区间之内的,即:[c, d],其中c表示下限,d表示上限。

计算机的原码,反码,补码_位取反

下面代码:addend+addend2是溢出。计算结果是不正确

func main() {

//len计算字符串占用字节长度
var addend int8 = 100
var addend1 int8 = 3
var addend2 int8 = 32

fmt.Println("addend与addend1相加结果:", addend+addend1)
//addend+addend2 这两个相加是溢出
fmt.Println("addend与addend2相加结果:", addend+addend2)

}

运行结果:从下面结果来看,-124是错误的结果,为什么这样?因为golang中的int8是一个范围[-128~127]。在这个范围内的结果都是可以正确计算。超过这个范围就溢出,出现错误结果。

计算机的原码,反码,补码_反码_02

上面两个例子说明了计算机数值计算的范围重要性。是不可逾越的障碍。数值类型表示的数值有一定的范围,那么计算结果超出了这个范围,会发生什么呢?答案是:溢出。

现在我来解释100+32=-124的错误结果。

100与32在计算机的二进制如下图

计算机的原码,反码,补码_补码_03

计算机的原码,反码,补码_反码_04

100+32结果为1000 0100,这个是一个负数值。按照这个负值应该是-4,而不是-124。为什么出现这样结果?

那么我们就需要了解数值在计算机当中的存储方式。所有数值在计算机存储与表示都是以补码的方式出现。


原码、反码、补码之间的关系(以8位int8为例子)

原码:就是十进制转换为二进制的真实数据。例如正数10转换为二进制就是

0000 1010.

反码:反码规定正数的原码与反码相同。正数10的反码也是0000 1010。负数的反码是对正数逐位取反,0变1,1变0,符号位保持为1。例如-10的原码是1000 1010,那么它的反码是1111 0101

补码:补码规定正数的原码与补码相同。正数10的补码也是0000 1010。-10的补码在反码基础在加1。-10的反码是1111 0101,再加1.结果为1111 0110。

现在返回来看看上面100+32=-124的问题。在实际二进制相加过程中得到结果是1000 0100。由于溢出导致两个正数相加出现最高位为1,也就是负数。由于负数在计算机当中的表示与存储都是以补码方式存在。于是计算机会对1000 0100这个负数结果转换为补码形式得到是1111 1100(也就是测试结果的-124)

*正数的反码、补码与原码相同。反码、补码只针对负数进行转换。

为什么负数一定要用补码形式出现?

但是原码可以解决我们的负数运算问题吗?我们来试试:

// 计算: 5 + (-3)

0000 0101 // 5的原码
+ 1000 0011 // -3的原码
------------
1000 1000 // -8

可以看到:5 + (-3) = -8,这是错误的。所以用原码来表示负数,并进行运算是不行的。

我以10十进制的数来试解释一下补码:

9-3=6

9+7=16,这个是在数学计算结果,但是在10进制(假设计算机计算长度为0-9范围内),那么9+7=16的计算机计算中,会把溢出的1去掉,保留6.意味着9+7=6。这是计算机计算的正确结果。之前我们讲过计算机CPU是没有减法运算器。我们利用范围溢出方式进行减法算运,9-3=6和9+7=6,情况下,我们把-3在计算机中,用7来代替做加法运算。7就是-3的补码。关于计算机二进制中的负数补码转化方式,上面已经讲过。这个解释不一定科学,但是想不到有更加通俗的说法了。​

// 计算: 5 + (-3)

0000 0101 // 5的原码
+ 1111 1101 //-3的原码1000 0011,反码是1111 1100,再加1得补码1111 1101
------------
10000 0010 // 左边溢出1,超过值范围了。省略掉1.取值为0000 0010,这值为
正数2.假如为负数,需要再转过为补码保存结果。


//我们来看看这个例子 计算: 5 + (-6)

0000 0101 // 5的原码
+ 1111 1010 //-6的原码1000 0110,反码是1111 1001再加1得补码1111 1010
------------
1111 1111 // 这里没有溢出。但是是一个负数,取反1000 0000再加1得补码
1000 0001 这是补码值-1,也就是我们真正的数学科学运算结果。

看一张图:以4位的二进制有符号数为例,对应的取值范围是:[-8, 7],我们将其想象成一个圆。来感受一个环形范围溢出结果。

计算机的原码,反码,补码_补码_05

                                       网络图片



0000  0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7 // 上限
1000 -8 // 下限
1001 -7
1010 -6
1011 -5
1100 -4
1101 -3
1110 -2
1111 -1
0000 0 // 回到了0
...

下溢出,-8 + (-1) --> 1000 + 1111 = 0111,也就是上限7。



补充:移码

移码从何而来

知识点:

  • 大家知道浮点数的组成是:符号位+阶码+尾数。
  • 比较整数的方式:从高位到低位,逐位比较。
  • 负数的原码,补码,反码的机器数都比正数大。

要知道

  • 在cpu内,电路越简单越好。
  • 而浮点数的运算经常有比较接码大小这种操作。
  • 阶码只有整数,而通常定点整数的比较方式:数值位就是从左往右逐位比较。然而,无论阶码采用补码、原码都不行,因为无论补码还是原码,负数机器码都比正数大。
  • 为了复用电路,采取比较定点数的方式来比较解码,于是设计了一种编码,真值和机器码是正比关系,由此引出了移码。
如何设计移码

要真值和机器时正比,很简单,高中数学告诉我们,平移就好了。
那平移多少呢?
先看三个位能表示的真值:

111 、110、101、100、011、010、001、000

我们在这些数中找到中间值作为0,如100。
可以类推为 2^(n-1),或首位为1其他位为0的机器数 作为数字0.

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

那么n位定点整数,可知:​​x移 = x+2^(n-1) (-2^(n-1) <= x < 2^(n-1))​​ 由于 阶码不可能是小数,所以移码也不考虑小数。

移码的性质
  • 0是唯一的。
  • 符号位 1表示正,0表示负。
  • x表示范围:(-2^(n-1) <= x < 2^(n-1)
  • 移码和真值呈线性正比关系。

2^(n-1)就是符号位,也就是说,移码等于补码符号位取反,同理,补码符号位取反就等于移码。


计算机的原码,反码,补码_位取反_06


2^(n-1)就是符号位,也就是说,移码等于补码符号位取反,同理,补码符号位取反就等于移码。



参考文档:​​https://www.jianshu.com/p/411cab22a71e​



标签:反码,补码,负数,正数,原码,1000
From: https://blog.51cto.com/wyf1226/5919657

相关文章

  • 原码反码和补码的区别及用法笔记
    之前学习原码、反码、补码的时候就学的很懵,知道反码和补码怎么算的,但是不知道有什么用。今天看了几个视频,虽然有举例,但是自己换了个数就算不出来了。后来终于弄明白了。......
  • 补码4×4阵列乘法器设计
    视频讲解:https://www.bilibili.com/video/BV1ye4y1H7Ao/一、简述乘法运算在全部算数运算中大约占据三分之一,因此采用高速乘法部件,无论从速度上还是效率上,都十分必要。本......
  • PC_机器数_定点负数的原码_补码_反码在结构上的关系
    文章目录​​预备知识​​​​模2范畴内的取反​​​​证明二进制补码规律​​​​模k同余​​​​......
  • 原码、补码、反码的表示及计算
    今天简单总结了一下计算机的原码、补码、反码的表示,谨以此文缅怀教过我数字逻辑电路课程以及计算机组成原理课程的老师。一个数在计算机中的二进制表示形式我们称之为机器......
  • C - 原码、反码和补码
    原码计算机使用二进制编码存储数字.用第一个bit位表示符号,1表示负号,0表示正号.4个bit能够表示的数字:最小:1111→-7最大:0111→7但是原码不能进行加减......
  • golang获取补码,原码
    packagemainimport("encoding/binary""fmt""strconv")funcmain(){vara=[]byte{0x15,0x4B}varb=[]byte{0xE0,0x15}//fmt.Println(fmt.......
  • 源码补码与反码
    title:源码补码与反码comments:truedate:2022-11-2113:24:55tags:javacategory:计算机底层存储数据时使用的是二进制数字,但是计算机在存储一个数字时并不是直......
  • 原码,反码,补码
    源码源码就是该数的二进制数反码整数的反码是其本身,负整数的反码是0变1,1变0;补码整数的补码就是本身,负整数的补码是反码+1;......
  • object类(查看JDK原码,子类重写equals,hascode,toString,finalize)--JAVA
    一、equals==      publicclassequals{//把光标放在equals方法,直接输入ctrl+b--查看jdk源码publicstaticvoidmain(String[]args){Pers......
  • java 为什么要用补码_Java为什么使用补码进行计算的原因分析
    转自csdn---主要是前面的解释很通俗易懂,后面的没有细看,转过来以后查看方便。我们主要要解决的问题就是负数的表示,而众所周知,绝对值相等的两个正负数之和为0。假设我们有......