问题:对一个有符号数signed A[15:0]进行截位(除以256)处理,结果要求四舍五入。
方法一:
assign OUT = (A[15:0] + 8'd128) >> 8;
方法二:
assign OUT = A[15:8] + {7'b0, A[7]};
方法三:
always @(*)
begin
if(A[15]) // negative
OUT = (A[15:0] + 127) >> 8;
else // positive
OUT = (A[15:0] + 128) >> 8;
end
方法一和方法二是等效的,逻辑简单,一般情况下也没错。但是有一种特殊情况,如果A是负数且刚好是256的0.5倍,则小数的0.5会被误舍掉。
比如,A = 1111_1110_1000_0000 (-384),A/256 = -1.5,本来应该四舍五入成-2,但是按照前两种方法,结果变成了:
(1111_1110_1000_0000 + 0000_0000_1000_0000)>>8 = (1111_1111_0000_0000)>>8
由此得到OUT = 1111_1111 = -1 (错误)
精确的做法应该是:
判断A[15] = 1,是负数,所以应该采用:
(1111_1110_1000_0000 + 0000_0000_0111_1111)>>8 = (1111_1110_1111_1111)>>8
由此得到OUT = 1111_1110 = -2 (正确)
这就是方法三。