单精度浮点数的数学计算
加减法:
⼀.将⼗进制数变为⼆进制数
⼗进制的⼩数转换为⼆进制,主要是⼩数部分乘以2,取整数部分依次从左往右放在⼩数点后,直⾄⼩数点后为0。例如⼗进制的0.125,要转换为⼆进制的⼩数。
举例:
0.125(⼗进制变为⼆进制)
将⼩数部分0.125乘以2,得0.25,然后取整数部分0
再将⼩数部分0.25乘以2,得0.5,然后取整数部分0
再将⼩数部分0.5乘以2,得1,然后取整数部分1
则得到的⼆进制的结果就是0.001
⼆.把⼆进制数变为浮点数源
先将⼗进制转换后的⼆进制数调整尾数,⽐如:11.1001应该变成1.11001E+1。
三.套⼊单精度-默认空壳中
带⼊下图的单精度浮点数的空壳中,如上例中,符号位为0,价码为 0b01111111 + (E+1) = 0b10000000 ,尾数为11001。
符号位价码尾数
A  【31】【30:23】【22:0】
B  【31】【30:23】【22:0】
四.操作数预处理
定义rA,rB把A和B中的数据存⼊,如图所⽰
符号位[56]价码[55:48]隐藏位[47:46]尾数[45:23]尾数补偿[22:0]
rA  A[31]        A[30:23]      01          A[22:0]            23'd0
rB  B[31]          B[30:23]      01          B[22:0]            23'd0
五.价码对齐
设置寄存器rExp和rExpDiff。rExp = A[30:23] - B[30:23]; rExpDiff存rExp的正值。
寄存器 rExp 和 rExpDiff 均为 10 位,rExp 寄存 A 与 B 的价码差;rExpDiff 则寄存相 差位数。寄存器 rExp 之所以要声明为 10 位位宽,是为了判断价码差的符号位。如果 rExp[8]为 1 的话,说明价码差位负值,换句话说 A 的价码⼩于 B;如果 rExp[8]为 0, 说明 A 的价码⼤于还是等于 B。
if( rExp[8] == 1) 表⽰ A 的价码⼩于 B 的价码, 所以 A 必须向 B 对齐,rA 的尾数(包括补偿尾数)即 rA[47…0] 向右移 rExpDiff 位。 然后 rA 的价码即,rA[55:48]赋予 rB 的价码。
反之 B 必须向 A 对齐,rB 包括补偿尾数 移动 rExpDiff 位(rB[47:0]>>rExpDiff),然后 rB 的价码赋予 rA 的价码(rB[55:48]<<
rA[55:48])。
六.尾数运算预处理
未执⾏加减运算之前,我们还要根据 rA 和 rB 的符号位,把 rA 和 rB 的尾数(包括尾数补偿)转换成补码与否。
位【48】位【47:0】
TempA    rA【56】        rA【47:46】(隐藏位) rA【46:0】
TempB    rA【56】        rB【47:46】(隐藏位) rB【46:0】
需要对TempA和TempB进⾏补码转化。
七.加减法操作
Temp <= TempA + TempB,如图所⽰
⼋.结果预处理
isSign 赋予 Temp[48],Temp[48]则是加减结果的符号位。然后 判断 Temp[48]的符号位,如果为 1 的就正直化结果。最后更新 rExp 为 rA 的价码 (rB 的价码也是等价)。
位【9:8】位【7:0】
rExp      00                      rA【55:48】(价码)
九.结果调整
假定⼩数点Temp【47:46】.Temp【45:23】
调整过程如图所⽰:
除了结果的隐藏位为 2’b01 以外,其外都需要调整:
如果结果的隐藏位为 2’b11 那么尾数需右移 1 位,然后价码加 1;
如果结果的隐藏位为 2’b10 那么尾数需右移 1 位,然后价码加 1;
如果结果的隐藏位为 2’b00,但是第 45 位为 1,那么需尾数左移 1 位,然后价码减 1;
如果结果的隐藏位为 2’b00,但是第 44 位为 1,那么需尾数左移 2 位,然后价码减 2;
如果结果的隐藏位为 2’b00,但是第 43 位为 1,那么需尾数左移 3 位,然后价码减 3;
如果结果的隐藏位为 2’b00,但是第 24 位为 1,那么尾数需左移 22 位,然后价码减 22;
如果结果的隐藏位为 2’b00,但是第 23 位为 1,那么尾数需左移 23 位,然后价码减 23。
这个过程中会对价码进⾏改变,后⾯输出和格式需要进⾏判断
⼗.输出格式化
1.价码溢出
假设 rExp[9:8]为 2’b00,即表⽰价码没有溢出;
rExp[9:8]为 2’b01,即表⽰价码为上溢;
rExp[9:8]为 2’b11,即表⽰价码为下溢。
2.尾数零值
尾数零值仅是⼀个假想的错误状态,⼀般上单精度的浮点数⽆法表⽰ 0 值,0 值在浮点 数中表⽰⽆穷⼤。尾数零值还有另⼀个可能是:当浮点数执⾏运算过后可能会发⽣尾数 全零的状态,举个例⼦ 1.5E+2 减 1.5E+2。
除此之外,当运算结果使得精度⾮常⾮常⼩的时候,甚⾄超过单精度可以曾受的范围之内,我们也可以看成是尾数零值。
3.四舍五⼊
对于 2 进制来说四舍五⼊等价于“0 舍 1 ⼊”。
支持小数点的进制转换器
如果 Temp[22]的值是 1 的话,那么 Temp[45…23]就加1,反之不然。
位【31】位【30:23】位【22:0】
rResult    isSign    rExp【7:0】(价码)尾数
⼗⼀.单精度浮点数转换为⼆进制数
1、分割数字的符号、阶码和有效数字;
2、将偏移阶码减去偏移,得到真正的阶码;
3、把数字写成规格化的⼆进制数形式
举个例⼦:
结果调整后:
Temp(A+B后的)=0 01 11100000000000000000000(经过了取反)
符号位为1,隐藏位为01,价码为10000000
所以:
rResult=32’b1_10000000 11100000000000000000000
还原阶码:10000000 – 01111111=1
该浮点数的⼆进制规格化形式:1.111×E1 (其中前⾯的“1.”从隐含位⽽来)
⼗⼆.⼆进制数转换为⼗进制
1、把规格化的⼆进制数改变成⾮规格化的⼆进制数;
2、把⾮规格化的⼆进制数转换成⼗进制数。
⼆进制为1.111×E1
尾数调整后,⾮规格化⼆进制数为:11.11
⼩数点前转化为:1+12=3
⼩数点后转化为:11/2+1*1/4=0.75
由于符号位为1
所以结果为-3.75
乘法:
⼀.操作数预处理
位【32】位【31:24】位【23】位【22:0】
rA    A【31】  A【30:23】      1    A【22:0】
rB    B【31】    B【30:23】      1    B【22:0】
rA<= {A[31],A[30:23], 1’b1,A[22:0]};
rB<= { B[31], B[30:23], 1’b1, B[22:0]}
A,B与加法中⼀致
⼆.符号位运算
符号位的运算可以⽤亦或取得。
isSign <=A[31] ^ B[31];
三.移位预操作
根据某个“特殊条件”,把操作数 B 的⼩数点左移 1 位,然后价码递增 1,在移位过程中包括隐藏位。特殊条件:操作数组价码等价,但是双反尾数同不等于 0
if(rA[31:24]==rB[31:24]&&(rA[22:0]!=23'd0&rB[22:0]!=23'd0))
begin
rB[31:24]<=rB[31:24]+1'b1;
rB[23:0]<=rB[23:0]>>1;
end
四.价码和尾数运算
价码相加,尾数相乘,因为指数需要相加
BDiff= rB[31:24] - 8'd127; // + (~8'd127 + 1)
rExp <= rA[31:24] + BDiff;//A.Exp + B.Exp
Temp <= rA[23:0] * rB[23:0];
五.结果调整
Temp为【47:0】,没有符号位
begin
if(Temp[47]==1'b1)
begin
Temp<=Temp;
end
elseif(Temp[46]==1'b1)
begin
Temp<=Temp<<1;
end
elseif(Temp[45]==1'b1)
begin
Temp<=Temp<<2;
rExp<=rExp-1'b1;
end
end
这⾥需要注意的是价码的改变,并且调整范围没有加减运算的⼤。
六.输出和格式化
在这个步骤中,我们同样要检查价码溢出或者尾数零值等错误信息以外,我们要四舍五⼊尾数的结果。
begin
if( rExp[9:8]== 2'b01 )
begin
isOver <= 1'b1;
rResult <={1'b0,8'd127, 23'd0};
end  // E Underflow
else if( rExp[9:8] == 2'b11 )
begin
isUnder <= 1'b1;
rResult <= {1'b0, 8'd127, 23'd0};
end // E Underflow
else if(Temp[47:24]== 24'd0 )
begin
isZero <= 1'b1;
rResult <={1'b0, 8'd127, 23'd0};
end // M Zero
else if(Temp[23] == 1'b1 )
rResult <={ isSign, rExp[7:0],Temp[46:24] + 1'b1 };
else rResult <={ isSign, rExp[7:0], Temp[46:24]};
end
除法
⼀.操作数预处理
位【32】位【31:24】位【23】位【22:0】
rA    A【31】  A【30:23】      1    A【22:0】
rB    B【31】    B【30:23】      1    B【22:0】
rA<= {A[31],A[30:23], 1’b1,A[22:0]};
rB<= { B[31], B[30:23], 1’b1, B[22:0]}
⼆.运算
操作数 A 的尾数左移24位,操作数B的尾数右移24位,对于单精度格式的来说这种程度的马⼒已经⾜够满⾜运算。
begin
isSign<=A[31]^B[31];
BDiff=rB[31:24]-8'd127;
rExp<=rA[31:24]-BDiff;
Temp<={rA[23:0],24'd0}/{24'd0,rB[23:0]};
end
三.结果调整
如果操作数为24位,马⼒为24档位,左移23位的话,价码不变化,左移24位,价码减1。
begin
if(Temp[25]==1'b1)
begin
Temp<=Temp<<22;
end
elseif(Temp[24]==1'b1)
begin
Temp<=Temp<<23;
end
elseif(Temp[23]==1'b1)
begin
Temp<=Temp<<24;
rExp<=rExp-1'b1;
end
end
四.输出格式化
在输出和格式化这个步骤中,浮点乘法和浮点除法的内容基本上是⼤同⼩异,因为浮点除法和浮点 乘法都⼀样,我们“假定”⼩数点介于Temp[47]-Temp[46]之间。不过有⼀点读者会吓到的是, 浮点除法少了四舍五⼊这个操作,为什么呢?有两种原因,第⼀个原因是经过结果调整以后,Temp[23]~Temp[0] 很⼤可能是全零。另⼀个原因是,在尾数运算途中保护精度的措施已经最⼤发 挥了,所以四舍五⼊操作显得有点鹌鹑,因此就被节了。
begin
if(rExp[9:8]== 2'b01 )
begin
isOver <= 1'b1;
rResult <={1'b0,8'd127, 23'd0};
end
else if(rExp[9:8] == 2'b11)
begin
isUnder <= 1'b1;
rResult<= {1'b0, 8'd127, 23'd0};
end
else if(Temp[47:24]== 24'd0)
begin
isZero <= 1'b1;
rResult<={1'b0, 8'd127, 23'd0};
end
else
rResult <={ isSign,rExp[7:0],Temp[46:24]};
end