免费注册 查看新帖 |

Chinaunix

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

[C] 11.0与11导致运算结果不一致 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-05-11 00:13 |只看该作者 |倒序浏览
我的一个练习程序,是《C Primer》上的一个实例:
  1. /**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2.   *编程实例16-18,可变参数
  3.   **/

  4. #include <stdio.h>
  5. #include <stdarg.h>

  6. double sum(int , ...);

  7. int main(void)
  8. {
  9.     double s, t, r;

  10.     s = sum(3, 11.0, 2.5, 13.3);    //11.0跟11的结果不一样
  11.     r = sum(3, 11, 2.5, 13.3);
  12.     t = sum(6, 1.1, 2.1, 13.1, 4.1, 5.1, 6.1);
  13.     printf("return value for sum(3, 11.0, 2.5, 13.3):   %g.\n", s);
  14.     printf("return value for sum(3, 11, 2.5, 13.3):  %g.\n", r);
  15.     printf("return value for sum(6, 1.1, 2.1, 13.1, 4.1, 5.1, 6.1):"
  16.         "  %g.\n", t);

  17.     return 0;
  18. }

  19. /*使用可变参数的函数*/
  20. double sum(int n, ...)      //省略了n个参数
  21. {
  22.     va_list ap;     //声明用于存放可变参数的变量
  23.     double total = 0;
  24.     int i;

  25.     va_start(ap, n);        //初始化参数列表
  26.     for(i=0; i<n; i++)
  27.         total += va_arg(ap, double);    //访问参数列表
  28.     va_end(ap);     //清理列表

  29.     return total;
  30. }
复制代码
结果,由于11.0与11导致了运算结果不一致:
  1. [color=Red]return value for sum(3, 11.0, 2.5, 13.3):   26.8.[/color]
  2. [color=Red]return value for sum(3, 11, 2.5, 13.3):  13.3.[/color]
  3. return value for sum(6, 1.1, 2.1, 13.1, 4.1, 5.1, 6.1):  31.6.
复制代码

论坛徽章:
4
白羊座
日期:2013-09-17 21:59:30技术图书徽章
日期:2013-10-12 22:16:03白羊座
日期:2013-10-14 11:01:40双子座
日期:2013-12-17 18:26:39
2 [报告]
发表于 2013-05-11 03:06 |只看该作者
整型和浮点型数据在内存中的存储格式不同。va_list的原理一般是相当于一个指向char*指针,va_start将它初始化为可变参数的起始地址,
va_arg根据第二个参数类型取出数据,并使va_list向前移动第二个参数类型的字节长度或移动到\0后(对于char*)。
你将整型内存数据当作浮点取出,它俩对应的值本身就不同。而你的例子中int和double的字节数也可能不同。
下面是我用gdb查看的内存数据(32位系统):
1. s = sum(3, 11.0, 2.5, 13.3);
  1. 0xbffff180:        0x00000003        0x00000000        0x40260000        0x00000000
  2. 0xbffff190:        0x40040000        0x9999999a        0x402a9999        0x4a0200e3
  3. 0xbffff1a0:        0x4a19a384        0x08049920        0x00000001        0x08048309
复制代码
2.sum(3, 11, 2.5, 13.3);
  1. 0xbffff180:        0x00000003        0x0000000b        0x00000000        0x40040000
  2. 0xbffff190:        0x9999999a        0x402a9999        0x402a9999        0x4a0200e3
  3. 0xbffff1a0:        0x4a19a384        0x08049920        0x00000001        0x08048309
复制代码

论坛徽章:
4
白羊座
日期:2013-09-17 21:59:30技术图书徽章
日期:2013-10-12 22:16:03白羊座
日期:2013-10-14 11:01:40双子座
日期:2013-12-17 18:26:39
3 [报告]
发表于 2013-05-11 03:15 |只看该作者
接上,
1. 最开始四个字节为3,接着8字节为浮点11,8字节浮点2.5,8字节浮点13.300000000000001。
2. 四字节3, 四字节11, 8字节浮点2.5, 8字节浮点13.300000000000001。
将第二个当浮点读后为: 四字节3, 8字节浮点5.434722104253712e-323, 8字节浮点-2.353438280142842e-185, 8字节浮点13.299997334671206。

注:编译环境gcc (GCC) 4.6.3 20120306 (Red Hat 4.6.3-2)。

论坛徽章:
0
4 [报告]
发表于 2013-05-11 12:52 |只看该作者
回复 2# 井蛙夏虫

C语言在存储数据的时候,会把不带小数点的11认为是整形数,只有带小数点的11.0才会认为是浮点数吗?必须在存储之前显式地强制把11转换为浮点数才行吗?

论坛徽章:
36
CU大牛徽章
日期:2013-09-18 15:24:20NBA常规赛纪念章
日期:2015-05-04 22:32:03牛市纪念徽章
日期:2015-07-24 12:48:5515-16赛季CBA联赛之辽宁
日期:2016-03-30 09:26:4715-16赛季CBA联赛之北控
日期:2016-03-30 11:26:2315-16赛季CBA联赛之广夏
日期:2016-05-20 15:46:5715-16赛季CBA联赛之吉林
日期:2016-05-24 11:38:0615-16赛季CBA联赛之青岛
日期:2016-05-30 13:41:3215-16赛季CBA联赛之同曦
日期:2016-06-23 16:41:052015年亚洲杯之巴林
日期:2015-02-03 15:05:04CU大牛徽章
日期:2013-09-18 15:24:52CU十二周年纪念徽章
日期:2013-10-24 15:46:53
5 [报告]
发表于 2013-05-11 12:59 |只看该作者
回复 4# gleerat


    是这样的,要使用浮点数表示,可以在数后面加个f,如11f,或者加上小数如11.0,都是表示的浮点数.
    个人理解浮点数储存的时候能只表示近似值,如0.2在内存中是无法精确表示为0.2的,具体可以参考浮点数的储存格式。

论坛徽章:
4
白羊座
日期:2013-09-17 21:59:30技术图书徽章
日期:2013-10-12 22:16:03白羊座
日期:2013-10-14 11:01:40双子座
日期:2013-12-17 18:26:39
6 [报告]
发表于 2013-05-11 13:00 |只看该作者
这是关于c语言常量类型的问题,11一般默认会被当作int, 11.0一般是double。
你可以用加后缀的方式指明类型,比如11l指明long, 11.0f指明float等。

论坛徽章:
0
7 [报告]
发表于 2013-05-11 13:06 |只看该作者
回复 5# idi0t


谢谢,以后在存储数据前,就要注意考虑需不需要显式地强制转换数据类型了。

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
8 [报告]
发表于 2013-05-11 15:04 |只看该作者
你确定你正确理解了“...”和va_*是怎么工作的么?如果不确定,那就仔细看手册。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP