題目傳送門:UVa 11809:Floating-Point Numbers
這道題弄了幾個小時才AC。首先觀察下題目的輸入輸出:
Input
The input file contains around 300 line of input. Each line contains a floating-point number F that denotes the maximum value that can be represented by a certain floating-point type. The floating point number is expressed in decimal exponent format. So a number AeB actually denotes the value A×10B. A line containing ‘0e0’ terminates input. The value of A will satisfy the constraint 0 < A < 10 and will have exactly 15 digits after the decimal point.
Output
For each line of input produce one line of output. This line contains the value of M and E. You can assume that each of the inputs (except the last one) has a possible and unique solution. You can also assume that inputs will be such that the value of M and E will follow the constraints: 9 ≥ M ≥ 0 and 30 ≥ E ≥ 1. Also there is no need to assume that (M + E + 2) will be a multiple of 8.
Sample Input
5.699141892149156e76
9.205357638345294e18
0e0
Sample Output
5 8
8 6
題目的輸出提到 9 ≥ M ≥ 0 and 30 ≥ E ≥ 1,所以我們可以打表,把尾數二進制位數在 0-9 之間,階碼位數在 1-30 之間的所有最大值都存起來(打表)。
需要注意一點的是,階碼最大的位數爲 30,也就是說指數最大爲 2^30 - 1,所以說 2 的 2^30 - 1 次方會超範圍。
令尾數爲 m,階碼爲 e,輸入中有AeB,則他們有如下關係:
這裏的 e 最大爲 2^30 - 1,會超範圍,所以我們可以對等式兩邊取對數:
等價於:
題目中還提到 0 < A < 10,所以
所以,我們只要保存M和E對應的A和B,然後查表即可。
AC代碼如下:
#include <stdio.h>
#include <string.h>
#include <math.h>
double M[15][35];
int E[15][35];
void init()
{
int i, j;
for (i = 0; i <= 9; ++i)
{
for (j = 1; j <= 30; ++j)
{
long long e = pow(2, j) - 1; // 階碼
double m = 1 - pow(2, -(i+1)); // 尾數
double t = log10(m) + e * log10(2);
E[i][j] = t;
M[i][j] = pow(10, t - E[i][j]);
}
}
}
int main()
{
init();
char str[25];
while (1 == scanf("%s", str))
{
if (0 == strcmp(str, "0e0"))
return 0;
str[17] = ' '; // str[17]是字符e
double a; int b;
sscanf(str, "%lf %d", &a, &b); // 從字符串輸入
int i, j, flag = 0;
for (i = 0; i <= 9; ++i) // 查表
{
for (j = 1; j <= 30; ++j)
{
if (b == E[i][j] && fabs(a - M[i][j]) < 1e-4) // 注意判斷double是否相等時的精度問題
{
printf("%d %d\n", i, j);
flag = 1;
}
if (flag) break;
}
}
}
return 0;
}