算典03_习题_12_UVA-11809

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值