UVa 11809 Floating-Point Numbers

题目链接

只是用来恢复状态,才做的水题,所以没什么好说的。

观察题目,可以得到

[left( 1 - dfrac{1}{2^{M + 1}} ight) imes 2^{2^E - 1} = A imes 10^B ]

但是等式两边的值太大了,不好求值,于是我们可以取对数。

[lg left(1 - dfrac{1}{2^{M + 1}} ight) + (2^E - 1) lg 2 = lg A + B ]

然而取对数之后算出来结果太小,误差很大,AC不了。所以我们还要用些其他技巧。

设式子左边的值为 (res),则 (10^{res} = C imes 10^D) ,其中 (0 < C < 10)
显然 (0 < lg C < 1),所以 (D = lfloor res floor) , $ C = 10 ^ {res - D}$ 。
比较一下 (A)(C)(B)(D) 即可。

顺带一提,记得用sscanf输入,注意$ eps $ 不能取太小,$ 10^{-4} $ 即可。

#include <cstdio>
#include <cstring>
#include <cmath>

#define MAX_M (9 + 5)
#define MAX_E (30 + 5)

using namespace std;

const double eps = 1e-4;
const double lg2 = log10(2);
double A;
int B;
int b[MAX_M][MAX_E];
double a[MAX_M][MAX_E];
char s[100];

int main()
{
	double res;
	for (int M = 0; M <= 9; ++M)
	{
		for (int E = 1; E <= 30; ++E)
		{
			res = log10(1.0 - 1.0 / (1 << M + 1)) + ((1 << E) - 1) * lg2;
			b[M][E] = (int)res;
			a[M][E] = pow(10, res - b[M][E]);
		}
	}
	while (scanf("%s", s))
	{
		*strchr(s, 'e') = ' ';
		sscanf(s, "%lf %d", &A, &B);
		if (!A && !B) break;
		for (int M = 0; M <= 9; ++M)
		{
			for (int E = 1; E <= 30; ++E)
			{
				if (b[M][E] != B || a[M][E] - A > eps || a[M][E] - A < -eps) continue;
				printf("%d %d
", M, E);
				goto NEXT;
			}
		}
		NEXT:;
	}
	return 0;
}
原文地址:https://www.cnblogs.com/kcn999/p/13195145.html