题意:
题目介绍了浮点数存储的方法,尾数有 M 位,阶码有 E 位,还有两位符号位分别表示尾数的符号和阶码的符号。现在给出对应一种 M 和 E 的能够表示的最大数,要求判断出 M 和 E 的值,其中 M 属于 (0, 9),E 属于 (1, 30)。
思路:
题目的 Input 中说有 300 行输入,且 M 属于 (0, 9),E 属于 (1, 30),刚好有 300 种情况,我们会去朝着打表的方向去想。
我们先将对应 M 和 E 的浮点数最大值求出来,如下图,浮点数最大值的二进制形式应该是这样的。
换算成十进制的数应该是
(2M+1−1)×22E−M−2
(
2
M
+
1
−
1
)
×
2
2
E
−
M
−
2
=2M+1×22E−M−2−22E−M−2
=
2
M
+
1
×
2
2
E
−
M
−
2
−
2
2
E
−
M
−
2
=22E−1−22E−M−2
=
2
2
E
−
1
−
2
2
E
−
M
−
2
=22E−1×(1−2−M−1)
=
2
2
E
−
1
×
(
1
−
2
−
M
−
1
)
又 题目的输入是
A×10B
A
×
10
B
,所以有
A×10B=22E−1×(1−2−M−1)
A
×
10
B
=
2
2
E
−
1
×
(
1
−
2
−
M
−
1
)
我们希望的是事先通过打表算出上面等式的右边部分,然后和输入的数据,即左边部分进行比较找到 A 和 B。
但是现在的左边部分太大了,比如样例一就有 10 的 76 次方多了,所以还得另想办法。
用数学的办法,我们将等式两边取对数,得到
lgA+B=lg22E−1+lg(1−2−M−1)
l
g
A
+
B
=
l
g
2
2
E
−
1
+
l
g
(
1
−
2
−
M
−
1
)
⇒lgA+B=(2E−1)×lg2+lg(1−2−M−1)
⇒
l
g
A
+
B
=
(
2
E
−
1
)
×
l
g
2
+
l
g
(
1
−
2
−
M
−
1
)
有了上面的等式,我们就可以打表啦
注意:
1.如果读取数据时用 double 型读取,读取不到 A 和 B,所以我们选择把输入当成字符串读取,然后处理出 A 和 B。
2. lg 的函数应该是 log10(),不是 log()。log() 函数是 ln。我就在这弄错了。
3. 浮点数的比较要取绝对值然后和较小的一个数比较,这里用的是 1e-4。
代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<stack>
#include<queue>
#include<utility>
#include<vector>
#include<cmath>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
#include<sstream>
using namespace std;
typedef long long LL;
char ch[30];
double A;
double B;
double num[15][35];
int main()
{
//freopen("in.txt", "r", stdin);
//初始化数据
for(int M=0; M<=9; M++){
for(int E=1; E<=30; E++){
num[M][E] = (pow(2, E)-1)*log10(2) + log10(1-pow(2, -M-1));
//printf("M = %d, E = %d, num = %.15lf\n", M, E, num[M][E]);
}
}
while(scanf("%s", ch)==1 && strcmp(ch, "0e0")!=0){
//输入处理
A = B = 0;
int len = strlen(ch);
int i = 0;
for(; ch[i]!='.'; i++){
A *= 10;
A += ch[i]-'0';
}
i++;
for(double w = 1; ch[i]!='e'; i++){
w /= 10;
A += w*(double)(ch[i]-'0');
}
i++;
for(; i<len; i++){
B *= 10;
B += ch[i]-'0';
}
//printf("%.15lfe%.15lf\n", A, B);
double C = B+log10(A);
//printf("C = %.15lf\n", C);
bool ok = false;
for(int i=0; i<=9; i++){
for(int j=1; j<=30; j++){
if(fabs(C-num[i][j]) < 1e-4){
ok = true;
printf("%d %d\n", i, j);
break;
}
}
if(ok) break;
}
}
return 0;
}
想看书上的源代码的话看这 (^▽^)
https://github.com/aoapc-book/aoapc-bac2nd