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;
}


 

 

發佈了209 篇原創文章 · 獲贊 20 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章