![f8c85e8b077c16739a8f4ceb040f7162.png](https://i-blog.csdnimg.cn/blog_migrate/f6c5d740bbbf2a0e409e964ee6a26fd6.png)
本篇文章通过解析浮点数精度格式,分析为什么浮点数会出现误差,并提供了减少浮点数运算误差要尽量遵循的原则。
在计算机中,小数有两种表示方式:定点数和浮点数。小数点隐含在某一个固定位置上的数据,就称为定点数。为了能正确的表示定点数,我们必需规定数据的位数和小数点的位置,以8位的数据为例,规定低3位是小数位,则一个定点数
IEEE 754标准[4,5]是由1985年[1]引入的浮点数算术标准,是最广泛使用的浮点数运算标准,在2008年[2]对该标准进行了修改。
![2cc0c0cc28cd9193159b14ff57c390b1.png](https://i-blog.csdnimg.cn/blog_migrate/325fa2f880742d586a9ec85873062868.png)
IEEE 754标准规定的单精度和双精度浮点数的存储格式如图1.1所示,最高位是符号位
![83f286ed14b89e73795a11aafb720c6a.png](https://i-blog.csdnimg.cn/blog_migrate/095582ecf5c6532713b01a74aa47953b.png)
浮点数的数值可以用三元组
- 若
,则
,称该浮点数为正规数;
- 若
且
,则
(无论
为0或1);
- 若
且
,则
;
- 若
且
,则
,称该浮点数为非正规数;
- 若
且
,则
。
以单精度浮点数为例,单精度编码和对应的数值如表2所示:
![c529d7641425bb574b8fc60a8acb53e0.png](https://i-blog.csdnimg.cn/blog_migrate/3fa95829da8941a98f53333d9976fca1.jpeg)
例如,将数“-7.5”用单精度浮点数的二进制表示,它的转化过程如下所示:
![a2c25afd985862b68b7382a5108153f2.png](https://i-blog.csdnimg.cn/blog_migrate/5317b0a13d4a959ccf0997df0dd70fc4.png)
数“-7.5”的二进制浮点数表示为
为了方便理解,设浮点数的底数为
![0da785e91e32314f50215aeecac635e1.png](https://i-blog.csdnimg.cn/blog_migrate/2fbe9442187c6331ed5c29a8aaf9c2ad.png)
浮点数表示的数据范围比定点数更广泛,但它并不能精确的表示在最大数和最小数之间的所有实数,例如无理数
![bc2b8ac3c5a75f5e6dd1ddc389f863dc.png](https://i-blog.csdnimg.cn/blog_migrate/379e7b9e75b11a084807b32b28f3c7e6.png)
浮点数不仅在实数的表示上存在误差,在数值运算上也存在误差。为了方便理解,设浮点数的底数为10,有3个有效数字。计算
如果对两个绝对值差别很大的两个数作加减操作,就会出现上述所示的“大数吃小数”的现象。被消除的小数
此外,由于浮点数范围的局限,如果两个特别大(小)的数相乘或除以一个特别小(大)的数,就可能造成上(下)溢,这也是误差的一个来源。
在运算过程中,重复利用上一次浮点运算的结果,可能造成误差的累加。例如,计算多项式
在设计算法的时候,必需在精度和速度做好一定的权衡,可以采用32位的浮点数,具有更快的速度、更少的内存,也可能采用64位的双精度,具有更高的精度,但是需要更多的内存,速度也会有所降低。在涉及浮点数的算法中,尽量遵循下面几个原则,尽可能的减少由于浮点数造成的错误,或者减少误差:
1.避免相近的两数相减
例如a1 = 0.12345,a2 = 0.12346,各有5位有效数字,而 a2 - a1 = 0.00001,只剩下1位有效数字,容易造成相对误差增大,严重影响最终计算精度。
2.避免小分母
例如单精度浮点数,阶码表示的范围是-126~127,分母过小,分母和分子的阶码叠加,可能造成浮点数的溢出
3.避免大数吃小数
在浮点运算中,要对阶操作,否则可能造成小数有效数字溢出,影响结果。举个例子,为了解释的方便,假设计算机采用十进制表示:
4.简化计算步骤
减少运算次数(运算量),避免误差积累。
参考
[1] IEEE. "IEEE Standard for Binary Floating-Point Arithmetic."
[2] Dan Zuras, et al. "IEEE standard for floating-point arithmetic." IEEE Std 754-2008, pp.1-70, 2008.
[3] Christer Ericson. Real-time collision detection. Amsterdam/Boston: Elsevier, 2005.
[4] James M. Van Verth, and Lars M. Bishop. Essential Mathematics for Games and Interactive Applications: A Programmer's Guide. CRC Press, 2008.
[5] David A. Patterson, and John L. Hennessy. Computer organization and design: the hardware/software interface. Newnes, 2013.
[6] David Goldberg. "What every computer scientist should know about floating-point arithmetic." ACM Computing Surveys (CSUR), vol.23, no.1. pp.5-48, 1991.
[7] John F. Reiser, and Donald E. Knuth. "Evading the drift in floating-point addition." Information Processing Letters, vol.3, no.3, pp.84-87, 1975.
[8] Jonathan Richard Shewchuk. "Adaptive precision floating-point arithmetic and fast robust geometric predicates." Discrete & Computational Geometry, vol.18, no.3, pp.305-363, 1997.
[9] Johnathan Richard Shewchuk. "Robust adaptive floating-point geometric predicates." Proceedings of the twelfth annual symposium on Computational geometry, ACM, 1996.