算典03_习题_12_UVA-11809

来源:互联网 发布:手机淘宝客户端软件 编辑:程序博客网 时间:2024/04/30 23:13

Floating-Point Numbers

这题我不会做,参考的大神的思路

传送门

题意

浮点数在计算机里是分三部分表示的
最前面一位表示符号,后面一部分是尾数,最后一部分是阶码
尾数是M,阶码是E的话表示起来就是:

M×2E12M<1

用二进制表示M的话就应该是0.1XX……,(用计算机表示的时候就把最前面的“0.1”给省略掉,只表示可能变化的部分。)
阶码部分则是只用二进制表示E。
例如:

这里写图片描述
前面的0表示是正数。
后面8位表示尾数M,这里是0.111111111(注意后面是9个1,因为头一个省略了)。
之后那个0表示分割
最后面6位表示E的二进制为111111。
所以这个数就是

0.111111111221111112

用十进制表示就是
0.998046875263=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×2e12m<1

那么根据前面的例子我们能得出m,e和M,E的关系:

m=12(M+1)
e=2E1

这样对我们遍历的每一个M和E,m和e就求出来了
然后我们要通过m和e求出AeB中的A的B(对应着输入格式),即

m×2e=A×10B

这个时候直接算肯定是不可行的,因为e本身的值就是2的指数(最大1073741823),而它又要作为2的指数
我就是做到这里卡住了,看了大神的博客恍然大悟,只要取个对数就可以了,这是整个题目的关键,取完对数之后(对10取对数):

log10m+elog102=log10A+B

由于m,e是已知的,所以左边是已知的,不妨设为t,最后我们得到

t=log10A+B

由前面A的范围我们知道 log10A<1 那么B就是t的整数部分,A就是t的小数部分了,即

B=(int)t
A=10tB

至此便求出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;            }        }    }}
0 0