今天,不对,准确说是昨天(不知不觉就凌晨了),又做了14届蓝桥杯b组第二题,猛一看,感觉蓝桥杯b组的题不是我的菜,太简单是一个求调和级数的问题,题如下:
1/1 + 1/2 + 1/3 + 1/4 + … 在数学上称为调和级数。
它是发散的,也就是说,只要加上足够多的项,就可以得到任意大的数字。
但是,它发散的很慢:
前1项和达到 1.0
前4项和才超过 2.0
前83项的和才超过 5.0
那么,请你计算一下,要加多少项,才能使得和达到或超过 15.0 呢?
请填写这个整数。
注意:只需要填写一个整数,不要填写任何多余的内容。比如说明文字。
正确代码如下:
#include <stdio.h>
int main(int argc, const char * argv[])
{
float sum=0;
int i=1;
for (; i<=10000000; i++)
{
sum=sum+1.0/i;
if (sum>=15.0)
{
printf("%d\n",i);
break;
}
}
return 0;
}
一看题感觉没啥含金量,于是随手就做了起来,可是做后一直无法正常运行,搞的我好为难,于是自习审查,发现我一开始将sum和i都定义成了int型,说到int型函数我就要说道说道了,曾经对int型只知道这是个整形函数,但是并没有从本质上研究过他的作用,于是我就去找了度娘。终于,我对int函数有了更深点的理解,int型函数是向下取整函数,例如:int(3.8)=3,int(-3,8)=-4,主体强调的是向下取整。范围[-2^31 , 2^31 -1] 即 [-2147483648,2147483647]。然而这道题涉及到了小数,所以我就顺势将两个都定义成了float型,但是依然无法顺利编译,细细品来(在我看来,代码是艺术,需要品味),发现我犯了一个不经常涉及的小问题,那就是在“1.0/i”我写成了“1/i”,于是知错就改的我及时更正了问题,这是问题又出现了,我再次编译,答案是4(因为我一开始为了检验代码,所以条件语句中条件写的是“sum>=2.0”),正确,于是我就又改成了“sum>=15.0”,奇迹出现了,答案竟然是一串不明字符“1.67386e+06”,顿时我蒙圈了,心里想着怎么破怎么破,此时,我开始理思路,前面的几个都成功,为什么到这里却不行了呢?会不会是答案范围的问题?答案是i,那么会不会是i的范围的问题?i是浮点型……什么,等等,我为啥要用浮点型呢?明明输出的答案都是整形,我却用的浮点型,先不管其是否可以编译成功,就这个情况定义这个类型也不符合代码的规范性啊!于是抱着试一试的心态的我将i改为了int型,奇迹再次出现,编译成功了,结果是“1673859”,正确。虽说这个程序成功了,但是我依然心存疑虑为什么数据一大,用float型就失败了呢?是不是也是数据范围的问题?于是,度娘,我又来了……
问过度娘后,我总算是明白了,浮点数使用 IEEE(电气和电子工程师协会)格式。浮点类型的单精度值具有 4 个字节,包括一个符号位、一个 8 位 excess-127 二进制指数和一个 23 位尾数。尾数表示一个介于 1.0 和 2.0 之间的数。由于尾数的高顺序位始终为 1,因此它不是以数字形式存储的。此表示形式为 float 类型提供了一个大约在 3.4E–38 和 3.4E+38 之间的范围。
范围的问题导致了输出结果的紊乱,看来这道题的含金量也是有的,但主要不是考察我们的算法,而是考察我们的细心程度与对整型和浮点型的认知深度。
真是辛苦出题人了,向出题人致敬!