论述:定点小数的运算

论述:定点小数的运算

更新历史
20190324:

  1. 首次发布

目录

  • 论述:定点小数的运算
    • 十进制下非负定点小数的乘法
    • 十进制下非负定点小数的加法
    • 十进制下非负定点小数的除法
    • 二进制下定点小数的乘法
    • 二进制下定点小数的加法
    • 二进制下定点小数的除法
    • 等等,是不是漏了减法...
    • 总结

使用定点小数,可以将小数的存储和运算,转化为整数的存储和运算。由于定点小数通常在硬件计算中使用,故而,我们尤其关心的是二进制下的定点小数运算

接下来,本文将从十进制下非负定点小数的乘法、加法、除法讲起,让读者对定点小数运算上的一些注意事项有所了解,然后讲二进制下无符号和有符号定点小数的乘法、加法、除法。

十进制下非负定点小数的乘法

十进制下的两个小数:

  • A = 999.9
  • B = 9.99

如果我们计算A、B的乘积,得到的结果是:

A × B = 999.9 × 9.99 = 9989.001 A \times B = 999.9 \times 9.99 = 9989.001 A×B=999.9×9.99=9989.001

对于乘法运算得到的结果"9989.001",我们可以看到,其整数部分有4位,其小数部分有3位。我们并不会对其感到奇怪,因为:

  • A的整数部分有3位,B的整数部分有1位,所以(A × \times ×B)的整数部分有3+1=4位
  • A的小数部分有1位,B的小数部分有2位,所以(A × \times ×B)的小数部分有1+2=3位

好了,现在我们使用定点小数来替代原先的小数,看看情况变成什么样了:

  • A 定 A_定 A = 9999,对应:A = 999.9
  • B 定 B_定 B = 999,对应:B = 9.99
  • A 定 × B 定 = 9999 × 999 = 9989001 A_定 \times B_定 = 9999 \times 999 = 9989001 A×B=9999×999=9989001

由于我们事先就知道 A 定 A_定 A 的整数部分有3位,小数部分有1位, B 定 B_定 B 整数部分有1位,小数部分有2位,所以,对于乘法运算得到的整数"9989001",我们知道:

  • 其整数部分有4位,其小数部分有3位,即"9989001"对应的实际小数是"9989.001"。

对于上面的分析,我们做一下归纳总结,可以得到:

设十进制下的两个非负的定点小数:
	A定 = M位整数部分 + X位小数部分
	B定 = N位整数部分 + Y位小数部分
那么:
	(A定 × B定) =  (M+N)位整数部分 + (X+Y)位小数部分
	注:运算结果不会产生溢出

十进制下非负定点小数的加法

十进制下的两个小数:

  • A = 999.9
  • B = 9.99

如果我们计算A、B的和,得到的结果是:

A + B = 999.9 + 9.99 = 1009.89 A + B = 999.9 + 9.99 = 1009.89 A+B=999.9+9.99=1009.89

现在,我们使用定点小数来替代原先的小数,看看情况变成什么样了:

  • A 定 A_定 A = 9999,对应:A = 999.9
  • B 定 B_定 B = 999,对应:B = 9.99
  • A 定 + B 定 = 9999 + 999 = 10998 A_定 + B_定 = 9999 + 999 = 10998 A+B=9999+999=10998

看到这里,机智的你一定发现情况不对了吧?定点小数"10998"对应的实际小数怎么看都不会是"1009.89",是吧?那么,问题出在哪里呢?我们可以看看运算过程中的数据位的对应情况:

计算"A + B":							计算"A定+B定":
	9	9	9	.	9					9	9	9	9
+			9	.	9	9			+		9	9	9
----------------------------		-------------------
1	0	0	9	.	8	9			1	0	9	9	8

嗯,看来我们找到问题的真相了:

  • 求和过程中,定点小数的数据位的对应关系错了

所以,我们应该改成:

计算"A定+B定":
	9	9	9	9	(0)
+	(0)	(0)	9	9	9
----------------------------
1	0	0	9	8	9

定点小数"100989"对应的实际小数正是"1009.89"。

对于上面的分析,我们做一下归纳总结,可以得到:

设十进制下的两个非负的定点小数:
	A定 = M位整数部分 + X位小数部分
	B定 = N位整数部分 + Y位小数部分
那么:
	计算(A定 + B定)之前,要采取相应的补0措施,使得两个定点小数的整数部分位宽一致,小数部分的位宽一致。
	(A定_补0 + B定_补0) =  max(M,N) 位整数部分 + max(X,Y)位小数部分
	注:运算结果可能会产生进位溢出

十进制下非负定点小数的除法

十进制下的两个小数:

  • A = 999.9
  • B = 9.99

如果我们计算A、B的商,得到的结果是:

A ÷ B = 999.9 ÷ 9.99 = 100.09 0 ˙ 0 ˙ 9 ˙ ≈ 100 A \div B = 999.9 \div 9.99 =100.09\dot0\dot0\dot9 \approx 100 A÷B=999.9÷9.99=100.090˙0˙9˙100

现在我们使用定点小数来替代原先的小数,看看情况变成什么样了:

  • A 定 A_定 A = 9999,对应:A = 999.9
  • B 定 B_定 B = 999,对应:B = 9.99
  • A 定 ÷ B 定 = 9999 ÷ 999 = 10.009 0 ˙ 0 ˙ 9 ˙ ≈ 10 A_定 \div B_定 = 9999 \div 999 = 10.009\dot0\dot0\dot9 \approx 10 A÷B=9999÷999=10.0090˙0˙9˙10

咦,又出问题了?意外不?惊喜不?咳,言归正传,这里出现问题的原因是:

  • A 定 = A × 10 A_定 = A \times 10 A=A×10
  • B 定 = B × 100 B_定 = B \times 100 B=B×100
  • ∴ A 定 ÷ B 定 = ( A × 10 ) ÷ ( B × 100 ) = ( A ÷ B ) × 0.1 \therefore A_定 \div B_定 = (A \times 10)\div(B \times 100) = (A \div B) \times 0.1 A÷B=(A×10)÷(B×100)=(A÷B)×0.1

所以,要想得到正确的商,在做除法之前,需要先在 A 定 A_定 A的低位补0(或者说,将 A 定 A_定 A乘上10)。

对于上面的分析,我们做一下归纳总结,可以得到:

设十进制下的两个非负的定点小数:
	A定 = M位整数部分 + X位小数部分
	B定 = N位整数部分 + Y位小数部分
那么:
	计算(A定 ÷ B定)之前,要采取相应的补0措施,使得两个定点小数的小数部分的位宽一致,且A的整数部分位宽不小于B的整数部分位宽。
	(A定_补0 ÷ B定_补0) = ( max(M,N) + max(X,Y) ) bit整数部分

到此为止,通过对十进制下定点小数运算的分析,我们已经接触到了定点小数运算过程中的一些“坑”了。下面,让我们小心地避开这些“坑”,来分析二进制下有符号和无符号定点小数的乘法、加法、除法。

二进制下定点小数的乘法

对于二进制下无符号定点小数的乘法运算,其运算结果的位宽变化规律和十进制下非负定点小数乘法相同:

设二进制下的两个无符号定点小数:
	A定 = M bit整数部分 + X bit小数部分
	B定 = N bit整数部分 + Y bit小数部分
那么:
	(A定 × B定) =  (M+N) bit整数部分 + (X+Y) bit小数部分
	注:运算结果不会产生溢出

而对于二进制下有符号定点小数的乘法运算,由于牵涉到符号位,其运算结果的位宽变化规律稍稍有些不同,分析可知:

设二进制下的两个有符号定点小数:
	A定 = 1 bit符号位 + M bit整数部分 + X bit小数部分
	B定 = 1 bit符号位 + N bit整数部分 + Y bit小数部分
那么:
	(A定 × B定) = 1 bit符号位 + (M+N) bit整数部分 + (X+Y) bit小数部分
	注:运算结果不会产生溢出

可以举例说明:

  • A 定 A_定 A = 1000b,为1bit符号位+2bit整数位+1bit小数位,对应的十进制小数为-4.0
  • B 定 B_定 B = 0_1111b,为1bit符号位+2bit整数位+2bit小数位,对应的十进制小数为3.75
  • A 定 × B 定 = 1000 b × 0 _ 1111 b = 1000 _ 1000 b A_定 \times B_定 = 1000b \times 0\_1111b = 1000\_1000b A×B=1000b×0_1111b=1000_1000b,为1bit符号位+4bit整数位+3bit小数位,对应的十进制小数为-15.0

二进制下定点小数的加法

对于二进制下无符号定点小数的加法运算,其运算结果的位宽变化规律和十进制下非负定点小数加法相同:

设二进制下的两个无符号定点小数:
	A定 = M bit整数部分 + X bit小数部分
	B定 = N bit整数部分 + Y bit小数部分
那么:
	计算(A定 + B定)之前,要采取相应的补0措施,使得两个定点小数的整数部分位宽一致,小数部分的位宽一致。
	(A定_补0 + B定_补0) =  max(M,N) bit整数部分 + max(X,Y) bit小数部分
	注:运算结果可能会产生进位溢出

而对于二进制下有符号定点小数的加法运算,由于牵涉到符号位,其运算结果的位宽变化规律稍稍有些不同,分析可知:

设二进制下的两个有符号定点小数:
	A定 = 1 bit符号位 + M bit整数部分 + X bit小数部分
	B定 = 1 bit符号位 + N bit整数部分 + Y bit小数部分
那么:
	计算(A定 + B定)之前,要采取相应的低位补0措施,使得两个定点小数的小数部分的位宽一致。
	计算(A定 + B定)之前,要采取相应的次最高位补0(非负数)、次最高位补1(负数)措施,使得两个定点小数的整数部分的位宽一致。
	(A定_补齐 + B定_补齐) = 1 bit符号位 +  max(M,N) bit整数部分 + max(X,Y) bit小数部分
	注:运算结果可能会产生进位溢出

可以举例说明:

  • A 定 A_定 A = 1000b,为1bit符号位+2bit整数位+1bit小数位,对应的十进制小数为-4.0
  • B 定 B_定 B = 00_1111b,为1bit符号位+3bit整数位+2bit小数位,对应的十进制小数为3.75
  • A 定 ( 补 齐 ) + B 定 ( 补 齐 ) = 1 1 000 0 b + 00 _ 1111 b = 11 _ 1111 b A_{定(补齐)} + B_{定(补齐)} = 1{\color{orange}{1}}000 {\color{red}0} b + 00\_1111b = 11\_1111b A()+B()=110000b+00_1111b=11_1111b,为1bit符号位+3bit整数位+2bit小数位,对应的十进制小数为-0.25

二进制下定点小数的除法

对于二进制下无符号定点小数的除法运算,其运算结果的位宽变化规律和十进制下非负定点小数除法相同:

设二进制下的两个无符号定点小数:
	A定 = M bit整数部分 + X bit小数部分
	B定 = N bit整数部分 + Y bit小数部分
那么:
	计算(A定 ÷ B定)之前,要采取相应的补0措施,使得两个定点小数的小数部分的位宽一致,且A的整数部分位宽不小于B的整数部分位宽。
	(A定_补0 ÷ B定_补0) = ( max(M,N) + max(X,Y) ) bit整数部分

而对于二进制下有符号定点小数的除法运算,由于牵涉到符号位,其运算结果的位宽变化规律稍稍有些不同,分析可知:

设二进制下的两个有符号定点小数:
	A定 = 1 bit符号位 + M bit整数部分 + X bit小数部分
	B定 = 1 bit符号位 + N bit整数部分 + Y bit小数部分
那么:
	计算(A定 ÷ B定)之前,要采取相应的低位补0措施,使得两个定点小数的小数部分的位宽一致。
	计算(A定 ÷ B定)之前,要采取相应的次最高位补0(非负数)、次最高位补1(负数)措施,使得A的整数部分位宽不小于B的整数部分位宽。
	(A定_补齐 ÷ B定_补齐) = 1 bit符号位 + ( max(M,N) + max(X,Y) ) bit整数部分

可以举例说明:

  • A 定 A_定 A = 1000b,为1bit符号位+2bit整数位+1bit小数位,对应的十进制小数为-4.0
  • B 定 B_定 B = 00_1111b,为1bit符号位+3bit整数位+2bit小数位,对应的十进制小数为3.75
  • A 定 ( 补 齐 ) ÷ B 定 ( 补 齐 ) = 1 1 000 0 b ÷ 00 _ 1111 b = 11 _ 1111 b A_{定(补齐)} \div B_{定(补齐)} = 1{\color{orange}{1}}000 {\color{red}0} b \div 00\_1111b = 11\_1111b A()÷B()=110000b÷00_1111b=11_1111b,为1bit符号位+5bit整数位,对应的十进制整数为-1

注:虽然这里讲了二进制的除法,然而实际上,由于除法实现起来电路比较复杂,因此往往能避免使用除法就尽量避免使用除法。非要做除法运算的话,可以考虑使用集成的除法单元,或者采用辗转相除法自己写逻辑实现。

等等,是不是漏了减法…

在硬件计算中,减法运算的电路比较复杂,故而,通常将(a-b)运算转化为(a+(-b)),将减法运算转化为加法运算。而将b转化为(-b)是相对简单的。因此,定点小数的减法运算,就拜拜啦。。

总结

用一句话将本论述归纳总结一下,那就是:

  • 定点小数的运算,需要小心地处理位宽问题。

你可能感兴趣的:(硬件逻辑开发,定点小数)