poj1131

题目不难,高精度除法+放缩法

大致题意为:给定一个8进制数的小数(包括0和1),要将其转化为10进制小数。要将十进制小数的小数点后保留8进制小数小数点后位数的3倍即可。

题意很明确。分析如下:

8进制小数转化为10进制小数,具体规则很简单。例如现在有0.123(8),要转化为10进制,则为1*8^-1 + 2*8^-2 + 3*8^-3。可以依据这个作为题目的突破点。

按照上面的转化规则,可以将8进制小数转化为两个十进制数相除。例如上面可以转化为(1*8^2+2*8^1+3)/8^3。问题就转化为高精度整数除法运算了。同时由于要求保留小数点后规定数字,所以这里必须实现将分子放大,保证满足商可以有题目要求的精度位数,最后将商缩小,取满足题目的精度位数即可。

另外就是注意0和1要特别处理,其实也很简单,同时分子分母要使用__int64类型,数据量比较大,详见注释。

下面是代码:168K+0MS

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Max 1010
char Input[Max/10];
int result[Max]; //保存商结果
int a[Max];//除数
int b[Max];//被除数
int alen,blen; //长度
int num,len; //num为放大位数,len为输入的浮点数位数(包括小数点)
__int64 son,parent;
__int64 Power(int x){ //计算8^x
	__int64 temp=1;
	for(int i=0;i<x;i++)
		temp*=8;
	return temp;
}
int Substract(int *p,int *q,int lenp,int lenq){ //高精度减法,-1表示不够减,0表示相等,>0表示正常减法后被减数长度
	if(lenp<lenq) //若前者长度较小
		return -1;
	else if(lenp==lenq){ //长度相同时,继续比较大小
		for(int i=lenp-1;i>=0;i--){
			if(p[i]<q[i]) return -1; //若相同位置前者比较小,则说明不够减
		    else if(p[i]>q[i]) break;
		}
	} // 相等或大于同一处理
	for(int i=0;i<lenp;i++){ //高精度减法核心代码
		p[i]-=q[i];
		if(p[i]<0){ //借位
			p[i]+=10;
			p[i+1]-=1;
		}
	}
    int i;
	for(i=lenp-1;i>=0;i--) // 清0
		if(p[i]>0)
			break;
	if(i>=0) // 若不相等则返回结果长度
		return i+1;
	else //相等返回0
		return 0;
}
void cal(){ // 高精度除法运算
	memset(a,0,sizeof(a)); // 除数清0
	memset(b,0,sizeof(b)); //被除数清0
	memset(result,0,sizeof(result)); // 结果清0
	int i,j;
	for(i=0;i<num;i++) // 放大被除数,是商满足题目精度,低位置0
		b[i]=0;
    while(son>0){ // 处理高位
		b[i++]=son%10;
		son/=10;
	}
	blen=i; // 长度
	i=0;
	while(parent>0){ // 赋值除数
		a[i++]=parent%10;
	    parent/=10;
	}
	alen=i;
    int ntime=blen-alen; //位数差
	for(i=blen-1;i>=ntime;i--) // 右移除数,低位补零
		a[i]=a[i-ntime];
	while(i>=0){
		a[i]=0;
		i--;
	}
	alen=blen; //使长度相同
	for(i=0;i<=ntime;i++){  //高精度除法核心代码
		int ntemp;
		while((ntemp=Substract(b,a+i,blen,alen-i))>=0){ // 若够减除数*10^(ntime-i)
			blen=ntemp; //减之后被除数的长度
			result[ntime-i]++; //相应为增加
		}
	}
	for(i=0;i<Max;i++) // 查找尾部0位置
		if(result[i]>0) 
			break;
	printf("%s [8] = ",Input);
    printf("0.");
	int Sum=0; //计数,小数点后保留位数
    for(j=num-1;j>=i;j--){ //依次输出小数点后数字
		printf("%d",result[j]);
		Sum++;
		if(Sum==(len-2)*3) //若已经到达最大精度,则直接退出
			break;
	}
	printf(" [10]\n");
}
int main(){
	while(scanf("%s",Input)!=EOF){
		getchar();
		len=strlen(Input); //求长度
		int index=0,dnum=0; // 分别标记小数点后第一个不为0的数字下标, 计数小数点后位数(包括尾部0)
		bool trag=true; // 标记
		son=0; //分子初始化为0
		for(int i=len-1;i>=0;i--){ //试探小数点字符串
			if(Input[i]=='.') //若为小数点,直接退出
				break;
			if(trag && Input[i]!='0'){ //若为小数点后第一个不为0的数字
				trag=false; // 置标记
				parent=Power(i-1); // 赋值分母值
				son+=(Input[i]-'0'); // 累加分子值
				index=i; //标记该下标
			}
			else if(!trag && Input[i]!='0' && Input[i]!='.') //处理小数点后第一个不是0的数字出现以后,且不是小数点
				son+=((Input[i]-'0')*Power(index-i)); //累加分子
			dnum++; //累计小数点后数字个数
		}
		if(son==0){ //若为1或0特殊情况,特殊处理
			printf("%s [8] = %s",Input,Input);
			for(int i=0;i<2*dnum;i++)
				printf("0");
			printf(" [10]\n");
		}
		else{ //否则一般处理
			num=(len-2)*5; // 设置分子扩大位数*10^num
			cal(); //计算十进制小数
		}
	}
	return 0;
}


 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值