首先是float累加产生误差的原因,该部分转自:http://blog.csdn.net/zhrh0096/article/details/38589067

1.  浮点数IEEE 754表示方法

要搞清楚float累加为什么会产生误差,必须先大致理解float在机器里怎么存储的,具体的表示参考[1] 和 [2], 这里只介绍一下组成

由上图可知(摘在[2]), 浮点数由: 符号位 + 指数位 + 尾数部分, 三部分组成。由于机器中都是由二进制存储的,那么一个10进制的小数如何表示成二进制。例如: 8.25转成二进制为1000.01, 这是因为 1000.01 = 1*2^3 + 0*2^2 + 0*2^1 + 0*2^0 + 0*2^-1 + 2*2^-2 = 1000.01.

(2)float的有效位数是6-7位,这是为什么呢?因为位数部分只有23位,所以最小的精度为1*2^-23 在10^-6和10^-7之间,接近10^-7,[3]中也有解释

那么为什么float累加会产生误差呢,主要原因在于两个浮点数累加的过程。

2. 两个浮点数相加的过程

两浮点数X,Y进行加减运算时,必须按以下几步执行(可参考 [4] 中插图):
(1)对阶,使两数的小数点位置对齐,小的阶码向大的阶码看齐。
(2)尾数求和,将对阶后的两尾数按定点加减运算规则求和(差)。
(3)规格化,为增加有效数字的位数,提高运算精度,必须将求和(差)后的尾数规格化。
(4)舍入,为提高精度,要考虑尾数右移时丢失的数值位。
(5)判断结果,即判断结果是否溢出。

关键就在与对阶这一步骤,由于float的有效位数只有7位有效数字,如果一个大数和一个小数相加时,会产生很大的误差,因为尾数得截掉好多位。例如:

123 + 0.00023456 = 1.23*10^2 + 0.000002 * 10^2 = 123.0002

那么此时就会产生0.00003456的误差,如果累加多次,则误差就会进一步加大。

解决方式有几种,但都不是最佳方式,参考:http://bbs.csdn.net/topics/390549664

3.解决方法

方法一

Kahan summation算法

https://en.wikipedia.org/wiki/Kahan_summation_algorithm

function KahanSum(input)
var sum = 0.0
var c = 0.0 // A running compensation for lost low-order bits.
for i = 1 to input.length do
var y = input[i] - c // So far, so good: c is zero.
var t = sum + y // Alas, sum is big, y small, so low-order digits of y are lost.
c = (t - sum) - y // (t - sum) cancels the high-order part of y; subtracting y recovers negative (low part of y)
sum = t // Algebraically, c should always be zero. Beware overly-aggressive optimizing compilers!
next i // Next time around, the lost low part will be added to y in a fresh attempt.
return sum

伪代码如上

解决方法就是把多余的误差部分算出来(c),再在下一次循环减去这个误差

方法二

int main()
{
float f = 0.1;
float sum = 0;
sum+=add(f,4000000);
cout<<sum<<endl;
return 0;
} float add(float f,int count)
{
if(count==1)
return f;
else
return add(f,count/2)+add(f,count-count/2);
}

二分法递归计算加法,这样会没有误差,但是函数调用消耗大(尤其是多次)

方法三

使用double,精度更高,但是本来是没有必要用这么高精度的

方法四

ieee浮点数,为了规格化,精度每超过2的整数次幂,精度要下降一位,
你的f是0.1,float位数是23,当sum足够大的时候,会出现 sum+f==sum 的情况,这个是ieee标准,
和C++没关系,事实上编译器应该已经做了浮点精度调整了,你这结果误差算小的了.
避免这种误差的方法就是浮点数,永远不要让一个很大的数去加上一个很小的数.不知你这段代码的目的是

什么,但如果你改成这样,误差会小很多:

float f = 0.1;
float sum = 0;
for( i=0; i<100; i++)
{
int sumEachBig=0;
for(....k<400....)
{
int sumEachSmall=0;
for(....j<100.....)
sumEachSmall += f; sumEachBig+=sumEachSmall; } sum += sumEachBig; }

来自manzi11的回答。多次用多次循环,小循环的计算结果加上大循环的运算结果

by wolf96 2017/7/10

浮点数float累加误差解决方式总结的更多相关文章

  1. Java浮点数float,bigdecimal和double精确计算的精度误差问题总结

    (转)Java浮点数float,bigdecimal和double精确计算的精度误差问题总结 1.float整数计算误差 案例:会员积分字段采用float类型,导致计算会员积分时,7位整数的数据计算结 ...

  2. Relearning PHP (2) – php 的浮点数float

    Relearning PHP (2) – php 的浮点数float 暂无评论 php有很多坑,但是并不妨碍他是最好的语言.其他语言对于浮点数处理同样有问题,这应该是个“共有坑”.不信可以用googl ...

  3. C++中的浮点数运算的误差测试分析

    C++中的浮点数运算的误差 项目中需要计算判定,采用的是float型,如: float a < yLing, 其中:a = 2.0, y则从1.0 + 0.2*n  当n = 4时,条件成立了? ...

  4. mixare的measureText方法在频繁调用时抛出“referencetable overflow max 1024”的解决方式

    这几天在搞基于位置的AR应用,採用了github上两款开源项目: mixare android-argument-reality-framework 这两个项目实现机制大致同样.我选取的是androi ...

  5. 精通CSS:高级Web标准解决方式(第2版)

    精通CSS:高级Web标准解决方式(第2版) 跳转至: 导航. 搜索 层叠重要度:(也就是说.用户!important能够覆盖inline style) !important.用户>作者.最后是 ...

  6. Android内存优化-内存泄漏的几个场景以及解决方式

    转自:http://blog.csdn.net/a910626/article/details/50849760 一.什么是内存泄漏 在Java程序中,如果一个对象没有利用价值了,正常情况下gc是会对 ...

  7. Linux下Chrome浏览器不支持WebGL的解决方式。

    今天使用Chrome浏览器,总是报这样一个错误: Uncaught TypeError: Cannot read property 'canvas' of null. 细看之下是无法获取WebGL上下 ...

  8. get传递中文产生乱码的解决方式汇总

    1 最基本的乱码问题. 这个乱码问题是最简单的乱码问题.一般新会出现.就是页面编码不一致导致的乱码. <%@ page language="java" pageEncodin ...

  9. Ubuntu安装出现左上角光标一直闪解决方式

    Ubuntu安装出现左上角光标一直闪解决方式: 01下载ubunu http://cn.ubuntu.com/download/ 02.软碟通 http://pan.baidu.com/s/1qY8O ...

随机推荐

  1. dfs(枚举)

    http://codeforces.com/gym/100989/problem/L L. Plus or Minus (A) time limit per test 1.0 s memory lim ...

  2. Educational Codeforces Round 60 (Rated for Div. 2) D. Magic Gems(矩阵快速幂)

    题目传送门 题意: 一个魔法水晶可以分裂成m个水晶,求放满n个水晶的方案数(mol1e9+7) 思路: 线性dp,dp[i]=dp[i]+dp[i-m]; 由于n到1e18,所以要用到矩阵快速幂优化 ...

  3. python学习第四十三天生成器和next()关联

    我们在用列表生成式的时候,如果有一百万的数据,内存显然不够用,这是python想要什么数据,就生产什么数据给你,就产生了生成器,下面简单讲述生成器用法 1,生成器的用法 a=([a*a for a i ...

  4. Ubuntu 中查找软件安装的位置

    Ubuntu 中查找软件安装的位置 执行该程序 直接执行该程序,有时候一些程序执行时会显示出自己的位置,比如: 用命令 ps -e 找到该程序的名字 用 find 或 whereis 命令查找文件位置 ...

  5. vue.js(10)--案例--列表增加与删除

    品牌管理案例 (1)bootstrip快速布局 <div class="app"> <div class="panel panel-primary&qu ...

  6. vs code 同步

    vs code 同步需要在github上配置好gist id, 将gist id添加至setting.json中, 然后再在localsetting中设置access token,  gist id ...

  7. 图像函数 imagecreatetruecolor()和imagecreate()的异同点

    共同点:这两个函数都是用于创建画布 区别: 1.不同的是创建画布和为画布填充颜色的流程不一样; 用imagecreatetruecolor(int x,int y)创建的是一幅大小为 x和 y的图像( ...

  8. JSP2的自定义标签和方法

    Jsp2的自定义标签 Jsp2 开发标签库的几个步骤: 开发自定义标签处理类. 建立一个*.tld文件,每个tld文件对应一个标签库,每个标签库可对应多个标签. 在jsp文件中使用自定义标签 空标签 ...

  9. How to compile and install Linux Kernel 5.1.2 from source code

    How to compile and install Linux Kernel 5.1.2 from source code Compiling a custom kernel has its adv ...

  10. Centos7搭建日志服务器rsyslog+loganalyzer

    一.系统环境 Rsyslog Server OS:CentOS 7 Rsyslog Server IP:172.28.194.118 Rsyslog Version: rsyslog-7.4.7-12 ...