有符号补码的加减法以及大小比较
1.瞎扯简述
最近在写用fpga进行解缠绕的IP,解缠绕做的事情并不算复杂,就是比较后进行加减而已。但是解缠绕前面这个IP是用的xilinx的Cordic内核,算出来的是补码,过去只做了一些什么简单的取反加一的简单原码补码转换,所以在这里加减就懵了,没有真正碰过补码运算,正好借此机会好好整明白补码的操作。
2.原码与补码的转换
什么是有符号原码,补码怎么转换的,百度即可,耐心看5分钟就整明白了。
3.表示范围
对于8位有符号数的来讲,原码很容易理解,表示范围是-127-127。但是计算机不采用原码存储,采用补码,+0和-0的补码都是0000 0000,当时最令我疑问的1000 0000为什么表示-128,对1000 0000的符号位不变,数值位取反加一,就变成了1 0000 0000,就算我人为规定了1 0000 0000这个就是-128的补码,但是计算机怎么识别呢,毕竟这是个9位数据。
其实,还是自己低估了补码的意义。
我们就来看看把1000 0000作为-128的补码能不能参与运算,为了方便大家验证,我们下面不以
8位有符号数来验证,以4位有符号数验证。4位有符号数是从-8-7,1000就是-8的补码。
举个例子,-8+6=1000+0110=1110 1110的原码是1010=-2 正确 ,1000作为-8的补码参与运算是完全正确的,我所不理解的这个补码转换成原码后变成9位后计算机为什么还能认识,是以人的角度思考的,对于加法器减法器来讲,这个是完全没问题的。
4.补码加减法
记住[X±Y]补=[X]补±[Y]补
用4位有符号数(补码)验证一下
1.-3+2=1101+0010=1111 1111的原码是1001=-1
2.-3-1=1101-0001=1100 1100的原码是1100=-4
3.-3+7=1101+0111=0100 0100的原码是0100=4
验证无误,考虑到上一节的内容来,所以使用补码在范围内进行加减是完全没有问题的。
5.有符号数加减后溢出的处理办法
在我的处理过程中,使用的是16位有符号数,但是是由1位符号位+2位整数位+13位分数位组成的,所以不会超过±4,但是在使用中我需要进行加减2pi的操作,这就超出了位数,应该怎么处理呢,实际上用补码非常方便,只需要扩增符号位即可,下面来看看具体如何操作。
还是以4位有符号数为例,如果要进行-8-2的操作,这势必超出了范围,做法就是进行位数扩增
-8-2=1000-0010=11000-00010=10110 10110的原码是11010=-10 加粗的数字就是讲4位有符号数补成5位有符号数,最高位补符号位。4位有符号数下1000是-8的补码,补符号位变成5位有符号数后,11000仍然是-8的补码,把4位扩成5位没有任何影响,如果前一个IP比如都是4位的补码,后面一个IP是8位的补码,完全可以将4位加了4个符号位变成8位有符号数,
举个例子,-8-4=1111 1000-0000 0100=1111 0100 其原码是1000 1100=-12,验证无误。
6.补码转成原码
上面虽然写了用补码完全OK,但是有时候就是想转成原码怎么办。我过去一直用的是符号位不变,数值位取反加1。但是,其他的没有问题,最小值是个麻烦事,例如对于4位有符号数(补码),-8=1000 如果按照取反加1,就变成了0000,那应该如何转成原码呢?方法和上一节相同,对于4位有符号数,如果我已知数据中不可能与-8,那没事,可以不管,如果不知道,或者说有可能有最小值-8出现。还是增加一位符号位,-8=1000—>11000 11000是补码,最高位不变,后四位按位取反后加1,有11000(原码)=-8。
过去我颇为不理解为什么Xilinx的IP核中,如果设置位宽为14,由于FPGA的内部结构,接口往往是8的倍数,所以是16,这种情况下会在高位自动补足两位符号位 ,但是补足符号位仅限于补码,原码能通过补足符号位来运算吗?当然不能,因为补足符号位,例如4位有符号数,如果是复数前面补符号位,数值就变了,自然不能用来计算了。
7.verilog大小比较
对于原码的大小比较,比较简单,比一下符号位,再比较一下数值位就OK了
对于我的问题,需要进行补码的大小比较。
假设输入的是4位有符号数补码,A和B,对A-B进行判断,差值大于7就-8后再输出,小于-8就+7后再输出。这样输出的数据也可以用4位有符号数来表示,下面贴上verilog代码
module bijiao
(input [3:0] A,
input [3:0] B,
output [3:0] C
);wire [4:0] A_5;//扩展成5位
wire [4:0] B_5;
wire [4:0] C_5;
wire [4:0] D_5;assign A_5={A[3:3],A};
assign B_5={B[3:3],B};
assign C_5=A-B;
assign C=D_5[3:0];allways@(C_5)
begin
if(!C_5[4:4]&&C_5[4:0]>5’b00111)//补码判断大于+7,保证符号位为0,整体>7的补码即可
D_5<=C_5-5’b01000;
else if(C_5[4:4]&&C_5[4:0]<5’b11000)//补码判断小于-8,保证符号位为1,整体<-8的补码即可
D_5<=C_5+5’b00111)
else
D_5<=C_5;
endendmodule
来源:CSDN
作者:烧了佛像来取暖
链接:https://blog.csdn.net/jhrcshizhang/article/details/103686718