大数吃小数在工程中是需要避免的,先来解释一下什么是大数吃小数,再提一下如何解决。
先了解一下单精度浮点数 float 双精度浮点数 double,本图来字知乎问题:单精度与双精度是什么意思,有什么区别?
2^23=8388608,一共7位,这意味着float类型最多能有7位有效数字,但是能绝对能保证的为6位,也即float的精度为6~7位。(平时讲有效数字是6~7位 ,指10进制。)我们用两个float相加,设有a=123456;b=2.189;a+b应该是123458.189但是由于float的精度只有小数点后6-7位,所以必然得不到123458.189,后面的89可能会截掉,8不一定,9是必然会截掉的。好的,才做一个加法就产生至少了0.009的误差,做1000个这样的加法,误差就是9了,这显然不是我们想要的。
kahan求和算法可以避免这种情况,它有一个数用来记住那个被截断的小数,同样做下面的计算,设有a=123456;b=2.189;计算a+b。kahan求和算法是这样做的:sum=a+b(不准确); temp= (a+b)-a-b;temp等于多少呢,初看这不就是0吗?不是的,计算机此时算的可不是0,而是等于-0.009,就是被截断的那个小数。通过一个临时变量我们就记住了这个误差,当计算下一个加法的时候,可以把这个误差补上,并且更新误差到sum。