浮点数(UVa11809)题解

浮点数(UVa11809)题解

如题


计算机常用阶码-尾数的形式保存浮点数。如下所示,若阶码有6位,尾数有8位,可以表达的最大的浮点数为0.1111111112 * 2 ^ 1111112。注意小数点后一位必须有1,所以一共有9位小数。

0111111110111111

这个数换算成十进制之后就是0.998046875 * 2^63 = 9.205357638345294 * 10^18。你的任务是根据这个最大浮点数,求出阶码的位数E和尾数的位数M。输入格式AeB,表示最大浮点数A * 10^B。0 < A < 10,并且恰好包括15位有效数字。输入结束标志为0e0。对于每组数据,输出ME。输入保证有为一街,且0 <= M <= 9,1 <= E <= 30.


​ 该题的输入AeB十分奇怪,数与数之间插入了字母,那么我们选择先用字符数组读入,再进行处理:

char n[MAXN]; double a,b; fgets(n,n + 60,stdin);//注意,fgets会读入最后的换行符,处理需谨慎 int p = 0; while(n[p] != 'e' && n[p] != '\0')p++; a[p] = ' '; sscanf(n,"%lf%lf",a,b);//将a,b从n里面读入(e已被换成空格),同样,也有sprintf

​ 既然是关于二进制转换的,那么首先就写一个二进制转换代码。但是:对于每一个二进制小数,有一个唯一确定的十进制小数,但对于一个十进制小数,其算出的二进制小数一般都具有误差!!(具体参见十进制转二进制计算方法)

​ 因此,从十进制推二进制的路就走不通了。鉴于此题ME的取值范围不算太大,那么,尝试二进制推十进制?

基本思路:

​ 枚举ME的大小,即尾数的尾数和阶码的位数。通过这样,我们就可以算出对于每一对ME所唯一确定的十进制最大小数,进而与AeB进行比较,选择差距最小的进行输出。

ME的枚举代码如下:

double m[10] = {0.5},k = 0.5;//当m = 0的时候,其实仍有一位小数(参见题目),因此m[0] = 0.5 double e[40] = for(int i = 1; i <= 9; i++){ m[i] = m[i - 1] + k / 2;//二进制小数化十进制 k /= 2; } int c = 2; for(int i = 1; i <= 30; i++){ e[i] = c - 1; c *= 2; }

​ 乍看上去,似乎是一个不错的代码。但是忽视了一个问题,E最大为30,那么就会乘上2(230),二的三十次方约为10亿,该数的大小就不用赘述了。因此,这样的思路肯定行不通。那么稍作改进!!!

​ 由题意得:


A * 10B = M*2E


那么两边同时取以10为底的对数,仍相等,并可以显著减小数据量级,即:


log10A * B = log10M * E*log102


对于每个M,E进行如是处理:

double m[10] = {0.5},k = 0.5; double e[40] = for(int i = 1; i <= 9; i++){ m[i] = m[i - 1] + k / 2; k /= 2; } for(int i = 0; i <= 9; i++){ m[i] = log10(m[i]); } int c = 2; for(int i = 1; i <= 30; i++){ e[i] = (c - 1) * log10(2);//此步认真理解 c *= 2; }

如此过后,再进行比对,记录答案

全代码:

#include<bits/stdc++.h> using namespace std; const int MAXN = 60; char s[MAXN]; double ans[MAXN][MAXN]; double a; double b; void in(){ double m[15] = {0.5},e[30]; long long k = 2; double t = 0.5; for(int i = 1; i <= 9; i++){ m[i] = m[i - 1] + t / 2; //cout << m[i] << " "; t /= 2; } //cout << endl; for(int i = 0; i <= 9; i++){ m[i] = log10(m[i]); } for(int i = 1; i <= 30; i++){ e[i] = (k - 1) * log10(2); k <<= 1; //printf("%lf\n",e[i]); } for(int i = 0;i <= 9; i++){ for(int j = 1; j <= 30; j++){ ans[i][j] = m[i] + e[j]; } } } int main(){ in(); while(fgets(s,MAXN,stdin)){ if(strncmp(s,"0e0",3) == 0)break;//strncmp可以选择比对前多少位 int p = 0; while(s[p] != 'e' && s[p] != '\0')p++; s[p] = ' '; sscanf(s,"%lf %lf",&a,&b); b = a = log10(a) + b;//对原数取对数 int pi = 0,pj = 1; for(int i = 0; i <= 9; i++){ for(int j = 1; j <= 30; j++){ if(fabs(a - ans[i][j]) < b){ b = fabs(a - ans[i][j]); pi = i; pj = j; } } } cout << pi << " " << pj << endl; } }

(终)


__EOF__

本文作者Never Gonna Give You Up!
本文链接https://www.cnblogs.com/CZ-9/p/16435661.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   腾云今天首飞了吗  阅读(160)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示