1.前言
前面一篇文章讲了计算机中的数字表示法:原码、补码和反码,这一篇文章开始进行定点数的讲解。
2.什么是定点数
定点数,从字面意思上理解就是小数点位置固定,如下图所示:
数字既包括整数,又包括小数,而小数的精度范围要比整数大得多,所以如果我们想在计算机中,既能表示整数,也能表示小数,关键就在于这个小数点如何表示?
于是人们想出一种方法,即约定计算机中小数点的位置,且这个位置固定不变,小数点前、后的数字,分别用二进制表示,然后组合起来就可以把这个数字在计算机中存储起来,这种表示方式叫做「定点」表示法,用这种方法表示的数字叫做「定点数」。
3.定点数如何去表示数字
定点数如果要表示整数或小数,分为以下三种情况:
1.纯整数:例如整数88,小数点其实在最后一位,所以忽略不写
2.纯小数:例如:0.1234,小数点固定在最高位
3.整数+小数:例如1.23、10.24,小数点在指定某个位置
对于纯整数和纯小数,小数点固定在最低位和最高位,只需要把整数部分、小数部分,分别按照十进制转二进制的规则,分别转换即可。下面以8bit为例:
纯整数定点数表示(从右到左,第N位二进制为
2
N
−
1
2^{N-1}
2N−1):
8
8
(
D
)
=
0101100
0
(
B
)
88_{(D)} = 01011000_{(B)}
88(D)=01011000(B)
纯小数定点数表示(从左到右,第N位二进制为
1
/
2
N
1/2^N
1/2N):
0.62
5
(
D
)
=
0.50
0
(
D
)
+
0.12
5
(
D
)
=
0.0010000
0
(
B
)
+
0.1000000
0
(
B
)
=
0.1010000
0
(
B
)
0.625_{(D)} = 0.500_{(D)} + 0.125_{(D)}= 0.00100000_{(B)} + 0.10000000_{(B)}=0.10100000_{(B)}
0.625(D)=0.500(D)+0.125(D)=0.00100000(B)+0.10000000(B)=0.10100000(B)
可以看到表示小数的时候并能够全精度的表示一切数值,8bit纯小数定点数的精度只到
1
/
2
8
1/2^8
1/28,超过精度外的数字需要进行舍取。
定点数表示整数+小数:
而对于整数 + 小数的情况,用定点表示时,需要约定小数点的位置,才能在计算机中表示。以 8 位为例,我们约定从高位开始,1位符号位,4位整数位,后3位表示小数部分。
对于数字 -1.5 用定点数表示就是这样:
首先表示数字正的1.5,即原码:
1.
5
(
D
)
=
0000110
0
(
B
)
1.5_{(D)} = 00001 100_{(B)}
1.5(D)=00001100(B)
符号位不变,其余各位取反,+1得:
0111001
1
(
B
)
+
1
=
0111010
0
(
B
)
01110 011_{(B)} + 1 = 01110 100_{(B)}
01110011(B)+1=01110100(B)
然后对于负数,符号位填充为"1"得数字 -1.5 用定点数表示:
−
1.
5
(
D
)
=
1111010
0
(
B
)
-1.5_{(D)} = 11110 100_{(B)}
−1.5(D)=11110100(B)
表示步骤如下:
1.在有限的 bit 宽度下,先约定小数点的位置,一般取高位为符号位
2.先不管符号,整数部分和小数部分,分别转换为二进制表示
3.对于正数,两部分二进制组合起来,即是结果
4.对于负数,除符号位进行取反,然后+1,符号位填充"1"
4.定点数表示法的局限性
前面我们约定从高位开始,1位符号位,4位整数位,后3位表示小数部分。这样做,整数部分的二进制最大值只能是 1111,即十进制的 15,加上符号只能表示-16~+15,小数部分的二进制最大只能表示 0.111,即十进制的 0.875。
如果我们想要表示更大范围的值,怎么办?
1.扩大 bit 的宽度:例如使用 2 个字节、4 个字节,这样整数部分和小数部分宽度增加,表示范围也就变大了
2.改变小数点的位置:小数点向后移动,整个数字范围就会扩大,但是小数部分的精度就会越来越低,没有办法表示类似 0.00001 这种高精度的值
由此我们发现,不管如何约定小数点的位置,都会存在以下问题:
1.数值的表示范围有限(小数点越靠左,整个数值范围越小)
2.数值的精度范围有限(小数点越靠右,数值精度越低)
所以,定点表示法的主要问题是它不能有效地表示非常大或非常小的数。为了解决这个问题,人们发明了浮点表示法,其中小数点的位置是浮动的,可以根据需要移动以表示不同大小的数。下一篇文章来讲浮点数。
微信公众号含更多FPGA相关源码: