今天,一如既往的训练c语言题,按照顺序,做到了14届蓝桥杯第三题,是一个关于近似值的问题,有点儿难度,尽管一上来我就有了思路,但是不得不承认,我想的办法不是最麻烦的,但是也够麻烦的了。题如下:
如果x的x次幂结果为10,你能计算出x的近似值吗?
显然,这个值是介于2和3之间的一个数字。
请把x的值计算到小数后6位(四舍五入),并填写这个小数值。
注意:只填写一个小数,不要写任何多余的符号或说明。
第一想法,很直观,就是用递归,函数嵌套在一起,最终得到需要的值,但是思路是有了,但是做后却无法正确输出,当然思路没问题,于是仔细看看代码,还是自己的定义的范围的问题(因为为了追求代码的高利用率,每次定义数据类型我总是追求刚好够用,杜绝浪费,于是作为新手的我总是出现这些小问题),另外旱出现一个弱智的问题,就是计数变量使用重复了,于是改动后,运算结果基本正确,这是我注意到一个问题,要求是四舍五入保留六位小数,而不是直接取整,于是我卡壳了,怎么破怎么破怎么破?心中默念三句咒语,果然不出所料,还是没想到破解办法,于是,呵呵,度娘,帮帮我。百度后,只找到了四舍五入保留整数部分的方法,因为c语言没有办法直接判别究竟是四舍还是五入,如是需要借助“0.5”来帮忙,加上0.5后取整即可,于是举一反三的我轻松的改动了部分解决了保留六位的办法。经过几番调试后,结果总算是正常了,并且每个数据类型都定义到刚刚好,不得不说我是个拮据的人,不想浪费内存。为此,我专门又查了查float型和double型表示的有效数字范围,float型可以表示6到7个有效数字,而double型可以表示15到16位有效数字,另外math函数库的内容也需要多加熟悉,代码如是矣:
#include <stdio.h>
#include <math.h>
double JinSiZhi=0;
int main(int argc, const char * argv[])
{
double Jin_Si_Zhi(int j);
float JSZ=0;
JSZ=(int)(Jin_Si_Zhi(1)*1000000+0.5);
JSZ=JSZ/1000000;
printf("%f\n",JSZ);
return 0;
}
double Jin_Si_Zhi(int j)
{
if (j<9)
{
for (int i=0; i<10; i++)
{
JinSiZhi=JinSiZhi+i/pow(10, j-1);
if (pow(JinSiZhi, JinSiZhi)>10)
{
JinSiZhi=JinSiZhi-1/pow(10, j-1);
Jin_Si_Zhi(j+1);
break;
}
JinSiZhi=JinSiZhi-i/pow(10, j-1);
}
}
return JinSiZhi;
}
做过这道题后,我并不满足于成功编译了这么简单,想要找一个更为简单的方法去解决它,于是辗转反侧终于想到了“二分法”,但是有了方向,但是没有具体的实施办法,于是没办法,我又去温习了一遍曾经的“二分法”,毕竟忘了具体的方法是做不出题的,寂静斟酌后,总算有所收获,简单的说涉及到三个变量:近似值下限,近似值上限以及中间值,可是我怎么才能让他循环分割并适时停止呢?没办法,我只好又去找度娘了,度娘告诉我:“小孩子,你要学的还有很多……努力学吧!”然后给了我一个宏,让我利用这个宏去做限定,这个宏是“1e-8”,好吧,我又不懂了,这都是啥玩意?于是我厚脸皮的又去百度了这个宏,明白了,他是表示1/100000000,经过度娘的提示,我最终想通了办法并作了出来,当然输出时的四舍五入的办法和上面的办法是一致的,经过最后的斟酌,我认为根本没必要“1e-8”,因为我系要保留六位小数,所以先求到七位就够了,保留的过多会导致循环次数增加过多,得不偿失,于是我就将“1e-8”改为了“1e-7”,终于,一切都正常编译了,并且达到了我目前认为的满意程度(因为我目前学识尚浅,有些地方还不知道怎么改会简化),经过整理,代码如下:
#include<stdio.h>
#include<math.h>
#define eps 1e-7
int main()
{
double l=2,r=3,mid=0;
float JSZ=0;
while(l+eps<r)
{
mid=(l+r)/2;
if(pow(mid,mid)<10)
{
l=mid;
}
else
{
r=mid;
}
}
JSZ=(int)(l*1000000+0.5);
JSZ=JSZ/1000000;
printf("%f\n",JSZ);
return 0;
}
经过今天的垂死挣扎,总算是解决了这两道题,不对,是一道题两种解法,做题做失迷了,��,倍感欣慰,因为感觉自己每天都没有止步不前,我要继续努力,蓝桥杯a组才是我的第一个目标!