您的位置:首页 > 理论基础

C++中输出设置有效位和计算机中浮点数的保存问题

2013-09-24 22:46 393 查看
Google Code Jam上的第二题是“Captain Hammer”问题。

具体描述如下:

Problem

The Hamjet is a true marvel of aircraft engineering. It is a jet airplane with a single engine so powerful that it burns all of its fuel instantly during takeoff. The Hamjet doesn't have any wings because
who needs them when the fuselage is made of a special Wonderflonium isotope that makes it impervious to harm.
Piloting the Hamjet is a not a job for your typical, meek-bodied superhero. That's why the Hamjet belongs to Captain Hammer, who is himself impervious to harm. The G-forces that the pilot endures when
taking a trip in the Hamjet are legen-dary.
The Hamjet takes off at an angle of θ degrees up and a speed of V meters per second. Vis a fixed value that is determined by the awesome power of the Hamjet engine and
the capacity of its fuel tank. The destination is D meters away. Your job is to program the Hamjet's computer to calculate θ given V and D.
Fortunately, the Hamjet's Wondeflonium hull is impervious to air friction. Even more fortunately, the Hamjet doesn't fly too far or too high, so you can assume that the Earth is flat, and that the acceleration
due to gravity is a constant 9.8 m/s2 down.

Input

The first line of the input gives the number of test cases, T. T lines follow. Each line will contain two positive integers -- V and D.

Output

For each test case, output one line containing "Case #x: θ", where x is the case number (starting from 1) and θ is in degrees up from the the horizontal. If there are several possible answers, output the
smallest positive one.
An answer will be considered correct if it is within 10-6 of the exact answer, in absolute or relative error. See the FAQ for
an explanation of what that means, and what formats of floating-point numbers we accept.

Limits

1 ≤ T ≤ 4500;

1 ≤ V ≤ 300;

1 ≤ D ≤ 10000;

It is guaranteed that each test case will be solvable.

Sample



这道题乍看起来,好像挺简单的,是一个简单的高中物理题,但是其实坑还蛮多的,试验了好多次(囧)。

首先,有精度问题需要考虑,C++中如何设置输出数据的精度,不是经常接触到的,还需要查看一些文档。

具体的设置方法为:

cout.setf(ios::fixed);
cout.precision(7);
cout << theta2 << endl;
cout.unsetf(ios::fixed);


其中,setf表示要设置cout的一些format flag(具体参考http://www.cplusplus.com/reference/ios/ios_base/setf/),这里我们只需要开启固定精度,然后就利用precision方法设置精度为7位,最后将刚刚设定的format flag复位。如果不先利用setf置位,precision是不起作用的!

还有就是由于计算机中浮点数保存的时候是不一定就是浮点本身(有一个近似,因为转换为2进制时,有可能是无限循环小数),例如1.2在计算机中保存的就是1.19999999999999995559,1445*9.8/(119*119)得到的结果就是“1.00000000000000022204”(9.8保存的是9.80000000000000071054)。这就会导致“0有可能不是0”,而是一个非常接近0的小数(可能为正,可能为负)。一般情况下,没什么问题,但是对一些特殊的运算,例如取平方根,“负0”就可能会导致结果为“-nan”。这道题中给出的测试用例中就会出现这样的问题,所以在取平方根时要判断是不是“负0”的情况。

具体代码如下:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>

using namespace std;

#define PI 3.14159

int main()
{
int T = 0;
cin >> T;

double V = 0.0, D = 0.0;
double g = 9.8;
double theta1 = 0.0;
double theta2 = 0.0;
for(int i = 0; i < T; i++)
{
cin >> V >> D;
double tmp = g*D/(V*V);
// cout << "xxxxxxxxxxxx" << V << "\t" << D << "\t" << tmp << endl;
double b = sqrt(1 + tmp);
double ac = 0.0;
if(1 - tmp < 1e-6 && 1 - tmp > -1e-6)
{
ac = 0.0;
}
else
{
ac = sqrt(1 - tmp);
}
theta1 = asin((b + ac)/2)*180.0/M_PI;
theta2 = asin((b - ac)/2)*180.0/M_PI;
// cout << "xxxxxxxxxxxx" << V << "\t" << D << "\t" << 1 - tmp << endl;

if(theta1 > 0 && theta2 > 0)
{
if(theta1 > theta2)
{
cout << "Case #" << i + 1 << ": ";
cout.setf(ios::fixed);
cout.precision(7);
cout << theta2 << endl;
cout.unsetf(ios::fixed);
}
else
{
cout << "Case #" << i + 1 << ": ";
cout.setf(ios::fixed);
cout.precision(7);
cout << theta1 << endl;
cout.unsetf(ios::fixed);
}
}
else
{
if(theta1 > theta2)
{
cout << "Case #" << i + 1 << ": ";
cout.setf(ios::fixed);
cout.precision(7);
cout << theta1 << endl;
cout.unsetf(ios::fixed);
}
else
{
cout << "Case #" << i + 1 << ": ";
cout.setf(ios::fixed);
cout.precision(7);
cout << theta2 << endl;
cout.unsetf(ios::fixed);

}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: