• 6723阅读
  • 9回复

[提问]浮点数加法,为嘛会有计算错误啊? [复制链接]

上一主题 下一主题
离线hawkingyy
 
只看楼主 倒序阅读 楼主  发表于: 2012-05-06
  1. #include <QtCore/QCoreApplication>
  2. #include <QFile>
  3. #include <QString>
  4. #include <QTextStream>
  5. #include <QTextCodec>
  6. int main(int argc, char *argv[])
  7. {    
  8.      QCoreApplication a(argc, argv);    
  9.      QFile file("flie.txt");    
  10.      int i=1;
  11.      float f[760];
  12.      f[1]=118;
  13.      for(i=1;i<=760;i++)
  14.        {        
  15.          f[i+1]=f[i]+0.025;
  16.        }    
  17. if(file.open(QIODevice::WriteOnly | QIODevice::Text))    
  18. {        
  19.         QTextStream stream(&file);
  20.         i=1;        
  21.         while(i<=760)        
  22.             {            
  23.                stream<<f[i]<<"\n";
  24.                i++;
  25.             }        
  26.         file.close();    
  27. }    
  28. return a.exec();
  29. }


前面的计算结果都是正确的,结果到了后面,怎么会出现
132.549
132.574
132.599
132.624
132.649
132.674
132.699
……
这种数据啊?应该都是以5或者0结尾的啊~~~~
如果是浮点数精度引起的误差,该怎么解决呢?


离线dbzhang800

只看该作者 1楼 发表于: 2012-05-06
晕,你能想到精度问题还用单精度的 float ?
离线roywillow

只看该作者 2楼 发表于: 2012-05-06
还是用double或者qreal吧……
专业维修核潜艇,回收二手航母、二手航天飞机,大修核反应堆,拆洗导弹发动机更换机油,无人侦察机手动挡改自动,航天飞机保养换三滤,飞碟外太空年检 ,各型号导弹加装迎宾踏板,高空作业擦洗卫星表面除尘、打蜡及抛光,东风全系列巡航导弹。并提供原子对撞机。量大从优,有正规发票。
离线lejcey

只看该作者 3楼 发表于: 2012-05-06
到了21世纪,请勿使用float,现在的CPU和编译器都专门针对double进行过优化,所以应当在所有的情况下都使用double。
离线hawkingyy
只看该作者 4楼 发表于: 2012-05-06
主要是二维数组的元素有点多,760*760个,一跑就出错。
只有用static的,double的太占资源了……
离线lejcey

只看该作者 5楼 发表于: 2012-05-06
很多吗?一个double不过8个字节,760*760*8=4620KB,不算大啊。

看你的代码是txt储存的,你可以使用二进制存储,速度会块很多,text会牵涉到很多转换的。
因为精度问题,你还要注意一个舍入误差,以免结果看起来很奇怪,如double a = (int)(3.1415926 * 1000.0) / 1000.0;
离线hawkingyy
只看该作者 6楼 发表于: 2012-05-06
引用第5楼lejcey于2012-05-06 21:04发表的  :
很多吗?一个double不过8个字节,760*760*8=4620KB,不算大啊。
看你的代码是txt储存的,你可以使用二进制存储,速度会块很多,text会牵涉到很多转换的。
因为精度问题,你还要注意一个舍入误差,以免结果看起来很奇怪,如double a = (int)(3.1415926 * 1000.0) / 1000.0;



谢谢lejcey啦!
现在先用txt,方便查错,以后要全部写到MYSQL里
舍入误差这个东东不是很清楚,还得好好看看
离线lejcey

只看该作者 7楼 发表于: 2012-05-06
你的程序还有一个问题,我不知道你是不是故意这样,你的数组是从1开始的,请转变思路,从0开始。

还有,可以不一行一行的写,先建立一个缓冲区,把结果写入内存,然后一次性写入文件,这样会快很多。数据库也是一样,用事务处理,加快速度。

你的程序我用c语言给你演示一下,请自行改为C++代码,原理一样:
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. int main(){
  5.   FILE *file = NULL;
  6.   int i = 0, count = 760;
  7.   size_t size = 0;
  8.   double *result, first = 118.0;
  9.   
  10.   result = malloc(sizeof(double) * (count + 1));
  11.   *result = first;
  12.   
  13.   for (i = 0; i < count; ++i){
  14.     *(result + 1 + i) = (int)((*(result + i) + 0.025) * 1000.0) /1000.0;
  15.   }
  16.   
  17.   
  18.   file = fopen("test.txt", "w");
  19.   for (i = 0; i < count; ++i){
  20.     fprintf(file, "%3.3f\n", *(result + i));
  21.   }
  22.   
  23.   free(result);
  24.   fclose(file);
  25.   
  26.   return 0;
  27. }


运行结果:
118.000
118.025
118.050
118.075
……
……
……
136.975

离线dbzhang800

只看该作者 8楼 发表于: 2012-05-07
引用第5楼lejcey于2012-05-06 21:04发表的  :
因为精度问题,你还要注意一个舍入误差,以免结果看起来很奇怪,如double a = (int)(3.1415926 * 1000.0) / 1000.0;

这个思路就有些问题了。

其实楼主的问题有两个方面,首先

0.025在2进制世界的浮点数中是无法精确表示的
0.025 = 2^(-6) + 2^(-7) + 2^(-10) + 2^(-11)+ ...

再就是单精度float只有6/7位的有效数字。而他直接用到了6位,而且还是累加一个本身有误差数得到的。

离线hawkingyy
只看该作者 9楼 发表于: 2012-05-09
引用第7楼lejcey于2012-05-06 22:32发表的  :
你的程序还有一个问题,我不知道你是不是故意这样,你的数组是从1开始的,请转变思路,从0开始。
还有,可以不一行一行的写,先建立一个缓冲区,把结果写入内存,然后一次性写入文件,这样会快很多。数据库也是一样,用事务处理,加快速度。
你的程序我用c语言给你演示一下,请自行改为C++代码,原理一样:
.......


太谢谢lejcey君啦!!!
我再好好学学,刚接触编程不久,还有好多东东要学啊!!
快速回复
限100 字节
 
上一个 下一个