高精度算法 (基础篇)

转载出处: http://www.cnblogs.com/ECJTUACM-873284962/ 

参考:https://blog.csdn.net/fanyun_01/article/details/79967170

前言:由于计算机运算是有模运算,数据范围的表示有一定限制,如整型int(C++中int 与long相同)表达范围是(-2^31~2^31-1),unsigned long(无符号整数)是(0~2^32-1),都约为几十亿.如果采用实数型,则能保存最大的double只能提供15~16位的有效数字,即只能精确表达数百万亿的数.因此,在计算位数超过十几位的数时,不能采用现有类型,只能自己编程计算.
高精度计算通用方法:高精度计算时一般用一个数组来存储一个数,数组的一个元素对应于数的一位(当然,在以后的学习中为了加快计算速度,也可用数组的一个元素表示数的多位数字,暂时不讲),表示时,由于数计算时可能要进位,因此为了方便,将数由低位到高位依次存在数组下标对应由低到高位置上,另外,我们申请数组大小时,一般考虑了最大的情况,在很多情况下,表示有富余,即高位有很多0,可能造成无效的运算和判断,因此,我们一般将数组的第0个下标对应位置来存储该数的位数.如数:3485(三千四百八十五),表达在数组a[10]上情况是:
下标  0    1    2    3     4    5    6    7    8    9  
内容  4    5    8    4     3    0    0    0    0    0
说明:位数   个位  十位  百位 千位
具体在计算加减乘除时方法就是小学时采用的列竖式方法.
注:高精度计算时一般用正数,对于负数,通过处理符号位的修正.


一 . 高精度数的存储
1.如对数采用的字符串输入

#include<iostream>
using namespace std;
const int N = 200;
int main()
{
	int a[N+1],i;
	string s1;
	cin >> s1;
	memset(a, 0, sizeof(a));
	a[0] = s1.length();
	for( i = 1; i <= a[0]; i++)
	a[i] = s1[a[0] - i] - '0';
	return 0;
}

二  . 高精度数比较

int Compare(int a[], int b[])
{
	int i;
	if(a[0] > b[0]) return 1;
	if(a[0] < b[0])	return -1;
	for( i = a[0];i > 0; i--)
	{
		if(a[i] > b[i])
		return 1;
		if(a[i] < b[i])
		return -1;
	}
	return 0;
}

三 . 高精度数相加

int Plus (int a[], int b[])
{
	int i, k;
	k = a[0] > b[0] ? a[0] : b[0];
	for( i = 1;i <= k; i++)
	{
		a[i+1] += (a[i] + b[i]) / 10;
		a[i] = (a[i] + b[i]) % 10; 	
	}	
	if(a[k+1] > 0)
	a[0] = k+1;
	else
	a[0] = k;
	return 0;
}

四   . 高精度数减法

int Subtraction(int a[], int b[])
{
	int flag ,i;
	flag = Compare(a,b);
	if(flag == 0)
	{
		memset(a, 0, sizeof(a));
		return 0;
	}
	if(flag == 1)
	{
		for( i = 1;i <= a[0]; i++)
		{
			if(a[i] < b[i])
			{
				a[i+1]--;
				a[i] += 10;
			}
			a[i] = a[i] - b[i];
		}
		while(a[a[0]] == 0) a[0]--;
		return 0;
	}
	if(flag == -1)
	{
		for(i = 1;i <= b[0]; i++)
		{
			if(b[i] < a[i])
			{
				b[i+1]--;
				b[i] += 10;
			}
			a[i] = b[i] - a[i];
		}
		a[0] = b[0];
		while(a[a[0]] == 0) a[0]--;
		return -1;
	}
} 

五 . 高精度数乘法

1 . 高精度乘低精度

int Multi(int a[],long key)//高精度 乘以低精度 a= a*key 
{
	int i,k;
	if( key == 0)
	{
		memset(a, 0,sizeof(a));
		a[0] = 1;
		return 0;
	}
	for( i = 1;i <= a[0];i++)
	a[i] = a[i] * key;
	for( i = 1;i <= a[0]; i++)
	{
		a[i+1] += a[i]/10 ;
		a[i] %= 10;
	}
	while (a[i] > 0)
	{
		a[i+1] = a[i]/10;
		a[i] %= a[i]%10;
		i++;
		a[0]++;
	}
	return 0;
} 

2. 高精度乘高精度

int main()
{
	int a[N+1], i, len, b[N+1], c[2*N+5];
	string s1, s2;
	cin >> s1 >> s2 ;
	memset(a, 0, sizeof(a));
	memset(b, 0, sizeof(b));
	memset(c, 0, sizeof(c));
	a[0] = s1.length();
	b[0] = s2.length();
	for( i = 1; i <= a[0]; i++)
	a[i] = s1[a[0] - i] - '0';
	for( i = 1; i <= b[0]; i++)
	b[i] = s2[b[0] - i] - '0';
	 
	for(i = 1; i <= a[0]; i++)
    for(int j = 1; j <= b[0]; j++)
    {
      	c[i + j - 1] += a[i] * b[j];  
    	c[i + j] += c[i + j - 1] / 10;  
    	c[i + j - 1] %= 10;
    }
    
	len = a[0] + b[0] + 1;  //去掉最高位的0,然后输出  
 	while((c[len]==0)&&(len>1)) len--;   //为什么此处要len>1??  
  	c[0] = len;
	for(i = c[0]; i >= 1; i--)  
    cout << c[i]; 
	return 0;
}

六  . 高精度除法

1. 高精度除低精度

#include  <stdio.h>
#define   N  500
main()
{
  int  a[N] = {0}, c[N] = {0};
  int  i, k, d, b;
  char  a1[N];  
  printf("Input 除数:");
  scanf("%d", &b);
  printf("Input 被除数:");
  scanf("%s", a1);
  k = strlen(a1);
  for(i = 0; i < k; i++)  a[i] = a1[k - i - 1] - '0';
  d = 0;
  for(i = k - 1; i >= 0 ; i--)
  {
     d = d * 10 + a[i];
     c[i] = d / b;
     d = d % b;      
  }   
  while(c[k - 1] == 0 && k > 1)  k--;  
  printf("商=");
  for(i = k - 1; i >= 0; i--)  printf("%d", c[i]);
  printf("\n余数=%d", d);   
}

代码2

int Devision(int a[], int b,int c[])    //c[]存商,a[]被除数,b除数
{
	int i;
	int d = 0;
	c[0] = a[0];
	for(i = a[0]; i >= 1;i--)
	{
		d = d * 10 + a[i];
		c[i] = d / b;
		d = d % b; 
	}
	
	while(c[0] == 0 && c[0] > 1) c[0]--;
	if(d == 0)            //余数为0
	return 1;
	else                   
	return 0;
	
}

2. 高精度除以高精度


#include<iostream>
#include<cstring>
using namespace std;
int a[100],b[100],c[100];
int compare(int a[],int b[])//比较a、b,若a>b为1;若a<b为-1;若a=b为0
{
    int i;
    if(a[0]>b[0])
        return 1;
    if(a[0]<b[0])
        return -1;
    for(i=a[0];i>0;i--)//从高位到低位比较
    {
        if(a[i]>b[i])
            return 1;
        if(a[i]<b[i])
            return -1;
    }
    return 0;
}
 
void subduction(int a[],int b[])//计算a=a-b
{
    int flag;
    int i;
 
    flag=compare(a,b);
    if(flag==0)//相等
    {
        a[0]=0;
        return;
    }
    if(flag==1)//大于
    {
        for(i=1;i<=a[0];i++)
        {
            if(a[i]<b[i])//若不够向上借位
            {
                a[i+1]--;
                a[i]+=10;
            }
            a[i]-=b[i];
        }
        while(a[0]>0&&a[a[0]]==0)//删除前导0
            a[0]--;
        return;
    }
}
int main()
{
    char str1[100],str2[100];
    int i,j;
 
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    memset(c,0,sizeof(c));
 
    cin>>str1>>str2;
    a[0]=strlen(str1);//a[0]存储串1的位数
    b[0]=strlen(str2);//b[0]存储串2的位数
    for(i=1;i<=a[0];i++)
        a[i]=str1[a[0]-i]-'0';
    for(i=1;i<=b[0];i++)
        b[i]=str2[b[0]-i]-'0';
 
 
    int temp[100];
    c[0]=a[0]-b[0]+1;
    for(i=c[0];i>0;i--)
    {
        memset(temp,0,sizeof(temp));
 
        for(j=1;j<=b[0];j++)//从i开始的地方,复制数组b到数组temp
            temp[j+i-1]=b[j];
        temp[0]=b[0]+i-1;
 
        while(compare(a,temp)>=0)//用减法模拟
        {
            c[i]++;
            subduction(a,temp);
        }
    }
 
    while(c[0]>0&&c[c[0]]==0)//删除前导0
        c[0]--;
 
    cout<<"商为:";
    if(c[0]==0)//输出结果
        cout<<0<<endl;
    else
    {
        for(i=c[0];i>0;i--)
            cout<<c[i];
        cout<<endl;
    }
 
    cout<<"余数为:";
    if(a[0]==0)//输出余数
        cout<<0<<endl;
    else
    {
        for(i=a[0];i>0;i--)
            cout<<a[i];
        cout<<endl;
    }
 
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Harington/article/details/83476464