Floating-Point Numbers
这题我不会做,参考的大神的思路
传送门
题意
浮点数在计算机里是分三部分表示的
最前面一位表示符号,后面一部分是尾数,最后一部分是阶码
尾数是M,阶码是E的话表示起来就是:
M×2E(12≤M<1) 。
用二进制表示M的话就应该是0.1XX……,(用计算机表示的时候就把最前面的“0.1”给省略掉,只表示可能变化的部分。)
阶码部分则是只用二进制表示E。
例如:
前面的0表示是正数。
后面8位表示尾数M,这里是0.111111111(注意后面是9个1,因为头一个省略了)。
之后那个0表示分割
最后面6位表示E的二进制为111111。
所以这个数就是
0.1111111112∗21111112
用十进制表示就是
0.998046875∗263=920535763834529382410
在计算机中用二进制表示M和E的时候如果位数不同,那么它们所能表示的最大值也不同。现在给你所能够表示的最大的浮点数的值,让你倒回去求M和E分别有多少位。
输入格式为AeB,表示最大浮点数为,并且0 < A < 10,并且保证输出的结果中0 ≤ M ≤ 9且1 ≤ E ≤ 30。输入以0e0表示结束,0e0本身不计算。(这里的M,E表示位数)
题解
可以看出,在本题中如果将一个十进制转换成二进制的话,那是极其不容易的,但是如果将一个二进制转成十进制,那还是可以尝试一下的
另一方面来说,M和E的范围都很小,而且都是整数,那么自然就想到打表了,我们不妨枚举所有的M和E,将其对应的最大值记录下来
因为这里M和E为位数,我们不妨设m和e为其对应的尾数和阶,即为
m×2e(12≤m<1)
那么根据前面的例子我们能得出m,e和M,E的关系:
m=1−2−(M+1)
e=2E−1
这样对我们遍历的每一个M和E,m和e就求出来了
然后我们要通过m和e求出AeB中的A的B(对应着输入格式),即
m×2e=A×10B
这个时候直接算肯定是不可行的,因为e本身的值就是2的指数(最大1073741823),而它又要作为2的指数
我就是做到这里卡住了,看了大神的博客恍然大悟,只要取个对数就可以了,这是整个题目的关键,取完对数之后(对10取对数):
log10m+e∗log102=log10A+B
由于m,e是已知的,所以左边是已知的,不妨设为t,最后我们得到
t=log10A+B
由前面A的范围我们知道 log10A<1 那么B就是t的整数部分,A就是t的小数部分了,即
B=(int)t
A=10t−B
至此便求出A和B了
#include <iostream>
#include <sstream>
#include <string>
#include <cmath>
using namespace std;
int main() {
double M[20][40];
long long E[20][40];
for(int i = 0; i <= 9; ++i) for(int j = 1; j <= 30; ++j) {
double m = 1 - pow(2, -1 - i), e = pow(2, j) - 1;
double t = log10(m) + e * log10(2);
E[i][j] = t, M[i][j] = pow(10, t - E[i][j]);
}
string in;
while(cin >> in && in != "0e0") {
for(string::iterator i = in.begin(); i != in.end(); ++i) if(*i == 'e') *i = ' ';
istringstream ss(in);
double A; int B;
ss >> A >> B;
while(A < 1) A *= 10, B -= 1;
for(int i = 0; i <= 9; ++i) for(int j = 1; j <= 30; ++j) {
if(B == E[i][j] && (fabs(A - M[i][j]) < 1e-4 || fabs(A / 10 - M[i][j]) < 1e-4)) {
cout << i << ' ' << j << endl;
break;
}
}
}
}