我正在硬件上设计一个单精度浮点乘法器,并且使用python来验证我的设计。这是单精度浮点格式。
相乘的结果是
在执行两个尾数的乘法运算后,在四舍五入数字时遇到问题。您知道尾数是24位(23和1个隐藏位),将两个24位相乘将得到48位。尾数字段只能包含23位,因此我尝试将其截断,如下所示:
example of mantissa truncating。但是,与python float32乘法相比,结果似乎不正确。
所以我在这里问python如何处理尾数乘法。谢谢。
答案 0 :(得分:2)
Python(和许多其他语言)使用IEEE754默认舍入模式,称为“舍入到最接近的关系到偶数”。您可以在这里了解更多信息:https://en.wikipedia.org/wiki/IEEE_754#Rounding_rules
答案 1 :(得分:1)
在这个答案中,我将说明如何针对基本的32位二进制浮点使用IEEE-754舍入到最近的关系到偶数规则舍入。这可能是您想要的。尽管许多Python实现使用IEEE-754,但是Python文档并不需要这样做,即使在确实使用IEEE-754的实现中,也可能与IEEE-754标准有所不同,因此您不应该将Python作为权威参考。
给出一个48位有效数 1 ,让我们对从最高有效位的0到最低有效位的47位进行编号。 (这与通常的方向相反,但是对于本次讨论很方便。)
如果乘积在浮点格式的正常范围内,则有效位数将被四舍五入:
如上所述,以上是针对正常情况的。处理所有情况:
请注意,“限制指数”步骤似乎会使“有效数标准化”步骤撤消,从而使前一步骤变得不必要,但是此组合可处理所有产生正常和非正规结果的正常和非正规操作数。
1 “有效位数”是IEEE-754标准中用于浮点数小数部分的术语。 “ Mantissa”是对数的分数部分的旧术语。 (有效数字是线性的。尾数是对数的。)
答案 2 :(得分:0)
过去,我已经将此精确的事情作为求职申请的练习:
Python脚本可生成随机浮点并创建包含IEEE754值和乘积的测试向量:
import bitstring, random
spread = 10000000
n = 100000
def ieee754(flt):
b = bitstring.BitArray(float=flt, length=32)
return b
if __name__ == "__main__":
with open("TestVector", "w") as f:
for i in range(n):
a = ieee754(random.uniform(-spread, spread))
b = ieee754(random.uniform(-spread, spread))
# calculate desired product based on 32-bit ieee 754
# representation of the floating point of each operand
ab = ieee754(a.float * b.float)
f.write(a.bin + "_" + b.bin + "_" + ab.bin + "\n")
Verilog代码使用最近的偶数舍入进行32位浮点乘法:
/* Input and outputs are in single-precision IEEE 754 FP format:
Sign - 1 bit, position 32
Exponent - 8 bits, position 31-24
Mantissa - 23 bits, position 22-1
Not implemented: special cases like inf, NaN
*/
// indices of components of IEEE 754 FP
`define SIGN 31
`define EXP 30:23
`define M 22:0
`define P 24 // number of bits for mantissa (including
`define G 23 // guard bit index
`define R 22 // round bit index
`define S 21:0 // sticky bits range
`define BIAS 127
module fp_mul(input wire clk,
input wire[31:0] a,
input wire[31:0] b,
output wire[31:0] y);
reg [`P-2:0] m;
reg [7:0] e;
reg s;
reg [`P*2-1:0] product;
reg G;
reg R;
reg S;
reg normalized;
reg state;
reg next_state = 0;
parameter STEP_1 = 1'b0, STEP_2 = 1'b1;
always @(posedge clk) begin
state <= next_state;
end
always @(state) begin
case(state)
STEP_1: begin
// mantissa is product of a and b's mantissas,
// with a 1 added as the MSB to each
product = {1'b1, a[`M]} * {1'b1, b[`M]};
// get sticky bits by ORing together all bits right of R
S = |product[`S];
// if the MSB of the resulting product is 0
// normalize by shifting right
normalized = product[47];
if(!normalized) product = product << 1;
next_state = STEP_2;
end
STEP_2: begin
// if either mantissa is 0, result is 0
if(!a[`M] | !b[`M]) begin
s = 0; e = 0; m = 0;
end else begin
// sign is xor of signs
s = a[`SIGN] ^ b[`SIGN];
// mantissa is upper 22-bits of product w/ nearest-even rounding
m = product[46:24] + (product[`G] & (product[`R] | S));
// exponent is sum of a and b's exponents, minus the bias
// if the mantissa was shifted, increment the exponent to balance it
e = a[`EXP] + b[`EXP] - `BIAS + normalized;
end
next_state = STEP_1;
end
endcase
end
// output is concatenation of sign, exponent, and mantissa
assign y = {s, e, m};
endmodule
希望有帮助!