源码有符号补码的加减法以及大小比较

有符号补码的加减法以及大小比较

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=;

assign B_5=;

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

else if(C_5[4:4]&&C_5[4:0]

D_5

else

end

endmodule

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20191228A0IKP600?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券