C语言中float和double的精度

来源:互联网 发布:hadoop和云计算 编辑:程序博客网 时间:2024/05/16 19:24

助教给小伙伴们调实验的时候,碰到一个求矩阵面积交的问题,问题如下,并不复杂。

问题描述 平面上有两个矩形,它们的边平行于直角坐标系的X轴或Y轴。对于每个矩形,我们给出它的一对相对顶点的坐标,请你编程算出两个矩形的交的面积。输入格式 输入仅包含两行,每行描述一个矩形。  在每行中,给出矩形的一对相对顶点的坐标,每个点的坐标都用两个绝对值不超过10^7的实数表示。 输出格式 输出仅包含一个实数,为交的面积,保留到小数后两位。 样例输入 1 1 3 3 2 2 4 4 样例输出 1.00
我的思路是首先求出两个矩形中心的位置,根据两个矩形中心的位置,结合矩形的长宽(这里实际上用的是长宽的一半),很容易求得矩形相交部分的面积。程序如下:

#include <stdio.h>#include <math.h>int main(){//分别用abcd和a1b1c1d1来接收矩形的相对顶点坐标//     double a,b,c,d;//     double a1,b1,c1,d1;//     //     scanf("%lf%lf%lf%lf",&a,&b,&c,&d);//     scanf("%lf%lf%lf%lf",&a1,&b1,&c1,&d1);float a,b,c,d;float a1,b1,c1,d1; scanf("%f%f%f%f",&a,&b,&c,&d);scanf("%f%f%f%f",&a1,&b1,&c1,&d1);//x,y和x1,y1分别表示矩形中心的坐标    double x=fabs(c-a)/2.0,y=fabs(d-b)/2.0;    double x1=fabs(c1-a1)/2.0,y1=fabs(d1-b1)/2.0;//xx,yy和xx1,yy1分别表示矩形的长宽的一半    double xx=(a+c)/2.0,yy=(b+d)/2.0;    double xx1=(a1+c1)/2.0,yy1=(b1+d1)/2.0;//xxx和yyy表示两个矩形中心的横纵距离    double xxx=fabs(xx-xx1),yyy=fabs(yy-yy1);    if (x1+x<=xxx || y+y1<=yyy)    {        printf("%.2f\n",0.000);    }    else    {        double height=fabs(y1+y-yyy);        double width=fabs(x1+x-xxx);if (height > (y > y1 ? y1*2 : y*2))height=(y > y1 ? y1*2 : y*2);if (width > (x > x1 ? x1*2 : x*2)){width=(x > x1 ? x1*2 : x*2);}        printf("%.2lf\n",height*width);    }    return 0;}
结果运行之后,有一组用例总是不过。通过某种不怎么光彩的手段,我知道,那组用例的输入数据如下:

283323.2393 2938832.3994 29838432.38288 983723.828
27783.84384 8793002.2 3995852.3884 2928344.2
没头没脑地把接收输入的变量的类型改成了double,程序如下:

#include <stdio.h>#include <math.h>int main(){//分别用abcd和a1b1c1d1来接收矩形的相对顶点坐标    double a,b,c,d;    double a1,b1,c1,d1;        scanf("%lf%lf%lf%lf",&a,&b,&c,&d);    scanf("%lf%lf%lf%lf",&a1,&b1,&c1,&d1);// float a,b,c,d;// float a1,b1,c1,d1;//  // scanf("%f%f%f%f",&a,&b,&c,&d);// scanf("%f%f%f%f",&a1,&b1,&c1,&d1);//x,y和x1,y1分别表示矩形中心的坐标    double x=fabs(c-a)/2.0,y=fabs(d-b)/2.0;    double x1=fabs(c1-a1)/2.0,y1=fabs(d1-b1)/2.0;//xx,yy和xx1,yy1分别表示矩形的长宽的一半    double xx=(a+c)/2.0,yy=(b+d)/2.0;    double xx1=(a1+c1)/2.0,yy1=(b1+d1)/2.0;//xxx和yyy表示两个矩形中心的横纵距离    double xxx=fabs(xx-xx1),yyy=fabs(yy-yy1);    if (x1+x<=xxx || y+y1<=yyy)    {        printf("%.2f\n",0.000);    }    else    {        double height=fabs(y1+y-yyy);        double width=fabs(x1+x-xxx);if (height > (y > y1 ? y1*2 : y*2))height=(y > y1 ? y1*2 : y*2);if (width > (x > x1 ? x1*2 : x*2)){width=(x > x1 ? x1*2 : x*2);}        printf("%.2lf\n",height*width);    }    return 0;}
程序居然神奇地过了。于是,想到可能是精度问题,调试了一下,记录下各个变量的值如下:


大致可以看出,float的精度貌似只能到6位有效数字。google到一篇解释double和float精度这个问题的博客,很详细,文章中将32位的float和64位的double如何存储说的很清楚,下面将相关的内容贴在下面。

1、范围
  float和double的范围是由指数的位数来决定的。
  float的指数位有8位,而double的指数位有11位,分布如下:
  float:
  1bit(符号位) 8bits(指数位) 23bits(尾数位)
  double:
  1bit(符号位) 11bits(指数位) 52bits(尾数位)
  于是,float的指数范围为-127~+128,而double的指数范围为-1023~+1024,并且指数位是按补码的形式来划分的。
  其中负指数决定了浮点数所能表达的绝对值最小的非零数;而正指数决定了浮点数所能表达的绝对值最大的数,也即决定了浮点数的取值范围。
  float的范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;double的范围为-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+308。
2、精度
  float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。
  float:2^23 = 8388608,一共七位,这意味着最多能有7位有效数字,但绝对能保证的为6位,也即float的精度为6~7位有效数字;
  double:2^52 = 4503599627370496,一共16位,同理,double的精度为15~16位。

ok,说明白了吧。微笑

参考:

http://www.cnblogs.com/BradMiller/archive/2010/11/25/1887945.html

0 0