官方论坛
官方淘宝
官方博客
微信公众号
点击联系吴工 点击联系周老师

算术运算符补码由来

发布时间:2023-04-13   作者:admin 浏览量:


需要看对应的视频,请点击视频编号:001100000060

1、在FPGA甚至计算机系统中,所有数据的保存方式都是补码形式的,

2、本视频主要讲解正数和负数的补码计算以及在数据电路中的处理方式。
3、这是ALTERA和VIVADO视频



补码的由来


FPGA实现各种算法的时候,首要的就是保证运算结果的正确性,否则一切毫无意义。

在分析加加法运算符和减法运算符的时候可以发现保存结果的信号位宽是否合理对正确性与否有很大的影响。

例如下面的加法运算:
1.3- 5加法运算结果
  
运算

十进制

结果
运算
十进制

结果
1位加法运算,1位保存结果,不保存进位
1’b0  + 1’b0 = 1’b0
0
1’b1  + 1’b0 = 1’b1
1
1’b0  + 1’b1 = 1’b1
1
1’b1  + 1’b1 = 1’b0
0
1位加法运算,2位保存结果,保存进位
1’b0  + 1’b0 = 2’b0
0
1’b1  + 1’b0 = 2’b01
1
1’b0  + 1’b1 = 2’b1
1
1’b1  + 1’b1 = 2’b10
2
1位数 + 2位数,2位保存结果,不保存进位
1’b0  + 2’b00 = 2’b00
0
1’b1  + 2’b00 = 2’b01
1
1’b0  + 2’b01 = 2’b01
1
1’b1  + 2’b01 = 2’b10
2
1’b0  + 2’b10 = 2’b10
2
1’b1  + 2’b10 = 2’b11
3
1’b0  + 2’b11 = 2’b11
3
1’b1  + 2’b11 = 2’b00
0
1位数 + 2位数,3位保存结果,保存进位
1’b0  + 2’b00 = 3’b000
0
1’b1  + 2’b00 = 3’b001
1
1’b0  + 2’b01 = 3’b001
1
1’b1  + 2’b01 = 3’b010
2
1’b0  + 2’b10 = 3’b010
2
1’b1  + 2’b10 = 3’b011
3
1’b0  + 2’b11 = 3’b011
3
1’b1  + 2’b11 = 3’b100
4




从上表可以发现,如果不保留进位,当加法出现进位的时候计算的结果是不正确的,

只有保留了进位计算的结果才是正确的。由此可以得出一个结论:使用加法的时候,为了保证结果的正确性,

必须保存进位,也就是结果要扩展位宽。

例如两个8位的数相加,则结果要扩展一位,将位宽设定为9位。


1
  
2
  
3
  
4
  
5
wire[7:0]  a,b;
  
wire[7:0]  c  ;
  
wire[8:0]  d  ;
  
assign c = a  + b; //结果不正确
  
assign d = a  + b; //结果正确


接着再来分析一下减法运算,如下表所示例子:


1.3- 6减法运算结果


  
运算
  
十进制
  
结果
运算
十进制
  
结果
2位减法运算,2位保存结果
2’b00  - 2’b00 = 2’b00
0
2’b10  - 2’b00 = 2’b10
2
2’b00  - 2’b01 = 2’b11
3
2’b10  - 2’b01 = 2’b01
1
2’b00  - 2’b10 = 2’b10
2
2’b10  - 2’b10 = 2’b00
0
2’b00  - 2’b11 = 2’b01
1
2’b10  - 2’b11 = 2’b11
3
2’b01  - 2’b00 = 2’b01
1
2’b11  - 2’b00 = 2’b11
3
2’b01  - 2’b01 = 2’b00
0
2’b11  - 2’b01 = 2’b10
2
2’b01  - 2’b10 = 2’b11
3
2’b11  - 2’b10 = 2’b01
1
2’b01  - 2’b11 = 2’b10
2
2’b11  - 2’b11 = 2’b00
0


注意表中和2’b00-2’b01,结果是2’b11,对应的十进制值为3,但期望的结果是“-1”。

同样的道理,2’b01 - 2’b11,结果是2’b10,对应的十进制值为2,而期望的结果是“-2”,

所以上面的结果是不正确的。

当期望结果中有正负之分时,可以通过增加一个符号位来区别结果的正负。业内约定的表示方法为,

最高位为0时表示正数,最高位值为1表示负数。符号位之后的数值用低2位表示,结果如下表:



1.3- 7增加符号位的减法运算结果


  
运算
  
十进制
  
结果
运算
十进制
  
结果
2位减法运算,3位保存结果,其中最高位是符号位
2’b00  - 2’b00 = 3’b000
+0
2’b10  - 2’b00 = 3’b010
+2
2’b00  - 2’b01 = 3’b111
-3
2’b10  - 2’b01 = 3’b001
+1
2’b00  - 2’b10 = 3’b110
-2
2’b10  - 2’b10 = 3’b000
+0
2’b00  - 2’b11 = 3’b101
-1
2’b10  - 2’b11 = 3’b111
-3
2’b01  - 2’b00 = 3’b001
+1
2’b11  - 2’b00 = 3’b011
+3
2’b01  - 2’b01 = 3’b000
+0
2’b11  - 2’b01 = 3’b010
+2
2’b01  - 2’b10 = 3’b111
-3
2’b11  - 2’b10 = 3’b001
+1
2’b01  - 2’b11 = 3’b110
-2
2’b11  - 2’b11 = 3’b000
+0


从上表中可以看出增加符号位后还是会存在部分运算结果与预期不符合的问题。

例如表中的2’b00-2’b01,结果是3’b111,对应的十进制值为-3,但期望的结果是“-1”。

所以上面的结果仍然是不正确的。


现在,重新对二进制数“000~111”进行如下转换:
a.       正数:保持不变
b.      负数:符号位保持不变,数值取反加1。

也就是说,如果是正数“+1”,之前是用“001”表示,现在仍然是用“001”表示。

如果是负数“-1”,之前是用“101”表示,现在则是用“111”表示。负数“-3”,

之前是用“111”表示,现在则是用“101”表示。这种表示方式就是补码表示方式。

改为用补码来表示后,再来分析下结果:


1.3- 8补码表示减法运算结果


  
运算
  
补码
  
结果
运算
补码
  
结果
2位减法运算,3位保存结果,其中最高位是符号位
2’b00  - 2’b00 = 3’b000
+0
2’b10  - 2’b00 = 3’b010
+2
2’b00  - 2’b01 = 3’b111
-1
2’b10  - 2’b01 = 3’b001
+1
2’b00  - 2’b10 = 3’b110
-2
2’b10  - 2’b10 = 3’b000
+0
2’b00  - 2’b11 = 3’b101
-3
2’b10  - 2’b11 = 3’b111
-1
2’b01  - 2’b00 = 3’b001
+1
2’b11  - 2’b00 = 3’b011
+3
2’b01  - 2’b01 = 3’b000
+0
2’b11  - 2’b01 = 3’b010
+2
2’b01  - 2’b10 = 3’b111
-1
2’b11  - 2’b10 = 3’b001
+1
2’b01  - 2’b11 = 3’b110
-2
2’b11  - 2’b11 = 3’b000
+0


可以看到上表的结果全部都是正确的,与预期全部一致。这一过程虽然完全没有对代码进行任何改变,

但通过更改数据的定义就实现了正确的结果。


在之前的讨论中,加数、被加数、减数和被减数的运算过程都没有使用有符号数。

现在使用有符号数的补码重新对其进行表示。

假设加数、被加数、减数和被减数都是2位(范围为-2~1),考虑到进位和借位原因,

结果用3位来表示(范围为-4~3)。因为结果位宽变为3位,所以减数和被减数都扩展成用3位表示,

列出下表:


1.3- 9补码表示运算结果


  
十进制运算
  
二进制补码表示
补码
  
结果
0-0
3’b000  - 3’b000 = 3’b000
+0
0-1
3’b000  - 3’b001 = 3’b111
-1
0--2
3’b000  - 3’b110 = 3’b010
+2
0--1
3’b000-  3’b111 = 3’b001
+1
1-0
3’b001  - 3’b000 = 3’b001
+1
1-1
3’b001  - 3’b001 = 3’b000
+0
1--2
3’b001  - 3’b110 = 3’b011
+3
1--1
3’b001  - 3’b111 = 3’b010
+2
-2-0
3’b110  - 3’b000 = 3’b110
-2
-2-1
3’b110  - 3’b001 = 3’b101
-3
-2--2
3’b110  - 3’b110 = 3’b000
+0
-2--1
3’b110  - 3’b111 = 3’b111
-1
-1-0
3’b111  - 3’b000 = 3’b111
-1
-1-1
3’b111  - 3’b001 = 3’b110
-2
-1--2
3’b111  - 3’b110 = 3’b001
+1
-1--1
3’b111  - 3’b111 = 3’b000
+0
0+0
3’b000  + 3’b000 = 3’b000
+0
0+1
3’b000  + 3’b001 = 3’b001
+1
0+-2
3’b000  + 3’b110 = 3’b110
-2
0+-1
3’b000  + 3’b111 = 3’b111
-1
1+0
3’b001 + 3’b000 = 3’b001
+1
1+1
3’b001  + 3’b001 = 3’b010
+2
1+-2
3’b001  + 3’b110 = 3’b111
-1
1+-1
3’b001  + 3’b111 = 3’b000
+0
-2+0
3’b110  + 3’b000 = 3’b110
-2
-2+1
3’b110  + 3’b001 = 3’b111
-1
-2+-2
3’b110  + 3’b110 = 3’b100
-4
-2+-1
3’b110  + 3’b111 = 3’b101
-3
-1+0
3’b111  + 3’b000 = 3’b111
-1
-1+1
3’b111  + 3’b001 = 3’b000
+0
-1+-2
3’b111  + 3’b110 = 3’b101
-3
-1+-1
3’b111  + 3’b111 = 3’b110
-2


总结运算步骤如下:
1. 根据“人的常识”,预计结果的最大最小值,从而确定结果的信号位宽。
2. 将加数、减数等数据,位宽扩展成结果位宽一致。
3. 按二进制加减法进行计算。


通过以上方式,得到的就是补码的结果。事实上,在FPGA甚至计算机系统中,

所有数据的保存的方式都是补码的形式。如果读者想要了解更多关于补码的内容可以参阅相关资料。

相关视频:https://www.bilibili.com/video/BV1yf4y1R7gH?p=14


相关视频:https://www.bilibili.com/video/BV1yf4y1R7gH?p=14



下一篇:逻辑运算符
   拓展阅读