高精度計算與代數計算

對string類和對象的操作

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int main()
{
	string str("123456789");
	cout<<str<<endl;
	return 0;
}

輸出:
在這裏插入圖片描述/

將字符數組轉換成整形數組程序
int *Str2Int(char *str)
{
	int i, len =strlen(str);
	int *a=new int[(len+1)*sizeof(int)];
	for(int i=0;i<len;i++) a[i]=str[len-i-1]-'0';
	return a;
}

整數數組的歸整運算(將a[k]中的數轉換成p進制)

int check(int *a,int n)
{
	int k=0,len=n;
	while(a[len-1]==0&&len>1) len--;
	for(int k=0;k<len;k++)
	{
		if(a[k]>=10)
		{
			a[k+1]=a[k+1]+a[k]/10;
			a[k]=a[k]%10;
		}
	}
	if(a[k]!=0) len=k+1; //確定數組最終長度
	return len;
}

歸整完畢後,可將整型數組再轉換爲字符數組,以備後用

char *Int2Str(int *a,int n)
{
	int i;
	char *str=new char[(n+1)*sizeof(char)];
	for(int i=0;i<n;i++) str[i]=(char)a[n-i-1]+48; // a轉換爲字符數組str
	str[n]='\0';
	return str;
}

高精度四則運算的基本處理方法

對輸入數據的處理:
數據小則直接存,大則用字符串存
接下來處理以下三個基本問題:
①計算結果位數的確定
②進位處理和借位處理
③商和餘數額求法
加法
減法
兩數A,B的減法處理方法有兩種:從低位開始或從高位開始
常用的方法是從低位開始:
①確定差的位數:兩數之差的位數不超過較大數的位數
②借位處理:做減法運算時,要先判斷是否需要借位,如果需要借位那麼從上一位借一個1,當作本位的10,上一位減1,然後本位相減
③負數的處理:如果減數B大於被減數A,那麼交換A,B的值轉化爲被減數大於減數的情況處理
乘法
除法
除法是基於減法的方式,採用試商法。做除法運算時,每次都是用被除數減去商與除數的積,如果所得餘數不爲零,將其擴大10倍再次作爲被除數,繼續試除,直至餘數爲零或達到要求的精度爲止。
在具體處理時,也可將除法轉化爲多位數乘1位數,這個多位數就是被除數。然後相加,在採用逐次減法的方法。
下面列出高精度四則運算的程序,每個程序都獨立可用

const int MAXLEN = 1000;
// 加法:輸入兩個用字符數組表示的長整數m1,m2
// 返回一個字符數組指針,指向m1與m2的和
char *addition(char *m1, char *m2)
{
	int i, len1, len2, len, c=0;
	int * t1, * t2;
	len1=strlen(m1);len2=strlen(m2);
	len=(len1>=len2)?len1:len2;  //定位數
	t1=new int[(len+2)*sizeof(int)];
	t2=new int[(len+2)*sizeof(int)];
	t1=Str2Int(m1);
	t2=Str2Int(m2);
	for(i=len1;i<len+1;i++) t1[i]=0; //缺位前導補零
	for(i=len2;i<len+1;i++) t2[i]=0; //缺位前導補零
	for(i=0;i<len;i++) t1[i]=t1[i]+t2[i]; //加法
	len=check(t1,len); // 歸整
	return Int2Str(t1,len); //轉化爲字符串,返回
}

// 減法:輸入兩個用字符數組表示的長整數m1,m2
// 返回一個字符數組指針,指向m1與m2的差
char *subtract(char *m1, char *m2)
{
	int i, len1, len2, len, c=0, *t1, *t2, cf=0;
	char *temp, *csub;
	len=strlen(m1);len2=strlen(m2);
	len=(len1>=len2)?len1:len2;   // 定位數
	t1=new int[(len+2)*sizeof(int)];
	t2=new int[(len+2)*sizeof(int)];
	temp=new char[(len+2)*sizeof(char)];
	csub=new char[(len+3)*sizeof(char)];
	if((len>len1)||((len2==len1)&&strcmp(m1,m2)<0)) // 當被減數小於減數時,調整
	{
		strcpy(temp,m1); //將m1複製到temp中
		strcpy(m1,m2);
		strcpy(m2,temp);
		len1=strlen(m1);len2=strlen(m2);
		cf=1;
	}
	t1=Str2Int(m1);t2=Str2Int(m2); // m1,m2分別轉化爲整型數組t1,t2
	for(i=len1;i<len;i++) t1[i]=0;
	for(i=len2;i<len;i++) t2[i]=0;
	for(i=0;i<len;i++)
	{
		if(t1[i]>=t2[i]) t1[i]=t1[i]-t2[i];
		else   //歸整
		{
			t1[i]=t1[i]-t2[i];
			c=(t1[i]*(-1)%10)==0?(t1[i]*(-1)/10):(t1[i]*(-1)/10+1);
			t1[i]=t1[i]+10*c;
			t1[i+1]=t1[i+1]-c;
		}
	}
	int n=i, begin =0;
	while(t1[n-1]==0&&n>1) n--;
	if(cf==1)
	{
		csub[0]='-';
		n++;begin=1;
	}
	for(i=begin;i<n;i++) csub[i]=(char)t1[n-i-1]+48;  // 將t1轉化爲字符數組csub
	csub[n]='\0';
	return csub;
}

// 乘法:輸入兩個用字符數組表示的長整數m1,m2
// 返回一個字符數組指針,指向m1與m2的積
char *multiply(char *m1,char *m2)
{
	int i, j, len1, len2, len, c=0, *t1, *t2, *prod;
	len1=strlen(m1);len2=strlen(m2);
	len=len1+len2;  // 定位數
	t1=new int[(len1+1)*sizeof(int)];
	t2=new int[(len2+1)*sizeof(int)];
	prod=new int[(len+1)*sizeof(int)];
	t1=Str2Int(m1);t2=Str2Int(m2);
	for(i=0;i<len+1;i++) prod[i]=0; // 	缺位前導補零
	for(i=0;i<len1;i++)
		for(j=0;j<len2;j++)
			prod[i+j]=prod[i+j]+t1[i]*t2[j];
	len=check(prod,len); //歸整
	return Int2Str(prod,len);
}

①高精度數除以高精度數的實現方法如下:

// 高精度數除以高精度數
// 輸入兩個用字符數組表示的長整數m1,m2
// 輸出m1被m2除的商quotient和餘數remainder
void divide(char *m1, char *m2, char *remainder, char *quotient) 
{
	int i, j, k, len, *temp;
	int len1=strlen(m1), len2=strlen(m2);
	char *m3;
	if(strcmp(m1,m2)==0)
	{
		quotient[0]='1';
		quotient[1]='\0';
		
		remainder[0]='0';
		remainder[1]='\0';
	}
	else if((len1<len2)||(len1==len2)&&strcmp(m1,m2)<0)
	{
		quotient[0]='0';
		quotient[1]='\0';
		remainder=m1;
	}
	else
	{
		temp=new int[(len2+1)*sizeof(int)];
		len=0;
		for(i=0;i<len1;i++)
		{
			temp[i]=0;
			remainder[len]=m1[i]; 
			remainder[len+1]='\0';
			len=strlen(remainder);
			while((len>len2)||((len==len2)&&(strcmp(remainder,m2)>=0)))
			{   //即remainder>=m2
				m3=new char[(len1+1)*sizeof(char)];
				memset(m3,0,sizeof(m3));
				m3=subtract(remainder,m2);
				remainder=m3;
				len=strlen(remainder);
				temp[i]++;
			}
			quotient[i]=temp[i]+'0';
		}
		j=0;
		while((j<len1)&&(quotient[j]=='0'))
			j++;
		for(k=0;k<len1-j;k++)
			quotient[k]=quotient[k+j];
		quotient[len-j]='\0';
		if(remainder[0]=0)
		{
			remainder[0]='0';
			remainder[1]='\0';
		}
	}
}

②高精度數除以低精度數的實現方法如下:
關於delete[]
//new[] 必須配合delete[]使用,有時使用delete了不會報錯(例如delete基本類型或者結構體等的數組指針)
string* pStr = new string[9];
delete[] pStr; //delete[]會逐個調用“對象數組”的每個對象的“析構函數”,這裏用delete肯定報錯(除非“這個類,沒有析構函數”)


#define max 1000

// 高精度數除以低精度數
// 一下程序中,num是被除數,p是除數,remainder是餘數,quotient是商
void HpDivByShort(string num,int p, int * remainder, string quotient)
{
	int len = num.length(), i, s, *nn;  //字符數據num轉化爲整型數組nn
	nn = new int[len];
	for(i=0;i<len;i++) nn[i]=num[i]-'0';
	int tmp = 0, rem, tmp_q[max], flag=0;
	i=0;
	while((i<len)&&(tmp<p)) //準備試商
	{
		tmp=tmp*10+nn[i];
		i++;
	}
	i--;  // 商的位置
	s=i;  //最高位置i
	tmp_q[i]=tmp/p; // 試商
	rem= tmp%p; //取餘
	tmp=rem; // 準備與num的後續數構成新數
	nn[i]=tmp_q[i];
	while(i<len-1)
	{
		tmp=tmp*10+nn[i+1];
		if(tmp<p)
		{
			tmp_q[i+1]=0;
			nn[i+1]=0;
		}
		else
		{
			rem=tmp%p;
			tmp_q[i+1]=tmp/p;
			nn[i+1]=tmp/p;
			tmp=rem;
		}
		i++;
	}
	*remainder=tmp;
	for(i=0;i<len-s;i++)
	{
		tmp_q[i+s]+='0';
		quotient[i]=tmp_q[i+s];
	}
	quotient[len-s]=0;
	delete[]nn;
	return;
}

題目:1005 大數加法
代碼:

// 這裏也考慮了負數的情況
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=1e4+10;


int main()
{
    char a_str[maxn],b_str[maxn];
    int a[maxn];
    int b[maxn];
    int c[maxn];

    int a_ans,b_ans;
    while(scanf("%s%s",a_str,b_str)==2){
   memset(a,0,sizeof(a));
   memset(b,0,sizeof(b));
   memset(c,0,sizeof(c));
    int alen=strlen(a_str);
    int blen=strlen(b_str);
    if(a_str[0]=='-')
    {
        a_ans=-1;
        //alen-=1;
        for(int i=1;i<alen;i++)
        {
            a[i-1]=a_str[alen-i]-'0';
        }
    }
    else
    {
        a_ans=1;
        for(int i=0;i<alen;i++)
        {
            a[i]=a_str[alen-i-1]-'0';
        }
    }
    //
    if(b_str[0]=='-')
    {
        b_ans=-1;
        //blen-=1;
        for(int i=1;i<blen;i++)
        {
            b[i-1]=b_str[blen-i]-'0';
        }
    }
    else
    {
        b_ans=1;
        for(int i=0;i<blen;i++)
        {
            b[i]=b_str[blen-i-1]-'0';
        }
    }
    ///
    int mx=max(alen,blen);
    for(int i=0;i<mx;i++)
    {
        c[i]=a_ans*a[i]+b_ans*b[i];
    }
    for(int i=0;i<mx;i++)
    {
        if(c[i]>9)
        {
            c[i]-=10;
            c[i+1]+=1;

        }
        if(c[i]<0)
        {
            c[i]+=10;
            c[i+1]-=1;
        }

    }
    int x=mx;
    while( x>=0&&c[x]==0 ) x--;
    if(x==-1)
    {
        printf("0\n");

    }

   else  if(c[x]>0)
    {


        for(int i=x;i>=0;i--)
        {
            printf("%d",c[i]);
        }
        printf("\n");
    }
    else  //是負數
    {
        for(int i=0;i<=x;i++)
           c[i]=-1*c[i];
        for(int i=0;i<=x;i++)
        {
            
            if(c[i]<0)
            {
                c[i]+=10;
                c[i+1]-=1;
            }
        }
        printf("-");

        int t=x+3;
        while(c[t]==0) --t;
        for(int i=t;i>=0;i--)
        {
            printf("%d",c[i]);
        }
        printf("\n");

    }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章