首页 > 代码库 > HighAccuracy1131
HighAccuracy1131
题意解释:
给定一个八进制的小数(0到1之间)题目要求你把它转换为十进制小数,转换后小数的位数是转换前八进制小数位数的3倍且不输出末尾无意义的零(即后置零).
0.75 in octal is 0.953125 (7/8 + 5/64) in decimal.
①先说最直接的想法,从十分位到最后一位,每次乘上8的(-i)次方,累加即可,但这样写起高精度来异常麻烦,有可能涉及到高除高。
②稍作思考,我们发现从最后一位开始到小数点之前停下来,上一位算出来的数加上这一位的数除以8即可当做当前位算出来的数。
例如:0.233 [(3/8+3)/8+2]/8就是答案。
但计算机处理如此精度的小数,高精度写的多累啊(高手勿喷)。
③于是想到了化小数为整数,每次除以8之前看看能否被8整除(这个判断应该知道吧,看后三位能不能被8整除),不能的话乘10再看,乘10的同时计数器加1,直到能被8整除,除以8。
举个例子
0.75
看5不能被8整除,5000可以,pos=3 5000/8=625
从最低位开始除,因为位数越低,需要被除的次数越多,这样通过不同位数除以不同次数的8即可完成进制转换。第三个方法是对第二方法的改进。
此时不能在625的基础上加7,应该加7*(10^pos),补全你乘的10,得到7625
此时7625不能被8整除,而7625000可以
pos=6 7625000/8=953125
最后输出的时候小数点往前移动pos位即可。
整个过程数组模拟计算,否则后果你知道。。
#include <stdio.h>
#include <string.h>
int divide(int *a, int len)//大整数除法的思想 //divide(a, len_a)
{
int residue = 0, next = 0, temp = 0, i;
for(i = 0; i < len; i++)//首先把len位的数尝试除8
{
temp = a[i] + next;
a[i] = temp / 8;//第一次除的时候,a[i]一定等于0,比较八进制的数都小于8
residue = temp % 8;
next = residue * 10;//看成除8操作,那么高位的余数留到低位应该乘10
}
//此时i=len
while(next)//除不尽,那么通过将余数乘10的方式继续除8,i接着上次继续增加
{
a[i++] = next / 8;
next = next % 8;
next = next * 10;
}
return i;//得到的小数共有多少位
}
int main()
{
char s[1000];
int a[3000];
while(scanf("%s", s)!=EOF)
{
int n;
n = strlen(s);
int i;
for(i = 0; i < n; i++) //寻找第一个不是‘0‘或是‘.‘的数
if(s[i] != ‘0‘ && s[i] != ‘.‘)
break;
if(i >= n)//如果是0
printf("%s [8] = %s [10]\n", s, s);
else
{
int len_a = 1;//初始时只需要把最低位拿去除即可,只有一位
for(i = n - 1; i > 1; i--)
{
a[0] = s[i] - ‘0‘;
/*将字符串倒着存入a[0]。新来的s[i]加入上次得到a
数组序列(旧数组中a[0]=0)。len_a返回除完之后的小
数长度(不包括小数点)这样越低位的数,被8除的次数
就越多。十分位被8除一次。百分位被8除两次
*/len_a = divide(a, len_a);
}
printf("%s [8] = 0.", s);
for(i = 1; i < len_a; i++)
printf("%d", a[i]);
printf(" [10]\n");
}
}
return 0;
}
HighAccuracy1131