算法竞赛入门经典(紫书)第三章——Floating-Point Numbers UVA-11809

题意:
题目介绍了浮点数存储的方法,尾数有 M 位,阶码有 E 位,还有两位符号位分别表示尾数的符号和阶码的符号。现在给出对应一种 M 和 E 的能够表示的最大数,要求判断出 M 和 E 的值,其中 M 属于 (0, 9),E 属于 (1, 30)。

思路:
题目的 Input 中说有 300 行输入,且 M 属于 (0, 9),E 属于 (1, 30),刚好有 300 种情况,我们会去朝着打表的方向去想。
我们先将对应 M 和 E 的浮点数最大值求出来,如下图,浮点数最大值的二进制形式应该是这样的。

换算成十进制的数应该是
(2M+11)×22EM2 ( 2 M + 1 − 1 ) × 2 2 E − M − 2
=2M+1×22EM222EM2 = 2 M + 1 × 2 2 E − M − 2 − 2 2 E − M − 2
=22E122EM2 = 2 2 E − 1 − 2 2 E − M − 2
=22E1×(12M1) = 2 2 E − 1 × ( 1 − 2 − M − 1 )

又 题目的输入是 A×10B A × 10 B ,所以有
A×10B=22E1×(12M1) A × 10 B = 2 2 E − 1 × ( 1 − 2 − M − 1 )

我们希望的是事先通过打表算出上面等式的右边部分,然后和输入的数据,即左边部分进行比较找到 A 和 B。
但是现在的左边部分太大了,比如样例一就有 10 的 76 次方多了,所以还得另想办法。
用数学的办法,我们将等式两边取对数,得到
lgA+B=lg22E1+lg(12M1) l g A + B = l g 2 2 E − 1 + l g ( 1 − 2 − M − 1 )
lgA+B=(2E1)×lg2+lg(12M1) ⇒ 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值