免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3889 | 回复: 6
打印 上一主题 下一主题

[C] C浮点数的精度问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-11-29 16:13 |只看该作者 |倒序浏览
业务代码里有这么一段代码
int sample(double a)
{
    ...
    int x;
    x = a * 100;
    ...
}
发现在a = 37.30或者10.20的时候x得不到想要的值。x的结果会变成3729和1029

写了个测试代码如下:
  1. #include <stdio.h>

  2. int main()
  3. {
  4.     double test = 37.30;
  5.     double test2 = 10.20;
  6.    
  7.     int i = 100;
  8.     for(; i < 1000000; i*=10) {
  9.         printf("%.2f * %d =  %d\n", test, i, (int)(test * i));
  10.         printf("%.2f * %d = %d\n", test2, i, (int)(test2 * i));
  11.     }   
  12.     return 0;
  13. }
复制代码
输出如下:
/home/xlc/DemoCode> ./floattest                  
37.30 * 100 =  3729
10.20 * 100 = 1019
37.30 * 1000 =  37300
10.20 * 1000 = 10200
37.30 * 10000 =  373000
10.20 * 10000 = 102000
37.30 * 100000 =  3729999
10.20 * 100000 = 1019999

在win7 64bit vs2013 下面和gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-54)都得到相同的结果

我知道浮点数不会精确表示。但是为何偏偏是这两个数出问题?
各位有遇到过没?

PS:目前我想是先改成 x = (int)(a * 1000) / 10;

论坛徽章:
0
2 [报告]
发表于 2014-11-29 16:33 |只看该作者
如果x是double肯定没问题,但楼主你的x是int,double转int最好用round,这样应该就没问题了。

另外楼主可以把a改成37.300和10.200试试。

论坛徽章:
0
3 [报告]
发表于 2014-11-29 16:38 |只看该作者
本帖最后由 c04n05 于 2014-11-29 17:08 编辑

回复 2# xphh2008
感谢关注。我试过37.300和10.200问题依旧。要用整形也是前辈们的业务代码这么弄的。



   

论坛徽章:
324
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
4 [报告]
发表于 2014-11-29 17:06 |只看该作者
应该跟浮点数的表示方法有关,IEEE 754

论坛徽章:
0
5 [报告]
发表于 2014-11-29 17:17 |只看该作者
本帖最后由 c04n05 于 2014-11-29 17:37 编辑

回复 4# hellioncu
回复 2# xphh2008
感谢关注。

经过验证,用round可以,输出改成这个样子

printf("%.2f * %d =  %d\n", test, i, (int)(round(test * i)));

但是在linux下这个函数需要c99标准,编译命令如下

gcc -o floattest floattest.c -std=c99 -lm

我们平台以前没有用到这个。不知道是否会影响其他代码?

ps:
又试了一下,去掉-std=c99结果一样。不过编译会有警告


   

论坛徽章:
0
6 [报告]
发表于 2014-11-29 17:52 |只看该作者
c04n05 发表于 2014-11-29 17:17
回复 4# hellioncu
回复 2# xphh2008
感谢关注。


不是一定要用round函数的啦,四舍五入很简单的,我们一般这么做:

(int)(x + 0.5)

然后写个ROUND宏就行了~



论坛徽章:
0
7 [报告]
发表于 2014-11-29 17:59 |只看该作者
回复 6# xphh2008
哦。这个思路也很不错!
果然来坛子里问一下是正确的

   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP