UVa 11809 Floating-Point Numbers(浮点数)

Description

Download as PDF

Floating-point numbers are represented differently in computers than integers. That is why a 32-bit floating-point number can represent values in the magnitude of 1038 while a 32-bit integer can only represent values as high as 232.

 

Although there are variations in the ways floating-point numbers are stored in Computers, in this problem we will assume that floating-point numbers are stored in the following way:

 


Floating-point numbers have two parts mantissa and exponent. M-bits are allotted for mantissa and E bits are allotted for exponent. There is also one bit that denotes the sign of number (If this bit is 0 then the number is positive and if it is 1 then the number is negative) and another bit that denotes the sign of exponent (If this bit is 0 then exponent is positive otherwise negative). The value of mantissa and exponent together make the value of the floating-point number. If the value of mantissa is m then it maintains the constraints . The left most digit of mantissa must always be 1 to maintain the constraint . So this bit is not stored as it is always 1. So the bits in mantissa actually denote the digits at the right side of decimal point of a binary number (Excluding the digit just to the right of decimal point)

In the figure above we can see a floating-point number where M=8 and E=6. The largest value this floating-point number can represent is (in binary) . The decimal equivalent to this number is: . Given the maximum possible value represented by a certain floating point type, you will have to find how many bits are allotted for mantissa (M) and how many bits are allotted for exponent (E) in that certain type.

 

Input

 

The input file contains around 300 line of input. Each line contains a floating-point number F that denotes the maximum value that can be represented by a certain floating-point type. The floating point number is expressed in decimal exponent format. So a number AeB actually denotes the value . A line containing 0e0 terminates input. The value of A will satisfy the constraint 0<A<10 and will have exactly 15 digits after the decimal point.  

 

Output

For each line of input produce one line of output. This line contains the value of M and E. You can assume that each of the inputs (except the last one) has a possible and unique solution. You can also assume that inputs will be such that the value of M and E will follow the constraints: 9 ≥ M ≥ 0 and 30 ≥ E ≥ 1. Also there is no need to assume that (M+E+2) will be a multiple of 8.

 

Sample Input

Sample Output

5.699141892149156e76

9.205357638345294e18

0e0

5 8

8 6

  


这个题,真的是让自己开始怀疑人生了。。。= =,一开始根本看不明白题的意思,一大堆乱七八糟的小数点,没办法只好把这个题放了两天,各种查资料来看浮点数的存储,根本是很懵(真心不明白存个浮点数就这么麻烦么)。。。

大概题意就是跟你介绍了一下浮点数的二进制存储,分为符号位尾数和阶码,然后给定一个科学计数法的浮点数,求出尾数和阶码所需的最小位数,大概就是这么个意思。。。= =

一开始完全没有思路,想着这东西怎么整。。。而且最眼下的问题是解决输入问题,毕竟他输入的是一个科学计数法表示的一个浮点数,没办法直接拆分,然后就想着手动拆,但突然想到了书上有一个sprintf函数,把输出存到字符数组里,然后就想是不是也有sscanf啊,可以从字符串中读,然后把那个e操作成空格,读进去直接就分割了。百度了一下果然有,果断用它,简单暴力。。

光这个输入就捣鼓了一个多小时,然后就停滞了好长时间还是没思路。然后就去学习了一下浮点数表示法,发现其实还是有规律可循的,就把思路定位为打表匹配,找接近值(因为浮点数自身的误差,所以不可能准确,忘了在哪看过,浮点数不能进行==运算),思路确定好了,问题又来了,有了确定的M,E的范围,但是怎么求他们对应的最大值,这个问题真的快把我搞疯了,没办法,还是要查资料,毕竟不是我发明的浮点数。。= =

最后经多方查阅和学习,终于解决了打表的问题。开两个二维数组M[][],E[][]分别存放对应位数的尾数和阶码的组合时尾数和指数所能表示的最大值,因为指数是整数,所以打表完成后可以通过匹配指数来寻找尾数最接近的那个,只要所求值和表中值的差的绝对值在误差允许的范围内就匹配上了,输出这时候的位置,便是答案。由于浮点数的精度原因,不可能两个数差别特别小,所以对误差的要求不能太苛刻(一开始就把误差定位在1e-10太小了结果就WA,改成1e-4就AC了。。。)

至于怎么根据位数求出可存储的最大数,网上查阅资料得知:

因为位数自带一个1,这个1是不被存储的,所以对于某个a位二进制数的尾数,它的十进制尾数值m=1-2^(-a-1)

对于某个b位二进制数的阶码,可表示的指数为2^e=2^[2^b-1]

然后把这个数转换成对应的以10为底的计数法表示出来(未知数已假设),m*2^e=c*10^d,解这个指数幂等式首先想到的是两边取常用对数,得到log10(m)+e*log10(2)=log10(c)+d,先令左边为t,则d=t-log10(c),因为1<=c<10,所以log10(c)<1,因为d为指数,为正,所以d=t/1(向下取整),所以c=10^(t-d),这样就可以根据式子进行打表了,然后就是上面说的先匹配指数再在误差允许的范围内匹配尾数就可以了,代码如下:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>

using namespace std;

double M[11][33];	//存储对应尾数
long long E[11][33];	//存储对应指数
const double min_differ=1e-5;	//设置误差
void solve(double m,long long e);

int main()
 {
	int i,j;
	double m,t;
	long long e;
	char str[22];
	for(i=0;i<=9;i++)
		for(j=1;j<=30;j++)
		{
			e=(1<<j)-1;		//根据上述公式打表,每一个对应位的尾数和指数分别存储
			m=1-1.0/(1<<(i+1));
			t=log10(m)+e*log10(2);
			E[i][j]=t/1;
			M[i][j]=pow(10,t-E[i][j]);
		}
	while(cin>>str,strcmp(str,"0e0"))
	{
		*(strchr(str,'e'))=' ';		//将字符串中的e替换成空格
		sscanf(str,"%lf %lld",&m,&e);	//运用sscanf巧妙分割尾数和指数
		solve(m,e);
	}

	return 0;
}
void solve(double m,long long e)	//把匹配过程放到函数中,匹配后可以及时中断
{
	int i,j;
	for(i=0;i<=9;i++)
		for(j=1;j<=30;j++)
			if(e==E[i][j]&&fabs(m-M[i][j])<min_differ)	//当指数等于表中所给并且尾数差值绝对值小于误差时即匹配,输出答案,跳出函数
			{
				cout<<i<<" "<<j<<endl;
				return;
			}
}




  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值