• 【组成原理-数据】定点数的编码与运算


    0 必知的常用数

    • (128)10 = (7F)16 = 27
    • (256)10 = (FF)16 = 28
    • (1024)10 = (400)16 = 210
    • (32768)10 = (FFFF)16 = 215
    • (65536)10 = (10000)16 = 216
    • (2147483648)10 = 231
    • (4294967296)10 = 232

    1 定点数的编码

    1.1 编码的种类

    定点数编码有四种:

    • 原码:最高位表示真值的符号(1 表示负,0 表示正),其余各位表示真值的绝对值

    【注 1】设原码字长为 n(即有 n 位),则原码整数的表示范围为-(2n-1-1) ≤ x ≤ +(2n-1-1)

    【注 2】设原码字长为 n(即有 n 位),则原码小数的表示范围为-(1-2-(n-1)) ≤ x ≤ +(1-2-(n-1))

    【注 3】原码全 0,对应真值的最小值-(2n-1);原码全 1,对应真值的最大值+(2n-1-1)

    【注 4】0 的表示不唯一,分正负零(0,000,0000 和 1,000,0000)

    • 反码:正数的反码与原码一样,负数的反码其数值部分全部取反

    【注 1】设反码字长为 n(即有 n 位),则反码整数的表示范围为-(2n-1-1) ≤ x ≤ +(2n-1-1)

    【注 2】设反码字长为 n(即有 n 位),则反码小数的表示范围为-(1-2-(n-1)) ≤ x ≤ +(1-2-(n-1))

    【注 3】反码全 0,对应真值的最小值-(2n-1);反码全 1,对应真值的最大值+(2n-1-1)

    【注 4】0 的表示不唯一,分正负零(0,000,0000 和 1,111,1111)

    • 补码(带符号整数):正数的补码与反码一样,负数的补码等于反码加 1

    【注 1】设补码字长为 n(即有 n 位),则补码整数的表示范围为-(2n-1) ≤ x ≤ +(2n-1-1)

    【注 2】设补码字长为 n(即有 n 位),则补码小数的表示范围为-1 ≤ x ≤ +(1-2-n)

    【注 3】补码全 0,对应真值的最小值-(2n-1);补码全 1,对应真值的最大值+(2n-1-1)

    【注 4】0 的表示唯一(0,000,0000)

    【注 5】若补码的符号位相同,则数值位越大码值越大

    • 移码:真值基础上加上一个偏置常数(取 2n

    【注 1】设移码字长为 n(即有 n 位),则移码整数的表示范围为-(2n-1) ≤ x ≤ +(2n-1-1)

    【注 2】移码全 0,对应真值的最小值-2n;移码全 1,对应真值的最大值+(2n-1)

    【注 3】0 的表示唯一(1,000,0000)

    【注 4】移码保持了数据原有的大小顺序,移码大真值就大,移码小真值就小

    真值补码移码
    -1281000,00000000,0000
    -1271000,00010000,0001
    -1261000,00100000,0010
    -21111,11100111,1110
    -11111,11110111,1111
    00000,00001000,0000
    10000,00011000,0001
    20000,00101000,0010
    1250111,11011111,1101
    1260111,11101111,1110
    1270111,11111111,1111

    1.2 编码的转换

    • 正数:原码 --(不用变)–> 反码 --(不用变)–> 补码 --(符号位取反)–> 移码
    • 负数:原码 --(数值部分取反)–> 反码 --(直接加 1)–> 补码 --(符号位取反)–> 移码
    • 负数:原码 <–(从右往左找第一个“1”,“1”左边所有数值位取反)–> 补码
    • 补码转真值:最高的符号位有负值加权,例:[1,000,0011] = (-27+21+20)10 = (-125)10

    【例 1】(-100)10 的编码转换(默认 8 位字长)

    先化为十六进制,再转换为二进制:(100)10 = (64)16 = (0110,0100)2

    (1)原码:1,110,0100

    (2)反码:1,001,1011

    (3)补码:1,001,1100

    (4)移码:0,001,1100

    【例 2】(1,000,1101)2(默认 8 位字长),若为(1)原码;(2)反码;(3)补码;(4)移码,求对应真值?

    (1)原码:1,000,1101 --> 转换为十六进制:1(-),000(0),1101(13) --> 转换为十进制:(-13)10

    (2)反码:1,000,1101 --> 原码:1,111,0010 --> 转换为十六进制:1(-),111(7),0010(2) --> 转换为十进制:-(16*7+2)10 = (-114)10

    (3)补码:1,000,1101 --> 原码:1,111,0011 --> 转换为十六进制:1(-),111(7),0011(3) --> 转换为十进制:-(16*7+3)10 = (-115)10

    (4)移码:1,000,1101 --> 补码:0,000,1101 --> 转换为十六进制:0(+),000(0),1101(13) --> 转换为十进制:(+13)10

    1.3 C 语言的强制转换

    • 相同字长下,有符号数与无符号数的转换:保持位值不变,仅改变解释位值的方式
    • 长字长转换短字长:多余的高位直接丢弃,低位直接赋值
    • 短字长转换长字长:无符号情况下,扩展的高位部分用 0 填充;有符号情况下,扩展的高位部分用原数字符号填充
    • C 语言中赋值和判断也会出现强制类型转换,常见转换路径:char–>int–>long–>double 和 float–>double

    【例】16 位补码 0x8FA0 扩展为 32 位是 0xFFFF 8FA0。

    【补充】C 语言数据类型

    • char:字长 8 位(1 字节)
    • short:字长 16 位(2 字节)
    • int:字长 32 位(4 字节)
    • long:在 64 位机器中,字长 64 位(8 字节);在 32 位机器中,字长 32 位(4 字节)
    • float:字长 32 位(4 字节)
    • double:字长 64 位(8 字节)

    【注】8 bit = 1 Byte

    2 定点数的运算

    2.1 定点数的移位

    移位有三种:算术移位、逻辑移位、循环移位。

    2.1.1 算术移位(有符号数)

    【规则】

    • 算术移位过程中,符号位均保持不变
    • 正数的算术移位:原码、补码、反码算术移位,空位添 0
    • 负数原码的算术移位:用 0 占据空位

    负数的原码数值部分与真值相同,因此移位时符号位不变,其余空位添 0

    • 负数反码的算术移位:空位添 1

    负数的反码数值部分与负数的原码相反,因此移位时其余空位添相反的数,即为 1

    • 负数补码的算术移位:算术左移,低位空位添 0;算术右移,高位空位添 1

    负数的原码转补码,从右往左(从低到高)找到第一个“1”,这个“1”的左边(符号位除外)与原码相反,故空位添相反的数,即为 1;右边与原码相同,故空位仍添 0

    【例】负数补码的算术移位

    算术右移 1 位:1,110,0110 >> 1 = 1,111,0011

    算术右移 2 位:1,110,0110 >> 2 = 1,111,1001

    算术左移 1 位:1,110,0110 << 1 = 1,100,1100

    算术左移 2 位:1,110,0110 << 1 = 1,001,1000

    【注】补码正数的符号位为 0,左移最高位为 0 时,数据不会丢失;负数的符号位为 1,左移最高位为 1 时,数据不会丢失。

    2.1.2 逻辑移位(无符号数)

    【规则】

    • 逻辑移位将操作数视为无符号数
    • 逻辑左移:高位丢弃,低位添 0
    • 逻辑右移:低位丢弃,高位添 0

    2.1.3 循环移位

    【规则】

    • 不带进位的循环左移:高位溢出的数填充回低位,且高位溢出的数还要存入进位标志位 CF
    • 不带进位的循环右移:低位溢出的数填充回高位,且低位溢出的数还要存入进位标志位 CF
    • 带进位的循环左移:CF 的值填充回低位,且高位溢出的数还要存入进位标志位 CF
    • 带进位的循环右移:CF 的值填充回高位,且低位溢出的数还要存入进位标志位 CF
    • 循环移 n 位:相当于进行 n 次的循环移 1 位
    • 一般用途:将数据的低字节数据与高字节数据互换位置

    【例】一个 8 位寄存器内的数值为 0100,1011,进位标志位 CF=1,若(1)带进位循环左移一位;(2)带进位循环右移一位;(3)不带进位循环左移一位;(4)不带进位循环右移一位,结果是多少?

    【注】括号内的英文表示该数值位是从 CF、数值的高位(HIGH)还是数值的低位(LOW)移进来的。

    (1)带进位循环左移一位:100,1011,1 (CF);CF = 0 (HIGH)

    (2)带进位循环右移一位:1 (CF),0100,101;CF = 1 (LOW)

    (3)不带进位循环左移一位:100,1011,0 (HIGH);CF = 0 (HIGH)

    (4)不带进位循环右移一位:1 (LOW),0100,101;CF = 1 (LOW)

    2.2 定点数的加减法

    2.2.1 补码的加减法

    • 加法运算:补码直接相加
    • 减法运算:被减数-减数,减数转换为其负数的补码,转换为加法运算进行

    【例】A = 15,B = 28,计算 [A+B],[A-B]

    转换为二进制:A = (15)10 = (000,1111)2, B = (28)10 = (001,1100)2

    [A]= 0,000,1111, [B]= 0,001,1100

    [A]= 0,000,1111, [B]= 0,001,1100, [-B]= 1,110,0100

    [A+B] = 0,000,1111 + 0,001,1100 = 0,010,1011 = (+43)10

    [A-B] = 0,000,1111 + 1,110,0100 = 1,111,0011 = (-13)10

    2.2.2 溢出的判别

    发生溢出的情况:

    • 两个同号数相加,得到的结果却异号
    • 两个异号数相减,得到的结果与被减数异号

    【模 2 补码】有一个符号位的补码,即正常的补码。

    【模 4 补码(变形补码)】有两个符号位 S1S2 的补码,“00”表示正数,“11”表示负数,如:

    • -3:补码:1,101;变形补码:11,101
    • +3:补码:0,011;变形补码:00,011

    若两个符号位不同,“01”表示正溢出,“10”表示负溢出,最高位符号位表示真正的符号。

    实际情况下,存储每个变形补码仅需一个符号位,因为无论正数还是负数,两个符号位都是一样的,只有在运算时才会出现不一样的情况。

    • 溢出标志位 OF = 1 时,说明发生了溢出
    • OF = 最高位(即符号位)进位 ⊕ 次高位(即数值的最高位)进位 = S1⊕ S2

    即:最高位和次高位,一个有进位,另一个没有进位,若它们的异或值是 1,则结果就有溢出。

    补码加减溢出的相关例题

    【例 1】溢出的例子:0100,0000 + 0100,0000 = 1000,0000

    列竖式:

    运算溢出操作数
    .0100 0000
    (+)0100 0000
    .1000 0000
    • 加黑体数位为最高位,最高位没有产生进位
    • 斜体数位为次高位,次高位产生了进位
    • 因此结果溢出

    【例 2】溢出的例子:1000,0000 + 1000,0000 = 0000,0000

    列竖式:

    运算溢出操作数
    .1000 0000
    (+)1000 0000
    .10000 0000
    • 加黑体数位为最高位,最高位产生了进位
    • 斜体数位为次高位,次高位没有产生进位
    • 因此结果溢出

    【例 3】没有溢出的例子:1111,1111 + 0001,0000 = 0000,1111

    列竖式:

    运算溢出操作数
    .1111 1111
    (+)0001 0000
    .10000 1111
    • 加黑体数位为最高位,最高位产生了进位
    • 斜体数位为次高位,次高位产生了进位
    • 因此结果没有溢出

    2.3 定点数的乘除法

    2.3.1 原码的乘法

    设[X]=xs.x1x2…xn,[Y]=ys.y1y2…yn原码一位乘法 X*Y 的规则如下:

    • 符号位 = xs ⊕ ys
    • 部分积 = X * yi
    • 部分积初值为 0。从 Y 的最低位 yn 开始,部分积 = 部分积 + yn * |X|,然后将部分积和 Y 逻辑右移一位。该步骤重复 n 次,进行加法运算也为 n 次

    【例】x = -0.1101,y = 0.1011,进行原码一位乘法 x * y:

    操作通用寄存器(被乘数)ACC(高位部分积)MQ(低位部分积/乘数)MQ 丢失
    初始状态,乘数 y=00.101100.110100.00001011
    step1. 乘数最低位为 1,ACC 加 |X|00.110100.11011011
    step1. 部分积(和乘数)逻辑右移一位00.110100.011011011
    step2. 乘数最低位为 1,ACC 加 |X|00.110101.001111011
    step2. 部分积(和乘数)逻辑右移一位00.110100.1001111011
    step3. 乘数最低位为 0,ACC 加 000.110100.1001111011
    step3. 部分积(和乘数)逻辑右移一位00.110100.01001111011
    step4. 乘数最低位为 1,ACC 加 |X|00.110101.00011111011
    step4. 部分积(和乘数)逻辑右移一位00.110100.100011111011

    符号位 = 1 ⊕ 0 = 1

    x * y = -0.10001111

    2.3.2 补码的乘法

    设[X]=xs.x1x2…xn,[Y]=ys.y1y2…yn补码一位乘法 X*Y 的规则如下:

    • 部分积、被乘数采用双符号位补码;乘数采用单符号位补码
    • 符号位参与运算
    • Y 增设辅助位 yn+1 = 0
    • 部分积初值为 0。从 Y 的最低位 yn 开始:当 (ynyn+1) = (01)部分积 = 部分积 + [X];当 (ynyn+1) = (10)部分积 = 部分积 + [-X];其他情况加 0。然后将部分积和 Y 算术右移一位
    • 以上步骤重复 n+1 次,但最后一次不用移位。所以需要加法运算 n+1 次,移位 n 次

    【例】x = -0.1101,y = 0.1011,进行补码一位乘法 x * y:

    [x] = 11.0011,[-x] = 00.1101,[y] = 0.1011

    操作通用寄存器(被乘数)ACC(高位部分积)MQ(低位部分积/乘数)MQ(辅助位)MQ 丢失
    初始状态,乘数 y=00.101111.0011 [负数: 00.1101]00.0000010110
    step1. 乘数最低位和辅助位为 10,ACC 加 [-X]11.0011 [负数: 00.1101]00.1101010110
    step1. 部分积(和乘数)算术右移一位11.0011 [负数: 00.1101]00.01101010110
    step2. 乘数最低位和辅助位为 11,ACC 加 011.0011 [负数: 00.1101]00.01101010110
    step2. 部分积(和乘数)算术右移一位11.0011 [负数: 00.1101]00.001101010110
    step3. 乘数最低位和辅助位为 01,ACC 加 [+X]11.0011 [负数: 00.1101]11.011001010110
    step3. 部分积(和乘数)算术右移一位11.0011 [负数: 00.1101]11.1011001010110
    step4. 乘数最低位和辅助位为 10,ACC 加 [-X]11.0011 [负数: 00.1101]00.1000001010110
    step4. 部分积(和乘数)算术右移一位11.0011 [负数: 00.1101]00.01000001010110
    step5. 乘数最低位和辅助位为 01,ACC 加 [+X]11.0011 [负数: 00.1101]11.01110001010110

    注:最后的 MQ = 00010 的最低位为原符号位,不用

    [x * y] = 11.01110001,x * y = -0.10001111

    2.3.3 原码的除法

    设[X]=xs.x1x2…xn,[Y]=ys.y1y2…yn加减交替法(不恢复余数法)求 X/Y 的规则如下:

    • 首先,|被除数| - |除数| = 新余数
    • 若新余数为负:商 0,余数左移,然后加|除数|,得到新余数
    • 若新余数为正:商 1,余数左移,然后减|除数|,得到新余数
    • 以上两个步骤重复 n+1 次,最后一次若余数为负,商 0,需加上|除数|得到正确余数
    • 总的加法运算为 n+1 或 n+2 次,移位总次数为 n 次

    【例】x = 0.1011,y = 0.1101,利用加减交替法求 x / y:

    |x| = 0.1011,|y| = 0.1101,[|y|] = 0.1101,[-|y|] = 1.0011

    操作通用寄存器(除数)MQ(被除数/部分余数)MQ(商)
    初始状态:|x|=0.1011,|y|=0.11010.1101 [负数: 1.0011]0.10110.0000
    step0. |x|-|y|0.1101 [负数: 1.0011]1.11100.0000
    step1. 部分余数为负,商 00.1101 [负数: 1.0011]1.11100.0000
    step1. 部分余数和商左移一位0.1101 [负数: 1.0011]1.11000.0000
    step1. +|y|0.1101 [负数: 1.0011]0.10010.0000
    step2. 部分余数为正,商 10.1101 [负数: 1.0011]0.10010.0001
    step2. 部分余数和商左移一位0.1101 [负数: 1.0011]1.00100.0010
    step2. -|y|0.1101 [负数: 1.0011]0.01010.0010
    step3. 部分余数为正,商 10.1101 [负数: 1.0011]0.01010.0011
    step3. 部分余数和商左移一位0.1101 [负数: 1.0011]0.10100.0110
    step3. -|y|0.1101 [负数: 1.0011]1.11010.0110
    step4. 部分余数为负,商 00.1101 [负数: 1.0011]1.11010.0110
    step4. 部分余数和商左移一位0.1101 [负数: 1.0011]1.10100.1100
    step4. +|y|0.1101 [负数: 1.0011]0.01110.1100
    step5. 部分余数为正,商 10.1101 [负数: 1.0011]0.01110.1101
    step6. 部分余数为正,不需要+|y|0.1101 [负数: 1.0011]0.01110.1101

    x / y = +0.1101,余数 = 0.0111 * 2-4

    2.3.4 补码的除法

    设[X]=xs.x1x2…xn,[Y]=ys.y1y2…yn加减交替法求 X/Y 的规则如下:

    • 部分余数、被除数、除数采用双符号位补码
    • 符号位参与运算
    • 首先,若 X、Y 同号,则余数 = X - Y;若 X、Y 异号,则余数 = X + Y
    • 若余数与 Y 同号,则商 1,余数左移,减去 Y
    • 若余数与 Y 异号,则商 0,余数左移,加上 Y
    • 重复以上两个步骤 n 次,商末位恒置 1

    【例】x = 0.1000,y = -0.1011,利用加减交替法求 x / y:

    [x] = 00.1000,[x] = 00.1000

    [y] = 11.1011,[y] = 11.0101,[-y] = 00.1011

    操作通用寄存器(除数)MQ(被除数/部分余数)MQ(商)
    初始状态:x=00.1000,y=11.010111.0101 [负数: 00.1011]00.10000.0000
    step0. x、y 异号,+y11.0101 [负数: 00.1011]11.11010.0000
    step1. 部分余数与 y 同号,商 111.0101 [负数: 00.1011]11.11010.0001
    step1. 部分余数和商左移一位11.0101 [负数: 00.1011]11.10100.0010
    step1. 部分余数-y11.0101 [负数: 00.1011]00.01010.0010
    step2. 部分余数与 y 异号,商 011.0101 [负数: 00.1011]00.01010.0010
    step2. 部分余数和商左移一位11.0101 [负数: 00.1011]00.10100.0100
    step2. 部分余数+y11.0101 [负数: 00.1011]11.11110.0100
    step3. 部分余数与 y 同号,商 111.0101 [负数: 00.1011]11.11110.0101
    step3. 部分余数和商左移一位11.0101 [负数: 00.1011]11.11100.1010
    step3. 部分余数-y11.0101 [负数: 00.1011]00.10010.1010
    step4. 部分余数与 y 异号,商 011.0101 [负数: 00.1011]00.10010.1010
    step4. 部分余数和商左移一位11.0101 [负数: 00.1011]01.00101.0100
    step4. 部分余数+y(商末位恒置 1)11.0101 [负数: 00.1011]00.01111.0101

    [x/y] = 1.0101,余数 = 0.0111 * 2-4

    —EOF—

  • 相关阅读:
    leetcode 1235
    linux篇【9】:进程间通信——<前序>
    C语言初阶—分支和循环语句1
    数据湖技术之 Hudi 集成 Flink
    centos中安装的goland配置sdk报错:所选的目录不是Go SDK的有效主路经
    CPU状态信息us,sy,ni,id,wa,hi,si,st含义
    Shiro学习(3)shiroConfig配置类
    关于共识算法
    【物联网开发】机智云App远程电机PWM调速
    对比学习15篇顶会论文及代码合集,2023最新
  • 原文地址:https://blog.csdn.net/baidu_39514357/article/details/126312740