良人从零开始的踩坑笔记:原码、补码、反码、移码

因为我上课没好好听

什么是机器数

机器数,是与真值相对的概念,指的是被计算机内部编码后表示的数。而真值指机器数真正的值,对应现实世界中带有正负号的数。

例如,负数在计算机中是以补码的形式存储的,-10用8位补码表示为11110110,说明机器数11110110B的真值是-10。

机器数一定是一个0/1序列,通常缩写成十六进制形式。

这里贴一个小工具,原码/反码/补码计算器
http://www.atoolbox.net/Tool.php?Id=952

原码表示法

一个数的原码表示由符号位Sign和数值位Magnitude构成,因此原码表示法也成为“符号-数值表示法”。

在原码表示法中,正数和负数的编码只有符号位上的不同。

原码编码规则如下:

  1. 当X为n位正数时,X n-1 = 0,X i = X i

  2. 当X为n位负数时,X n-1 = 1,X i = X i ( 0 ≤ i ≤ n-2)

这个X的上角标有一撇,但是特别小,无语,你电脑屏幕要是没擦干净绝对找不着

原码中0有两种表示形式:
3. [ +0 ] = 000…0
4. [ -0 ] = 100…0

原码与真值的对应关系直观、方便,与真值之间的转化简单,并且用原码实现乘除运算也比较简便。但是其0的表示不唯一,而且原码的加减运算规则复杂(见下文补码部分分析)。

现代计算机中不用原码来表示整数,只用定点原码小数来表示浮点数的尾数部分。
浮点数笔记:https://blog.csdn.net/Tea_Char/article/details/112297035

补码表示法

在计算机中,补码用来表示带符号整数。补码表示法也称“two’s complement”表示法,由符号位后跟上真值的模2n补码构成。

模运算

在模运算系统中,若A、B、M满足 A = B + k ⋅ M A=B+k · M A=B+kM其中k∈Z,则记为 A ≡ B ( m o d M ) A \equiv B(mod M) AB(modM)即A、B各除以M后的余数相同,故称B和A模M同余

钟表就是一个典型的模运算系统,其模数为12.
假定在钟表上只能顺时针方向拨动时针,如何用顺拨的方式实现将10点倒拨4格?拨动后钟表上是几点?
10 − 4 ≡ 10 + ( 12 − 4 ) ≡ 10 + 8 ≡ 6 ( m o d 12 ) 10-4 \equiv 10+(12-4) \equiv 10+8 \equiv 6(mod 12) 10410+(124)10+86(mod12)
因此可从10点顺时针拨8格来实现倒拨4格,最后是6点.

在上述题目中,8就是-4的补码

在计算机内部,存储、运算和传送部件都是有有限位的,因此计算机中机器数的位数也是有限的,两个n位数在运算过程中可能生成多于n位的结果,此时高位就会被舍弃。之后会有两种可能的结果:

  1. 剩下的低n位数不能表示正确的运算结果,即结果溢出 overflow

舍弃高位的操作相当于将一个多于n位的数除以2^n,保留其余数作为结果,也就是模运算操作。

  1. 剩下的低n位数能够表示正确的运算结果。

补码的定义

了解了上述原码和模运算的概念,我们可以引出补码的表示:正数的补码符号Sign为0,数值部分就是其本身;负数的补码等于与该负数绝对值之差。

  1. 当X为正数时, [ X ] 补 = X = M + X ( m o d M ) [X]_{补}=X=M+X(mod M) [X]=X=M+X(modM)
  2. 当X为负数时, [ X ] 补 = M − X ( m o d M ) = M + X ( m o d M ) [X]_{补}=M-X(mod M)=M+X(mod M) [X]=MX(modM)=M+X(modM)
    综合上诉两点,可以得到结论:
    对于任意一个数X, [ X ] 补 = M + X ( m o d M ) [X]_{补}=M+X(mod M) [X]=M+X(modM)

对于具有一位符号位,n-1位数值位的n位二进制整数X的补码来说,其补码的定义如下:
[ X ] 补 = 2 n + X ( − 2 n − 1 ≤ X < 2 n − 1 , m o d 2 n ) [X]_{补}=2^n+X(-2^{n-1} \leq X < 2^{n-1}, mod2^n) [X]=2n+X(2n1X<2n1,mod2n)

特殊数据的补码表示

  1. 补码位数为n时(其模为2n),求-2(n-1)的补码表示
    [ -2n-1 ] = 2n-2n-1 = 2n-1(mod 2n) = 10…0 (n-1个0)

  2. 补码位数为n+1位时(其模为2(n+1)),求-2(n-1)的补码表示
    [ -2n-1 ] = 2n+1-2n-1 = 2n+2n+1(mod 2n+1) = 110…0 (n-1个0)

  3. 设补码的位数为n,求-1的补码表示
    [ -1 ] = 2n-1 = 11…1 (n个1)

  4. 0的补码表示
    [ +0 ] = [ -0 ] = 2n ± 0 = 100…0(mod 2n) = 00…0(n个0)

从上述结果可以得知0的结果是唯一的,这带来了一些好处:

  1. 减少了+0与-0之间的转换问题
  2. 少占用一个编码表示,使补码比原码能多表示一个最小负数。比如我们用00…0表示0,那原本表示-0的补码100…0就用来表示最小负整数-2(n-1),这也是为什么整型int的范围是(-231,231-1)而不是(-231+1,231-1)

补码与原码之间的转换

已知补码的位数为8,求1101100和-1101100(真值)的补码表示
补码总位数为8,就有7位数值位和1位符号位.
[ 1101100 ] = 28+110 1100 = 1 0000 0000 +110 1100(mod 28) = 0110 1100
[ -1101100 ] = 28-110 1100 = 1 0000 0000-110 1100 = 1001 0100(冗长繁琐的计算过程,算不出也没事,下面有简单方法)

仿照上述的计算过程得到结论,负数的补码计算步骤为:
符号位取1,其余各数值位取反加1

因此,可以用过简单的方法来求一个数的补码,

已知[ X ] 求[ X ]

  1. 对于正数,符号位取0,其余各位同原码数值位中对应各位
  2. 对于负数,符号位取1,其余各位由数值位“各位取反,末位加1”得到

已知补码位数为8,用简便方法求X=-110 0011的补码表示
[ X ] = 1 110 0011
[ X ] = 1 001 1100 + 0 000 0001 = 1 001 1101

已知[ X ] 求[ X ]

  1. 对于符号位为0的数,原码同其补码.
  2. 对于符号位为1的数,原码符号位取1,数值位为其补码各数值位取反再加1.

已知补码位数为8,[ X ] =1 001 0100,求真值X
X=-(100 1011 +1 )=-100 1100

已知[ X ] 求[ -X ]

  1. 对于符号位为0的数,将[ X ] 的符号位取1,此时得到的是[ -X ] ,再将其各数值位取反再加1,就得到[ -X ]
  2. 对于符号位为1的数,对其补码表示再求补码,此时得到[ X ] ,再将[ X ] 符号位取1,此时得到[ -X ] ,再对其各数值位取反再加1,得到[ -X ]

总结可以得知,由[ X ] 求[ -X ] 的方法是:各位(包括符号位)取反,末位加1

已知[ X ] = 1 011 0100,求[ -X ]
[ -X ]=0 100 1011 + 0 000 0001 = 0 100 1100

注意最小负数取反后结果会溢出

已知[ X ] =1 000 0000,求[ -X ]
[ -X ]=0 111 1111 + 0 000 0001 = 1 000 0000(结果溢出)
8位整数补码1000 0000对应的是最小负数-27,对其取反后的值为27(即128),8位整数补码能表示的最大正数为27-1=127,而数128无法用8位补码表示,结果溢出。

反码表示法

负数的补码可通过符号位不变,其余各位取反,末位加1的方法得到,如果仅仅是各数值位取反而不加1,就可以得到负数的反码表示,因此负数反码的定义就是在相应的补码表示中再末位减1。

正数的反码是其本身

反码表示存在以下几点不足:

  1. 0的表示不唯一
  2. 表数范围比补码少一个最小负数
  3. 运算时必须考虑循环进位

因此反码在计算机中很少被使用,有时用作数码变换的中间表现形式或用于数据校验。

移码表示法

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值