文章末尾附上英文题目
这道题在“紫书”的第三章,难度应该不大(水题),可是做了好久……
题目大意
计算机用阶码-尾数的方式保存浮点数。
如图,尾数(Mantissa)有8位,阶码(exponent)有6位,可以表示的最大浮点数为
这里尾数
我们可以看到,数在计算机中是以二进制的形式保存的,因此需要把二进制
我们需要根据这个最大浮点数(
AC代码
如果看源代码能看懂的话,后面的内容可以略去
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <string>
#include <cstring>
#include <stdlib.h>
using namespace std;
double A[11][31];
long long B[11][31];
void CreateTable() {
for(int i=0; i<10; i++)
for(int j=1; j<=30; j++)
{
double m = 1 - pow(2, -1-i);
//double e = pow(2, j) - 1;
double e = (1<<j) -1; // 用位运算重写上面注释掉的代码
double convert = log10(m) + e*log10(2);
B[i][j] = (long long)convert;
A[i][j] = pow(10, convert-B[i][j]);
}
}
int main()
{
CreateTable();
char s[40];
while(cin.getline(s, 40)) {
if(strcmp(s, "0e0") == 0)
break;
char s1[40], s2[40];
// 分离出e前后的数
sscanf(s, "%[^e]", s1);
sscanf(s, "%*[^e]e%s", s2);
double a;
int b;
// 字符数组转换成浮点数与整数
sscanf(s1, "%lf", &a);
sscanf(s2, "%d", &b);
if(a < 1){
a*=10;
b-=1;
}
for(int i=0; i<10; i++)
for(int j=1; j<=30; j++)
if(b == B[i][j] && fabs(a - A[i][j]) < 0.0001)
printf("%d %d\n", i, j);
}
return 0;
}
求解步骤
打表
void CreateTable() {
for(int i=0; i<10; i++)
for(int j=1; j<=30; j++)
{
double m = 1 - pow(2, -1-i);
//double e = pow(2, j) - 1;
double e = (1<<j) -1; // 用位运算重写上面注释掉的代码
double convert = log10(m) + e*log10(2);
B[i][j] = (long long)convert;
A[i][j] = pow(10, convert-B[i][j]);
}
}
- 把对应位数的二进制
m 与e 转换成十进制 - 计算
m 时,对应位数i 的十进制m 计算步骤2−1+2−2+⋯+2−1−i=1−2−1−i - 计算
e 时,对应位数j 的十进制e 计算步骤20+21+⋯+2j−1=2j−1 - 对于
e 的计算,我们可以用位运算
(1<<j) -1
m∗2e=A∗10B ,不过直接计算目测会溢出(能优化就优化吧)。我们采用“对数法”(姑且这么叫吧),即等式两边取对数,得log10m+e∗log102=log10A+B∗log1010=log10A+B 0<log10A<1 ,对log10m+e∗log102 取整数部分,即是B ,A=10(log10A+B)−B=10(log10m+e∗log102)−B
B[i][j] = (long long)(log10(m) + e*log10(2));
A[i][j] = pow(10, (log10(m) + e*log10(2))-B[i][j]);
处理输入
- 整行读取,分理处
e 前后的数。这里我两次用到了sscanf 函数,先是配合正则表达式提取出e 前后的字符数组,再把字符数组转换成对应的浮点数与整数。(后来发现用strchr 函数更方便…)
char s1[40], s2[40];
// 分离出e前后的数
sscanf(s, "%[^e]", s1);
sscanf(s, "%*[^e]e%s", s2);
double a;
int b;
// 字符数组转换成浮点数与整数
sscanf(s1, "%lf", &a);
sscanf(s2, "%d", &b);
- 因为是
A∗10B 的形式,所以我们应限定1≤A<10 ,然而题目中只说0<A<10 。因此我们应该再处理一下
if(a < 1){
a*=10;
b-=1;
}
查表
- 在表中查找,其中关于
a 的精度,根据2−9≈0.001953 ,我们限定精度为0.0001即可。
if(b == B[i][j] && fabs(a - A[i][j]) < 0.0001)
英文题目