注册 登录
ET创芯网论坛(EETOP) 返回首页

hover99的个人空间 http://blog.eetop.cn/?253668 [收藏] [复制] [分享] [RSS]

日志

实现有符号定点数数的四舍五入截断

已有 421 次阅读2018-11-3 20:04 |系统分类:芯片设计

设计数学运算逻辑的时候,我们经常会遇到对定点数的截断,我们知道对于无符号数进行四舍五入截断N,需要先加上2**(N-1)再右移N位。例如,把a为U3.4(这里U代表无符号数,3代表整数位有3位,4代表小数位有4位,总位宽位3+4=7位,类似S3.4代表整数部分有3位小数部分有4位的有符号数,总位宽为1+3+4=8位)截断为U3.0。
assign b[2:0] = (a + 7'd8) >> 4;
但是对于有符号数的四舍五入截断,目前我还没发现有资料进行讨论。以前在我在某家欧美公司工作的时候,他们通常不区分有符号数和无符号数,统一按无符号数的四舍五入方法来截断。这种方法是否正确呢?我写了一段测试代码来验证:
module test;
  reg signed [11:0] data;
  reg signed [7:0]  ref_data;
  reg signed [11:0] temp;
  real r;
  
  initial begin
    repeat (1000) begin
      data = $urandom_range(0, 2047);
      data = data - 1024;
      r = $itor(data);
      r = r / 16;
      ref_data = r;
      temp = data + 8;
      if (ref_data != temp[11:4]) begin
        $display("%0d / 16 = %0d, actual is %0d", data, ref_data, $signed(temp[11:4]));
      end
    end
  end
endmodule
运行这段代码你会发现,对于有些负数,采用无符号数的四舍五入方法计算结果会比标准大1。仔细研究错误全部出在对五的取舍上。例如-856/16=-53.5,按标准方法结果应该是-54,但是如果+0.5之后,恰好变成了-53。这是为什么呢?其实我们仔细研究二的补码就会知道,用补码表示数的范围是不对称的,比如10位有符号整数表示的范围是[-1024,1023],所以对于负数需要再减去一个最低位。记对于负数在右移N位之前需要加的数为2**(N-1)-1。正负数统一起来表示为:
rand(x, n) = (x + 2**(n-1) - x[$bits(x)-1]) >>> n
特别的,当N=1时,
rand(x, 1) = (x + (!x[bits(x)-1])) >>> 1 
测试代码如下:
module test;
  reg signed [11:0] data;
  reg signed [7:0]  ref_data;
  reg signed [11:0] temp;
  real r;
  real ref_sum;
  real act_sum;
  
  initial begin
    repeat (1000) begin
      data = $urandom_range(0, 2047);
      data = data - 1024;
      r = $itor(data);
      r = r / 16;
      ref_data = r;
      temp = data + 8 - data[11];
      if (ref_data != temp[11:4]) begin
        $display("%0d / 16 = %0d, actual is %0d", data, ref_data, $signed(temp[11:4]));
      end
    end
  end
endmodule

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|ET创芯网 ( 京ICP备:10050787号 京公网安备:110105001212 )

GMT+8, 2019-4-21 08:31 , Processed in 0.029108 second(s), 8 queries , Redis On.

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

返回顶部