君子生非异也

导航

 

 go语言写了一段代码,为什么一个字节的有符号位与无符号位 计算后的结果不一样

一、计算机是如何存储数据的

在计算机中,存储一个数的时候,都是以补码的形式存储的
正数:正数的补码就等于它的原码

例如:16 
源码:‭0001 0000‬
补码:0001 0000‬   //这就是计算机最终存储的数据

负数:负数的补码是原码除符号位以外都取反,然后 + 1 得来的

例如: -16
源码:1 001 0000   // 计算机在处理负数时最高位代表符号位 所以 最高位的1为 负号 
反码:1 110 1111   //符号位不变 其他数据位取反
补码:1 110 1111+1=1 111 0000  //反码+1=补码  这就是计算机最终存储的数据

二、有符号与无符号

无符号:其最高位的1或0,和其它位一样,用来表示该数的大小。
一个字节(1111 1111)  1111 1111=1*2^7+1*2^6+1*2^5+1*2^4+1*2^3+1*2^2+1*2^1+1*2^0=255;所以无符号的一个字节表示的数据范围是0~255 共 256个;在Go语言中 uint8 范围(0~255)

例如:100 
无符号表示:01100100

有符号:最高数称为“符号位”。为1时,表示该数为负值,为0时表示为正值。一个字节(0111 1111) 最高位的0表示正号,0111 1111=+111 1111=+(1*2^6+1*2^5+1*2^4+1*2^3+1*2^2+1*2^1+1*2^0)=+127

例如:100 
有符号表示:01100100  //最高位0 表示 +号, 后七位才是具体数据位

对于有符号数的运算,一律采用补码进行;把减法运算转为加法运行 例如 5-3=5+(-3)

5  补码:0000 0101
-3 补码:1111 1101
相加:  10000 0010 // 由于我们是8位bit运算,我们丢弃溢出位1 最后 是 0000 0010=2

计算:5-7=5+(-7)=-2

5  补码:00000101
-7 补码:11111001
相加:   11111110 (由于符号位为1 所以改数为补码)
反码:   11111101  // 补码-1
源码:   10000010  // 反码除符号位以外取反

对于有符号位的0 

源码:1000 0000

反码:1111 1111

补码:1 0000 0000  //去掉溢出位1后 0000 0000

所以对于0 如果采用8bit位  我们规定就用0000 0000 表示,用1000 0000 表示-128

最后我们手动计算该代码

 

 1 源码:  0 000 0001

 1 补码:  0 000 0001

127源码:     0 111 1111

127补码:     0 111 1111

1补码+127补码=1000 0000  由于我们程序采用8bit位有符号类型,所以该结果是-128

三、原码与补码的相互转换

源码=》补码 (源码取反+1)
byte
b=-3;
源码:1000 0011
反码:1111 1100
补码:1111 1101
补码=》源码 (补码取反+1)
补码:1111 1101
反码:1000 0010
源码:1000 0011

 

四、计算机采用补码的意义

计算机通常用补码来表示有符号数,计算机的一个数据可以看作是有符号数,也可以看作无符号数的,也就是说计算机并不知道你存的是有符号数还是无符号数,而且所做的运算并不需要管你存的是什么数

使用补码的原因:简化计算机基本运算电路,使加减法都只需要用加法电路实现,用加法替代减法。
目的:为了简化计算机基本运算电路,使加减法都只需要通过加法电路实现,也就是让减去一个正数或加上一个负数这样的运算可以用加上一个正数来代替。于是改变负数存储的形式,存储成一种可以直接当成正数来相加的形式,这种形式就是补码。

 

posted on 2020-05-08 21:26  徐知语的笔记  阅读(2100)  评论(0编辑  收藏  举报