时间:2026-02-05 来源:FPGA_UCY 关于我们 0
小数定点化
Verilog在实现加法和乘法的时候结果位宽应该怎么设定才不会溢出
定点数的加法计算
我们假设都是无符号数,格式为8bit整数,8bit小数
然后计算1.35+2.67这个结果
首先要将这两个数转换为定点数,这里我们就直接使用二进制的在线网站进行转换了
那么获取到这两个数的二进制分别为
1.35 1.01011010
2.67 10.1010110
这两个数字肯定是有误差的,然后完成这两个数的加法,代码和整数加法是一样的,只需要我们记住小数点的位置即可
wire[15:0] a;
wire[15:0] b;
wire[15:0] c;
assigna = 16'b0000_0001_0101_1010;
assignb = 16'b0000_0010_1010_1100;
assignc = a + b;
![]()
定点数的乘法
仍然以上述数字为例
wire[15:0] a;
wire[15:0] b;
wire[31:0] c;
assigna = 16'b0000_0001_0101_1010;
assignb = 16'b0000_0010_1010_1100;
assignc = a * b;
![]()
这里我们将c的位宽由16bit扩展到了32bit,这是因为a是8bit的小数位,b也是8bit的小数位,那么a和b相乘的话,小数位就有16bit了,如果我们还以16bit来保存结果的话就会出现严重的溢出,因为16bit只够保留小数位,整数位会全部溢出。
饱和截断
我们肯定不可能仍由位宽进行扩展,不然对使用的资源来说将是灾难性的,那么我们就可以进行对小数位进行截断,比如上述计算中小数位16bit,那么我们可以将结果重新截断为8bit,最简单的办法就是将低8bit的小数位给丢掉
wire[15:0] a;
wire[15:0] b;
wire[31:0] c;
wire[23:0] d;
assigna = 16'b0000_0001_0101_1010;
assignb = 16'b0000_0010_1010_1100;
assignc = a * b;
assignd = c[31:8];
![]()
可以看到小数部分就被截断了低bit,数字也变小了。
这里只对小数做了处理,所以d只缩减到了24bit,并没有缩减到16bit,也可以对整数位进行饱和处理来进一步缩减位宽,这个就取决于实际需要了
当然还有更复杂的舍入方法,比如四舍五入,向偶数舍入,向奇数舍入,向0舍入等。
混合计算
比如先计算1.35*2.67,然后后面经过一些其他步骤之后需要加上1.25那么代码应该怎么写
wire[15:0] a;
wire[15:0] b;
wire[15:0] c;
wire[31:0] d;
wire[31:0] e;
assigna = 16'b0000_0001_0101_1010;
assignb = 16'b0000_0010_1010_1100;
assignc = 16'b0000_0001_0100_0000;
assignd = a * b;
assigne = d + {c, 8'd0};
可以看到在进行加法的时候我们在c后面补了8个零,这是因为a*b得到的结果d已经变成16bit的小数位了,而c还是8bit小数位,所以我们需要在后面补8个零从而让其小数点对齐保证计算正确。
![]()
所以在进行定点数的计算的时候最重要的是时刻记住小数点的位置。