大数运算

一、简介

  • 由于编程语言提供的基本数值数据类型表示的数值范围有限,不能满足较大规模的高精度数值计算,因此需要利用其他方法实现高精度数值的计算,于是产生了大数运算。

二、大数乘法

  • 大数乘法大致有以下几种算法:模拟手工计算的普通大数乘法,分治算法和FFT算法。
  • 模拟普通手算乘法:算法简单、空间复杂度小。时间复杂度为O(n^2)。
    利用代数方法优化的乘法:使用递归求解,空间复杂度较大。算法复杂,需要定义大数加法,大数减法。时间复杂度降低到O(n^1.5)。
    快速傅立叶变换FFT:基于FFT的大数乘法时间复杂度O(nlogn)。

 

  • 下面例子是模拟普通手算乘法,其他两种可看参考文章
  • 思路
    乘积是逐位相乘,也就是ai*bj,结果加入到积C的第i+j位,最后处理进位即可
    ①字符中转换为int,并反转
    ②逐位相乘,结果存放在result_num[i+j]中;
    ③处理进位,消除多余的0;
    ④转换并反转,将计算结果转换为字符串并反转。

 

  • 头文件和数据结构
    #include <iostream>
    #include <string>
    #include <vector>
    #include <stdlib.h>
    using namespace std;
    struct bigcheng
    {
    	vector<int> a;
    	vector<int> b;
    	string result_str;
    };
    void chartonum(string a,string b,bigcheng &tempcheng);//字符串转换为数字并反转
    void multiply(bigcheng &tempchengh,vector<int> &result_num);//逐位相乘,处理进位消除多余的0
    void numtochar(bigcheng &tempcheng,vector<int> &result_num);//将计算结果转换为字符串并反转
    

     

  • ①字符中转换为int,并反转
    void chartonum(string a,string b,bigcheng &tempcheng)
    {
    	int size_a=a.size();
    	int size_b=b.size();
    	for (int i=size_a-1;i>=0;i--)
    	{
    		tempcheng.a.push_back(a[i]-'0');
    	}
    	for (int i=size_b-1;i>=0;i--)
    	{
    		tempcheng.b.push_back(b[i]-'0');
    	}
    }
    

     

  • ②逐位相乘,结果存放在result_num[i+j]中;
    ③处理进位,消除多余的0;
    void multiply(bigcheng &tempcheng,vector<int> &result_num)
    {
    	for (unsigned int i=0;i<tempcheng.a.size();i++)
    	{
    		for (unsigned int j=0;j<tempcheng.b.size();j++)
    		{
    			result_num[i+j]+=(tempcheng.a[i])*(tempcheng.b[j]);
    		}
    	}
    	for (int i=result_num.size()-1;i>=0;i--)
    	{
    		if (result_num[i]!=0)
    		{
    			break;
    		}
    		else
    			result_num.pop_back();
    	}
    	int c=0;
    	for (unsigned int i=0;i<result_num.size();i++)//处理进位
    	{
    		result_num[i]+=c;
    		c=result_num[i]/10;
    		result_num[i]=result_num[i]%10;
    	}
    	if (c!=0)
    	{
    		result_num.push_back(c);
    	}
    }
    

     

  • ④转换并反转,将计算结果转换为字符串并反转。
    void numtochar(bigcheng &tempcheng,vector<int> &result_num)
    {   int size=result_num.size();
    	for (unsigned int i=0;i<result_num.size();i++)
    	{
    		tempcheng.result_str.push_back(char(result_num[size-1-i]+'0'));
    	}
    }
     
    

     

  • 主函数
    int main()
    {
           bigcheng tempcheng;
    	string a,b;
    	cin>>a>>b;
    	chartonum(a,b,tempcheng);
    	vector<int> resultnum(a.size()+b.size(),0);
    	multiply(tempcheng,resultnum);
    	numtochar(tempcheng,resultnum);
    	cout<<tempcheng.result_str<<endl;
    	system("pause");
    	return 0;
    }
    

     

三、大数加法

  • check合法性校验,校验字符串中是否有非数字。
    bool check(char *p)
    {
    	if (!p)
    	{
    		return 1;
    	}
    	int i=0;
    	while(p[i]!='\0') 
    	{
    		if (p[i]<'0'||p[i]>'9')
    		{
    			return 1;
    		}
    		else ++i;
    	}
    	return 0;//合法
    }
    

     

char* bigadd(char *p1,char *p2)
{
	if (check(p1)||check(p2))
	{
		throw exception("Invalid input!");
	}
	int len1=strlen(p1);
	int len2=strlen(p2);
	int len3=max(len1,len2)+1;
	char *p3=new char[len3+1];
	memset(p3,'0',len3);
	p3[len3]='\0';
	int index1=len1-1,index2=len2-1,index3=len3-1;
	int carry=0;
	while(index1>=0&&index2>=0)
	{
		int num=p1[index1--]-'0'+p2[index2--]-'0'+carry;
		if (num>=10)
		{
			carry=1;
			num-=10;
		}
		else
			carry=0;
		p3[index3--]=num+'0';
	}
	while(index1>=0)
	{
		int num=p1[index1--]-'0'+carry;
		if (num>=10)
		{
			carry=1;
			num-=10;
		}
		else
			carry=0;
		p3[index3--]=num+'0';
	}
	while(index2>=0)
	{
		int num=p1[index2--]-'0'+carry;
		if (num>=10)
		{
			carry=1;
			num-=10;
		}
		else
			carry=0;
		p3[index3--]=num+'0';
	}
	p3[index3]=carry?'1':'0';
	return p3;
}

四、大数相减

char* bigminus(char *p1,char *p2,bool &flag)
{
	if (check(p1)||check(p2))
	{
		throw exception("Invalid input!");
	}
	flag=0;//正数默认
	if (strlen(p1)<strlen(p2))
	{
		flag=1;
		char *tmp=p1;
		      p1=p2;
			  p2=tmp;
	}
	else if (strlen(p1)==strlen(p2))
	{
		if (strcmp(p1,p2)<0)
		{
			flag=1;
			char *tmp=p1;
			p1=p2;
			p2=tmp;
		}
	}
	int index1=strlen(p1)-1,index2=strlen(p2)-1,index3=strlen(p1);
	char *p3=new char[strlen(p1)+2];
	memset(p3,'0',index3+1);
	p3[index3+1]='\0';
	int carry=0;
	while(index1>=0&&index2>=0)
	{
		int num=p1[index1--]-p2[index2--]-carry;
		if (num<0)
		{
			carry=1;
			num+=10;
		}
		else carry=0;
		p3[index3--]=num+'0';
	}
	while(index1>=0)
	{
		int num=p1[index1--]-'0'-carry;
		if (num<0)
		{
			carry=1;
			num+=10;
		}
		else carry=0;
		p3[index3--]=num+'0' ;
	}
	    int i=0;
		while(p3[i]=='0') ++i;
		if (flag)
		{
		  p3[i-1]='-';
		}
	return p3;
}

五、大数相除

char* bigchu(char *p1,char *p2)//大数除,有问题,但思想是对的,关键怎么处理前面多样的0
{
	bool flag=0;
	char *tmp1=new char[strlen(p2)-strlen(p2)+1];
	char *tmp0=tmp1,*p3,*p4;
	memset(tmp1,'0',strlen(p2)-strlen(p2));
	tmp1[strlen(p2)-strlen(p2)]='\0';
	char *tmp2=bigminus(p1,p2,flag);
	      p1=tmp2; 
	while(!flag)
	{ 
 
		p3=bigadd(tmp0,"1");
		tmp1=tmp0;
		tmp0=p3;		
		delete []tmp1;
 
		tmp2=bigminus(p1,p2,flag);
		p4=p1;
		p1=tmp2; 
		delete []p4;
	}
	return tmp0;
	
}

 

 

 

参考文章:

大数乘法的几种算法分析及比较(2014腾讯南京笔试题)

大数乘法(Multiply Strings)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值