仰望天上的光 发表于 2011-7-29 20:29:13

另一个潜在的问题是:按照你原来的逻辑,++f和f的值一样,那么f和f+50的值也一样,即
08.for(f=start;f<start+50;++f,flag++)
测试条件f<start+50应该不成立,所以不应该执行循环,可为什么还是执行循环了?

sinner 发表于 2011-7-29 20:55:54

仰望天上的光 发表于 2011-7-29 20:29 static/image/common/back.gif
另一个潜在的问题是:按照你原来的逻辑,++f和f的值一样,那么f和f+50的值也一样,即
08.for(f=start;f

这个就牵涉到关系运算是怎样运算了。假设f=start,f2=start;
在VC++编译器上,如果先让f2加上50,然后做f<f2。这个结果是假的。
但是,让f,f2直接做(f<f2+50),这样的结果是却真的。
况且(start+50)这是一数据个整形的数据。结果依然是20亿零50。

trbrcdut 发表于 2011-8-1 15:39:06

结果不是很确定的,已经超过int的范围了,不同的环境会有不同的值

仰望天上的光 发表于 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规范了,涉及太多的无关概念)。
      关于这一点,我们可以写程序验证如下:#include<stdio.h>
int main(){
        float f = 2000000000;
        unsigned int *pi = (unsigned int *)&f;
        printf("f =\t%x\n",*pi);       
        ++f;
        printf("f+1 =\t%x\n",*pi);
        f+=50;
        printf("f+50 =\t%x\n",*pi);
}

仰望天上的光 发表于 2011-8-2 21:47:47

    那么有人要问了,按照这个逻辑,原题中的循环for(f=start;f<start+50;++f)
循环条件f<start+50并不满足,为什么居然会进入死循环呢?首先,能够认为这个循环不应该进行就是一个很大的进步,我把原题的程序稍作修改如下:#include<stdio.h>
int main( void ){
int start = 2000000000;
int count=0;
float f,d=start+50;
for(f=start;f<d;++f)
    count++;
printf("%d\n",count);
return 0;
}那么这个程序就一次循环也不会进行。

仰望天上的光 发表于 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.一个很大的浮点数+一个很小的数,结果往往还等于那个很大的浮点数(俗称“大数吃小数”)。

rainymay 发表于 2011-8-6 03:05:39

精度啊精度

faly 发表于 2013-6-1 23:00:26

感益{:1_1:}{:1_1:}良多

key2046 发表于 2017-1-21 14:59:13

count加1后,f加1;这样循环50次。仰光,为什么要把f定义为float型呢?

key2046 发表于 2017-1-21 15:05:19

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

key2046 发表于 2017-1-21 15:24:27

{:5_91:}

key2046 发表于 2017-1-21 15:26:53

{:5_109:}{:10_249:}{:10_281:}

key2046 发表于 2017-1-21 15:41:38

{:10_251:}

key2046 发表于 2017-1-21 15:54:25

{:10_280:}

key2046 发表于 2017-1-21 16:12:36

{:10_251:}

key2046 发表于 2017-1-21 16:21:02

{:10_247:}

key2046 发表于 2017-1-21 17:19:48

{:10_256:}

key2046 发表于 2017-1-21 17:20:41

{:10_249:}{:10_254:}

key2046 发表于 2017-1-21 17:25:06

{:10_245:}{:10_279:}{:10_261:}{:10_280:}{:10_269:}

key2046 发表于 2017-1-21 17:25:38

{:5_90:}{:5_93:}
页: 1 [2] 3
查看完整版本: C语言谜题系列1