《编程思维与实践》1015.八进制小数
题目
思路
进制转换(迭代)加高精度(数组存储)问题.
1. N = k n ⋅ 8 − 1 + k n − 1 ⋅ 8 − 2 + . . . + k 0 ⋅ 8 − n = k n + ( k n − 1 ⋅ 8 − 1 + . . . + k 0 ⋅ 8 − n + 1 ) ⋅ 8 − 1 N=k_n·8^{-1}+k_{n-1}·8^{-2}+...+k_0·8^{-n}=k_n+(k_{n-1}·8^{-1}+...+k_0·8^{-n+1})·8^{-1} N=kn⋅8−1+kn−1⋅8−2+...+k0⋅8−n=kn+(kn−1⋅8−1+...+k0⋅8−n+1)⋅8−1
可以采用迭代,如八进制数 0.75 = ( 7 + ( 5 ⋅ 8 − 1 ) ) ⋅ 8 − 1 0.75=(7+(5·8^{-1}))·8^{-1} 0.75=(7+(5⋅8−1))⋅8−1 (注意是逆向迭代).
2.高精度是因为保留的位数可能超过double的范围,需要人为操作计算每次/8的值,
模仿笔除: 1/8=0余1,不足补0即1·10/8=1余2,2·10/8=2余4,4·10/8=5余0,所以1/8=0.125.
注意的点:
1.在通过循环模拟笔除时退出循环的条件不仅仅是余数为0(有可能还有下一位,如0.321/8)!应为长度为小数位数*3+1.
2.如果循环条件为长度为小数位数*3+1时,则结果有可能含有后置0,输出时需要注意去除.
代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int T;
scanf("%d",&T);
for(int i=0;i<T;i++)
{
char s[100];
int result[200]={0}; //实现高精度存储
scanf("%s",s);
int k;
for(int j=strlen(s)-1;j>1;j--) //j=1时s[j]为小数点,逆向
{
k=0;
int mod=0; //记录余数
result[k]+=s[j]-'0'; //每一位均小于8,所以做完除法后第一位都会变为0
do{
int temp=mod*10+result[k]; //余数*10+下一位
result[k]=temp/8; //更新得到的商
mod=temp%8; //更新余数
k++;
}while(k<=3*(strlen(s)-2)); //循环条件 长度为小数位数*3+1 strlen(s)-2表示减去小数点和前置0
}
int m=k-1;
while(result[m]==0) //去除后置0
{
m--;
}
printf("case #%d:\n",i);
for(int j=0;j<=m;j++)
{
printf("%d",result[j]);
if(j==0)
{
printf(".");
}
}
printf("\n");
}
return 0;
}