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