浮点数和定点数
本篇文章旨在简短的介绍浮点数、定点数的定义,以及一些常见的数制、补码。
一、常识
如果缺少以下常识的话,将很难理解浮点数和定点数的概念。
1、数
- 自然数
- 整数/分数
- 小数:有限小数、无限循环小数、无限不循环小数
- 实数:一个完备的数域。
- 复数
- 向量
2、计算机中数
1和0。
3、数制
2进制:逢2进1
8进制:逢8进1
10进制:逢10进1
16进制:逢16进1
————————————————分割线——————————————————
二、定点数和浮点数
在现实世界,我们需要计算y=sin(x)、y=cos(x)的函数值,x属于R,结果将是-1~1的无限稠密的连续值。
考虑计算机,x和y只能用有限的1和0来表示(有没有感受到人类的局限性,哪怕是用10300个字节来存储,也是有限的,用全世界的硬盘来存储也是有限的)。
现在人类将做出让步:比如只用10位小数位数作为有效值,之后的小数位数就省略了。
1、定点数
一句话:区间等分。
1⃣️考虑自然数:4bit,表示0~15,一共16个数。这也被称为自然编码。无须多言,自然的意思就是自然就懂了。
2⃣️考虑小数:比如用4bit,可以表示0~15,一共16个整数。如果用来表示0~1,那么把0~1等分成16等份,4’b0000表示0,4’b0001表示1/16=0.0625,4’b1111表示15/16=0.9375。想要精度更高,就付出更多bit位数的代价。
比如8bit,8’b0000_0001 = 1/256 = 0.00390625 ≈千分之4
现在你已经学会了用二进制数表示有限位的小数了。
3⃣️现在考虑负数:补码(不需要从公式角度理解)。
补码就是走针的手表。12过了就是1。
举例:3bit,自然编码,最大就是111,表示7,现在用111表示-1,越过了111,就是000,表示0。其余的正常加减就行了。一句话:用自然编码的最大值和最小值来表示正负之间的鸿沟。
3bit的补码,范围为-4到3。(在这个数域中:3+1=-4)
-4 | -3 | -2 | -1 | 0 | 1 | 2 | 3 |
---|---|---|---|---|---|---|---|
100 | 101 | 110 | 111 | 000 | 001 | 010 | 011 |
现在你已经学会了用二进制数表示负数了。
4⃣️考虑负的小数:用补码表示小数。
比如3bit的补码,范围为-2到正2:
-4 | -3 | -2 | -1 | 0 | 1 | 2 | 3 |
---|---|---|---|---|---|---|---|
100 | 101 | 110 | 111 | 000 | 001 | 010 | 011 |
-2 | -1.5 | -1 | -0.5 | 0.0 | 0.5 | 1.0 | 1.5 |
(不知道读者读到这里有没有意识到一个问题:我们讨论的1和0和实数中的1和0是不是同一个东西?搜索关键词:伽罗华域。计算机中的1和0只是一个代号,其物理存在是高电平和低电平。如果不嫌麻烦完全可以记为阳和阴,那么这里-2的补码就是“阳阴阴”。)
2、浮点数
1⃣️考虑一个定点数:32bit能够表示的范围:0~42_9496_7295。一共有42.9亿多种状态,假设每个数,都带有10个bit的小数位数,并用补码表示:那么范围是:[-221,221-1]。221-1=209_7151。也就是说,计算范围是正负209万,两千乘以两千都会越界。(2000*2000=400万)
有没有感受到定点数的局限性?
现在我们来考虑牺牲一点东西,然后换来不越界的好处。
牺牲什么好呢?
自然是最不受重视的小数了。但又不能一个小数位数都不要。
那应该怎么办呢?
原则:大数的小数位数少一些,小数的小数位数多一些。这个原则显然是很合理的,想想你月初拿到生活费的时候,再想想你月底生活费快用光的时候。
2⃣️浮点数:
考虑一个大数:1314520 = 1.314520*106
考虑一个小数:0.1314520 = 1.314520*10-6
这里两个数差了12个数量级。
但是二者却很相似。科学记数法:±1.(小数部分)*10n
因此我们不用记录1,只需要记录正负号、小数部分、指数
现在我们把这个科学记数法里面的小数部分称为尾数部分,换个名字,便于区分。
来看看IEEE的规定:(图片截图于:通俗易懂理解——浮点与定点的计算机表示及互转)
那么你能计算出单精度浮点数的范围吗?
指数部分8位,考虑正负指数:-128到127次方。
范围就是[-10127,10127]。
这种表示规则的好处就是,将范围拓展的很大,并且每个数都只有23位尾数。这意味着,一个大于1023的数,将会一个小数位数都没有。
带来的坏处:一个大数+一个小数,小数结果将被无情丢弃,这可能会导致计算出错。