高精度算法

高精度算法
 

在编程进行数值运算时,有时会遇到运算的精度要求特别高,计算的位数达到几十位甚至几百位,虽然计算机的计算精度也算较高了,但因受到硬件的限制,往往达不到实际问题所要求的精度。这种情况下,就需要进行“高精度运算”。

高精度运算首先要处理好数据的接收和存储问题,其次要处理好运算过程中的“进位”和“借位”的问题。




      
高精度计算中需要处理好,以下几个问题:

  • (1)数据的接收方法和存储方法

    当输入的数很长时,可采用字符串方式输入,这样可输入位数很长的数,利用字符串函数和操作运算,将每一位数取出,存人数组中。

    void init(int a[]) //传入一个数组
    {
    string s; //读入字符串s
    cin>>s;
    a[0]=s.length(); //用 a[0]计算字符串s的位数
    for(int i=1;i<=a[0];i++)
    a[i]=s[a[0]-i]-'0'; //将数串s转换为数组a,并倒序存储
    }

  • (2)高精度数位数的确定:

    接收时往往是用字符串的,所以它的位数就等于字符串的长度。:

  • (3)进位,借位处理

    加法进位 : c[i] = a[i] + b[i];

          
          
        
    if(c[i]>=10)   { c[i]%=10;   c[i+1]++; }


    减法借位:if (a[i]<b[i])   { a[i+1]--;   a[i]+=10; }

          
          
       c[i] = a[i] - b[i];


    乘法进位:c[i+j-1]=a[i]*b[j]+x+c[i+j-1];

x=c[i+j-1]/10;

      
      
   c[i+j-1]%=10;

  • (4)商和余数的求法

    商和余数处理: 视被除数和除数的位数情况进行处理。

     

案例:

1.高精度加法

输入两个1000位以内的正整数,输出它们的和。

【输入样例】

  123456789

  987654321

【输出样例】

  1111111110

【分析】用字符串的方式读入两个高精度数,转存到两个整型数组a和b中,以下模拟加法的过程:从低位(第0位)开始对应为a[i]和b[i]相加,同时处理进位,结果存储
到另一个数组c中。最后,从高位到低位输出c[i]。
       7 5 1 2 9 9 6 0 1 9 
+              1 2 3 4 5 6
进位   0 0 0 1 1 0 0 0 1 0 
—————————————
       7 5 1 3 1 1 9 4 7 5 
                    

 程序如下:

#include<iostream>
#include<cstring>
using namespace std; 
char sa[1010],sb[1010];
int n1,n2,n3,a[1010],b[1010],c[1010];

int main(){
	cin>>sa>>sb;
	n1=strlen(sa);
	n2=strlen(sb);
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	
	for(int i=0;i<n1;i++)
		a[n1-i-1]=sa[i]-'0';    //读入的字符串转成数字存储
	for(int i=0;i<n2;i++)
		b[n2-i-1]=sb[i]-'0'; 
		
	n3=n1>n2 ? n1:n2;
	memset(c,0,sizeof(c));
	
	for(int i=0;i<n3;i++){
		c[i]=a[i]+b[i]+c[i];    //对应为相加,包括上一次运算产生的进位 
		if(c[i]>=10){           //处理进位 
			c[i+1]=1;
			c[i]-=10;
		}
	} 
	if(c[n3]>0) n3++;
	for(int i=n3-1;i>=0;i--)
		cout<<c[i]; 	
	return 0;	
}



2.高精度乘法

输入两个1000位以内的正整数,输出它们的乘积。

【输入样例】

  123456789

  987654321

【输出样例】

  121932631112635269

【分析】如图示,模拟“竖式”乘法的过程,用一个数的每一位a[i](从低位开始)逐位与另一位数的每一位b[j]相乘,结果存储到c[i+1]位,同时处理好位数。
                    9 9 8 1 4
            x           3 2 6
       ———————————— 
                  5 9 8 8 8 4
                1 9 9 6 2 8
              2 9 9 4 4 2
       ————————————
              3 2 5 3 9 3 6 4

程序如下: 

#include<iostream>
#include<cstring>
using namespace std; 
char sa[1010],sb[1010];
int n1,n2,n3,jw,f,w,a[1010],b[1010],c[10200];

int main(){
	cin>>sa>>sb;
	n1=strlen(sa);
	n2=strlen(sb);
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));	
	for(int i=0;i<n1;i++)
		a[n1-i-1]=sa[i]-'0';    
	for(int i=0;i<n2;i++)
		b[n2-i-1]=sb[i]-'0'; 
		
	memset(c,0,sizeof(c));
	jw=0;
	for(int i=0;i<n1;i++){
		for(int j=0;j<n2;j++){
			f=a[i]*b[j]; jw=f/10; f%=10;  //处理逐位乘,记录乘积和进位 
			w=i+j; c[w]=c[w]+f;           //将a[i]*b[j]结果存到c[i+j] 
			c[w+1]=c[w+1]+jw+c[w]/10;     //处理进位 
			c[w]%=10;		
		}
	} 
	
	n3=n1+n2;   //找到最高位的非0位 
	while(c[n3]==0) n3--;
	for(int i=n3;i>=0;i--)
		cout<<c[i];
	return 0;	
}




3.高精度减法

输入两个1000位以内的正整数,输出它们的差值。

【输入样例】

  987654321

  123456789

【输出样例】

  -864197532

#include<iostream>
#include<cstring>
using namespace std; 
char sa[1010],sb[1010],sc[1010];
int n1,n2,n3,jw,f,w,a[1010],b[1010],c[1010];
bool flag=false;

int main(){
	cin>>sa>>sb;
	n1=strlen(sa);
	n2=strlen(sb);
	if(strcmp(sa,sb)<0){
		strcpy(sc,sa);
		strcpy(sa,sb);
		strcpy(sb,sc);
		flag=true;
	}
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));	
	for(int i=0;i<n1;i++)
		a[n1-i-1]=sa[i]-'0';    
	for(int i=0;i<n2;i++)
		b[n2-i-1]=sb[i]-'0'; 
		
	n3=n1>n2 ? n1:n2;
	memset(c,0,sizeof(c));
	for(int i=0;i<n3;i++){
		if(a[i]<b[i]) {
			c[i]=a[i]+10-b[i];
			a[i+1]--;
		}else{
			c[i]=a[i]-b[i];
		}
	} 
	if(flag) cout<<"-";
	while(c[n3-1]==0 ) n3--;
	for(int i=n3-1;i>=0;i--)
		cout<<c[i]; 
	return 0;	
}




4.n/m的精确值。

输入n和m,输出n除以m的精确值。假设n和m在int范围以内,结果精确到小数点后100位。

【输入样例】

  355 113

【输出样例】

  3.1415929203539823008849557522123893805309734513274336283185840707964601769911504424778761061946902654

【分析】模拟数学中的“短除法”。由数学知识可知,除法运算中被除数、除数和商、余数的关系为:
    新的被除数 = 10 x 余数
    商 = 被除数 / 除数
    余数 = 被除数 % 除数

         3. 7 5
      ____________
    8√ 3 0
       2 4
     ———
         6 0
         5 6
       ———
           4 0
           4 0
         ———
             0
     (高精度除法示意图)     
    

程序如下: 

#include<iostream>
using namespace std; 
int n,m,b[100],s[100],y[100];

int main(){
	cin>>n>>m;
	b[0]=n; s[0]=n/m; y[0]=n%m;
	cout<<s[0];
	if(y[0]!=0) cout<<".";
	for(int i=1; i<=100; i++){
		if(y[i-1]==0) break;
		b[i]=y[i-1]*10;
		s[i]=b[i]/m;
		cout<<s[i];
		y[i]=b[i]%m;
	}
	cout<<endl;
	return 0;	
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值