C语言计算浮点数的小数位数,屏蔽掉了浮点运算的误差

来源:互联网 发布:ubuntu怎么稳定翻墙 编辑:程序博客网 时间:2024/04/30 01:16

问题是这样的,输入两个浮点数,分别为矩形的width和length,求其面积area,并输出显示。本身这道题是没什么好说的,正常来说,只要 %f 就好,虽然后面的小数位数恒定为6位。但是答题后发现答案是会自动把多余的0去掉的,这样的话就没办法使用%.3f之类的来限定具体的小数位数了。于是这个就需要我们把结果area算出具体的的小数位数n,使用printf("%.*f",n,area);来显示含正确小数位数的浮点数area。


因为一下子没想出来怎么计算小数位数,故而百度之类的搜索了一下,网上流传的的方法,从原理上来讲貌似没有错。找到的方法基本原理都是这样的,对浮点数f*10,然后判断个位数是否非0,如果非0则小数位数n++,直到个位为零,则n为该浮点数f的小数位数。

这里面其实是有两个问题的,导致他没有办法计算出正确的小数位数,甚至出现死循环的现象。

其中问题为:

1.上面的方法没有考虑到小数点后面的数中间含有0的现象,比如说2.120056,这样的话,如果用上述的方法,则会计算出小数位数为2,因为在计算到第位小数时为零,故而退出n的循环。

(这里面网上是有解决方法的,方法为 f - (int)f  > (float)0.000001是否成立,若成立,则小数位数已计算完毕,若不成立,则继续循环。但是这种方法依然会产生下面的2的问题,从而无法结束循环,得不到正确的结果);

2.上面的方法没有考虑到浮点数的相乘是会产生误差的,比如,

f = 2.123456;

s = f*10 ;// 结果为21.234560

s =s*10;//结果为212.2345603

这时就出现了误差0.000003,故而会使程序无法结束循环。


于是思考好久之后,有了以下这种我的解决方法。

首先,我们是知道浮点型float的小数位数是为6位的,所以我们只要一开始就假定area是有6位小数,然后再逆转判断。具体程序如下:

int  float_n(float area)

{

int n = 6;//一开始就假定小数位数为6位

long temp = (int)area * 1000000;//将6位小数全部取出,并舍弃计算后多余的可能是误差的小数部分

for(n = 6; n>0 ;i--)

{

if( 0 != temp %10  ) break;

temp = temp/10;

}

return n;

}


此时,n就是正确的小数位数了。

printf(" area = %.*f \n" , n , area);

可以正确显示去除多于的零的area结果了。


目前我在思考第二种有效的方法,大家知道,所有的数据都是按照二进制存储在内存中的,那么我们是否可以进行位运算 操作,来直接从float的储存格式获得小数的位数呢?

0 0
原创粉丝点击