鱼C论坛

 找回密码
 立即注册

[技术交流] C语言谜题系列1

  [复制链接]
 楼主| 发表于 2011-7-29 20:29:13 | 显示全部楼层
另一个潜在的问题是:按照你原来的逻辑,++f和f的值一样,那么f和f+50的值也一样,即
08.for(f=start;f<start+50;++f,flag++)
测试条件f<start+50应该不成立,所以不应该执行循环,可为什么还是执行循环了?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2011-7-29 20:55:54 | 显示全部楼层

这个就牵涉到关系运算是怎样运算了。假设f=start,f2=start;
在VC++编译器上,如果先让f2加上50,然后做f<f2。这个结果是假的。
但是,让f,f2直接做(f<f2+50),这样的结果是却真的。
况且(start+50)这是一数据个整形的数据。结果依然是20亿零50。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2011-8-1 15:39:06 | 显示全部楼层
结果不是很确定的,已经超过int的范围了,不同的环境会有不同的值
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2011-8-2 21:44:21 | 显示全部楼层
这几天临时有一些事,忙死了,现在才来公布答案,对不起各位了。
      首先要说明的是,对于一个很大的float类型的数f,++f或者f+50,值还是f,因为浮点数本身就只是近似表示,事实事实上,浮点数是用一种类似科学计数法的形式记录数据的(学名叫IEEE754),即只记录尾数和指数。所以当尾数很长的时候,就只记录高位的尾数忽略低位的尾数。所以2000000001表示为2.000000001+10^9由于尾数太长,所以尾数中的1将被省略,表示为形如2.000000+10^9(为了说明方便,我仅用10进制来说明,不具体列举IEEE754规范了,涉及太多的无关概念)。
      关于这一点,我们可以写程序验证如下:
  1. #include<stdio.h>
  2. int main(){
  3.         float f = 2000000000;
  4.         unsigned int *pi = (unsigned int *)&f;
  5.         printf("f =\t%x\n",*pi);       
  6.         ++f;
  7.         printf("f+1 =\t%x\n",*pi);
  8.         f+=50;
  9.         printf("f+50 =\t%x\n",*pi);
  10. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2011-8-2 21:47:47 | 显示全部楼层
    那么有人要问了,按照这个逻辑,原题中的循环for(f=start;f<start+50;++f)
循环条件f<start+50并不满足,为什么居然会进入死循环呢?首先,能够认为这个循环不应该进行就是一个很大的进步,我把原题的程序稍作修改如下:
  1. #include<stdio.h>
  2. int main( void ){
  3.   int start = 2000000000;
  4.   int count=0;
  5.   float f,d=start+50;
  6.   for(f=start;f<d;++f)
  7.     count++;
  8.   printf("%d\n",count);
  9.   return 0;
  10. }
复制代码
那么这个程序就一次循环也不会进行。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2011-8-2 21:54:32 | 显示全部楼层
      最后,关于上面的写法和原题的区别在于,原题for(f=start;f<start+50;++f)中的start+50是个常量,为了和f比较,首先要转换为float类型(32位),然而这个转换的结果并没有保存到什么float变量中,一般的C编译器为了优化会将该结果直接保存到CPU一个特殊的浮点数寄存器内(该寄存器有80个2进制位,而正统的float只有32个2进制位),所以该浮点数寄存器可以表示f+50的准确值,所以程序进入循环,又因为++f后f不能区分f和f+1,从而程序进入死循环。
      这个例子告诉我们:
1.不要随便对浮点数使用++运算符
2.浮点数的表示一般来说是不精确的
3.一个很大的浮点数+一个很小的数,结果往往还等于那个很大的浮点数(俗称“大数吃小数”)。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2011-8-6 03:05:39 | 显示全部楼层
精度啊精度
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-6-1 23:00:26 | 显示全部楼层
感益{:1_1:}{:1_1:}良多
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-21 14:59:13 | 显示全部楼层
count加1后,f加1;这样循环50次。仰光,为什么要把f定义为float型呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-21 15:05:19 | 显示全部楼层
呵呵,本来想放下的了,但看到LZ的回复,便忍不住再想了想这段代码。虽然我学c不久,但现在我肯定这个问题是出在这两种数据的不同的储存方式引发的。我自己写了些代码来测试发现float的2000000000和2000000050是等大的,我就查了下资料,又知道了单精度浮点数最多的十进制数的有效数字只有7位,超出的会四舍五入(也不知道这个和编译器有没关系),所以便会出现了我昨晚所说的情况,f一直小于start+50;则没有输出。呵呵,即使没答对,我还是学会到了许多东西,哈哈哈
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-21 15:24:27 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-21 15:26:53 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-21 15:41:38 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-21 15:54:25 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-21 16:12:36 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-21 16:21:02 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-21 17:19:48 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-21 17:20:41 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-21 17:25:06 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-1-21 17:25:38 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-25 21:12

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表