【题目链接】
【题目考点】
1. 数制
【解题思路】
八进制小数按位权展开式为
0.
d
1
d
2
d
3
.
.
.
d
k
=
d
1
∗
8
−
1
+
d
2
∗
8
−
2
+
.
.
.
+
d
k
∗
8
−
k
0.d_1d_2d_3...d_k=d_1*8^{-1}+d_2*8^{-2}+...+d_k*8^{-k}
0.d1d2d3...dk=d1∗8−1+d2∗8−2+...+dk∗8−k
设位权为q,初值为1。
循环遍历8进制数字字符串,每次循环q除以8。
第一次循环q除以8变为
8
−
1
8^{-1}
8−1,取到数字
d
1
d_1
d1,把
d
1
∗
q
d_1*q
d1∗q加到结果中。
第二次循环q除以8变为
8
−
2
8^{-2}
8−2,取到数字
d
2
d_2
d2,把
d
2
∗
q
d_2*q
d2∗q加到结果中。
…
第k次循环q除以8变为
8
−
k
8^{-k}
8−k,取到数字
d
k
d_k
dk,把
d
k
∗
q
d_k*q
dk∗q加到结果中。
最后输出结果。
题目要求k的范围为
0
<
k
<
15
0<k<15
0<k<15,最大为14。根据八进制与二进制的转化关系,1位8进制数字对应3位2进制数字,所以14位8进制数字最多可以转化为42位二进制数字。
考虑c++ double类型的存储原理(参考:c++ double类型存储),double类型尾数有52位,如果只是表示二进制数字,精度可以达到52位二进制数字。本题结果最多是精度为42位的二进制数字,因此使用double类型一定可以正确表示。
输出时,要最多保留42位小数,但如果小数点后位数不足42位,末尾也不要补0。这就不能用固定保留的位数的写法。如果写cout,不能写fixed
,只写setprecision(42)
;如果写printf,不能写%.42f
,只能写%.42g
。
【题解代码】
解法1:用cin,cout
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s;
double q = 1, ans = 0;//q:位权
cin >> s;
for(int i = 2; i < s.length(); ++i)
{
q /= 8;
ans += q * (s[i] - '0');
}
cout << s << " [8] = " << setprecision(42) << ans << " [10]";
return 0;
}
解法2:用scanf, printf
#include<bits/stdc++.h>
using namespace std;
int main()
{
char s[20];
scanf("%s", s);
int len = strlen(s);
double q = 1, ans = 0;//q:位权
for(int i = 2; i < len; ++i)//从十分位开始遍历
{
q /= 8;
ans += q * (s[i]-'0');
}
printf("%s [8] = %.42g [10]", s, ans);
return 0;
}