博主主页:@ᰔᩚ. 一怀明月ꦿ
❤️专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++
座右铭:“不要等到什么都没有了,才下定决心去做”
大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点
目录
概念
大数加法
加法原理
编程分析
大数乘法
乘法原理
编程分析
(1)累加法
(2)直接乘积法
效率对比
结果
计算机发明的初衷就是解决以人类计算能力无法有效解决的问题,这类问题包括反复多次的复杂运算也包括天文级数字的运算,但就c语言的初步学习可以发现,不论是int还是float乃至更大的unsigned long long int和double形式的数据都是有极限的。一般形式的数据里最大的整型是unsigned long long int,极限为18446744073709551615,是10^19次方的数量级,就日常生活的问题可能足够了,但以计算机的计算能力而言远远不够。
例如64位下的一个整形为例,一个整形四个字节,32bit位,存储的最大数据为4294967296,然而4294967295只有10位,如果字符数组存储只需两个字节,而且数组长度可以非常大。所以用字符数组存储数据,模拟计算数据去解决天文级数字的运算等难题。
加法原理
进行计算之前,我们先明白加法的原理
例如 12+9=21
2+9+0(余数)=11
余数:1
取模:1
1+1(余数)=2
余数:0
取模:2
所以等于21
转化为编程思想:
例如 12+9=21
str:string的对象,next:表示进位
next=0;
str:”"
2+9+next=11
next=1
str:”1”
1+0+next=2
next=0
str:”12”
最后逆置一下str,str:”21"
编程分析
string addStrings(string num1, string num2)//num1存储第一个数据,num2存储第二个数据 { int end1=num1.size()-1,end2=num2.size()-1;//这里我们获取每个数据的最后一位数的下标,因为我们进行计算,都是从最后一位数计算的 int next=0;//表示的进位 string str;//存储两个数据之和的对象 while(end1>=0||end2>=0)//值得注意的是,我们对两个数据相加,是对每一个数据对应位相加,但如果一个数据min的位数少于另一位max数据,我们不能停止相加,只是max多余的位都加0而已,所以这里的循环结束的条件是,两个数据遍历完才停止。 { //我们存储数据是用字符数组,计算数据还是以整形计算 int x1=end1>=0?num1[end1]-'0':0;//x1就是获取一个数据end1下标的数据,之所以会减'0',在num存储的数据是字符,只要减'0'才是对应的整数。end1>=0?num1[end1]-'0':0如果num1数据遍历完了,就会让x1的值为0 int x2=end2>=0?num2[end2]-'0':0;//x2就是获取一个数据end2下标的数据,之所以会减'0',在num存储的数据是字符,只要减'0'才是对应的整数。end2>=0?num2[end2]-'0':0如果num2数据遍历完了,就会让x2的值为0 int ret=x1+x2+next;//计算两个数据对应位之和 next=ret/10;//两个数据对应位之和大于等于10,就会产生进位 ret=ret%10;//两个数据对应位之和小于10 str+=ret+'0’;//存储两个数据对应位之和小于10的部分 end1--,end2—;//让两个数据的下标往前移动 } reverse(str.begin(),str.end());//因为str存储的数据是相反的,所以需要逆置一下,reverse是string类里的逆置函数 if(next==1)//就是两个数据相加时,最后一位也可能产生进位,例如:98+3,str里只保存了01,而最高位的1还没有保存就跳出循环了,所以在这里,可以将进位头插在str中 str.insert(0,1,'1’);//在str下标为0处插入1个’1' return str; }
乘法原理
进行计算之前,我们先明白乘法的原理
例如 25*12=300
5*2+0(余数)=10
取余:1
取模:0
2*2+1(余数)=5
取余:0
取模:5
个位乘积:50
5*1+(余数)=5
取余:0
取模:5
2*1+(余数)=2
取余:0
取模:2
十位乘积:25
总积:25*10+50=300
转化为编程思想:
例如 25*12=300
strN:string的对象,str:string的对象,next:表示进位
next=0
str=“”
strN=“0”
5*2+next=10
next=1
str=“0”
2*2+next=5
next=0
str=“05”
strN=strN+“50”
next=0
str=“”
5*1+next=5
next=0
str=“5”
2*1+next=2
next=0
str=“52”
strN=strN+”250”
strN=“300"
编程分析
(1)累加法
其实,乘法可以转换为加法,例如25*12,我们可以将25累加12次,这样也能达到乘法的效果。
缺陷:效率低
string multiply_1(string num1, string num2)//num1存储第一个数据,num2存储第二个数据 { string strN=num1;//strN时记录乘积总和的对象,我们将num2的数据传递strN int n=0;//n是存储的是num2整形的数字,例如num2=“123”,n=123 for(int i=0,j=pow(10,num2.size()-1);i
=0||end2>=0) { int x1=end1>=0?num1[end1]-'0':0;//x1就是获取一个数据end1下标的数据,之所以会减'0',在num存储的数据是字符,只要减'0'才是对应的整数。end1>=0?num1[end1]-'0':0如果num1数据遍历完了,就会让x1的值为0 int x2=strN[end2]-'0';//x2就是获取一个数据end2下标的数据,之所以会减'0',在strN存储的数据是字符,只要减'0'才是对应的整数。 int ret=x1+x2+next;//计算两个数据对应位之和 next=ret/10;//两个数据对应位之和大于等于10,就会产生进位 ret=ret%10;//两个数据对应位之和小于10 str+=ret+'0';//存储两个数据对应位之和小于10的部分 end1--,end2--;//让两个数据的下标往前移动 } reverse(str.begin(),str.end());//因为str存储的数据是相反的,所以需要逆置一下,reverse是string类里的逆置函数 if(next==1)//就是两个数据相加时,最后一位也可能产生进位,例如:98+3,str里只保存了01,而最高位的1还没有保存就跳出循环了,所以在这里,可以将进位头插在str中 str.insert(0,1,'1');//在str下标为0处插入1个’1' strN=str;//将str的数据传递给strN } return strN; } (2)直接乘积法
直接通过,乘法的计算原理进行计算
string multiply(string num1, string num2)//num1存储第一个数据,num2存储第二个数据 { int end2=num2.size()-1;//这里我们获取每个数据的最后一位数的下标,因为我们进行计算,都是从最后一位数计算的 string strN("0”);//strN是记录乘积总和的对象,初始值为’0' int flag=-1;//是一个标志 while(end2>=0&&(num1[0]!='0'&&num2[0]!='0’))//只要遍历完num2中的数据就结束运算,还有如果num1和num2中只要有一个为’0'就结束运算 { int end1=num1.size()-1;//这里我们获取每个数据的最后一位数的下标,因为我们进行计算,都是从最后一位数计算的 string str;//记录每次num1中的数据和num2中每一位值的乘积 int next=0;//进位 int x2=num2[end2]-'0’;//x2就是获取一个数据end2下标的数据,之所以会减'0',在strN存储的数据是字符,只要减'0'才是对应的整数。 while(end1>=0)//遍历num1中的数据 { int x1=num1[end1]-'0';//x1就是获取一个数据end1下标的数据,之所以会减'0',在num存储的数据是字符,只要减'0'才是对应的整数。 int ret=x1*x2+next;//计算num1每一位和num1每一位的乘积 next=ret/10;//num1每一位和num1每一位的乘积大于10,就会产生进位 ret=ret%10;//num1每一位和num1每一位的乘积小于10的值 str+=ret+'0’;//存储num1每一位和num1每一位的乘积小于10的值 end1—;//让num1数据的下标往前移动 } flag++;//标志+1 end2--;//让num2数据的下标往前移动 reverse(str.begin(),str.end());//因为str存储的数据是相反的,所以需要逆置一下,reverse是string类里的逆置函数 int count=flag;//传递标志的值 while(count—)//num2每一位值和num1数据乘积等级是不同的,num1第一位是个位,第二位是位,第三位是千位…,所以str存储数据是应该加上对应数目的’0' { str+='0'; } char ch=next+'0'; if(next!=0)//就是num2每一位值和num1数据乘积时,最后一位也可能产生进位,例如:98*3,str里只保存了94,而最高位的2还没有保存就跳出循环了,所以在这里,可以将进位头插在str中 str.insert(0,1,ch); strN=addStrings(strN, str);//将num2每一位值和num1数据乘积累加给strN,addStrings是我们前面提到的大数加法 } return strN; }
效率对比
同时计算999999*999999,看所需要的时间
#include
#include using namespace std; string multiply_1(string num1, string num2) { string strN=num1; int n=0; for(int i=0,j=pow(10,num2.size()-1);i =0||end2>=0) { int x1=end1>=0?num1[end1]-'0':0; int x2=strN[end2]-'0'; int ret=x1+x2+next; next=ret/10; ret=ret%10; str+=ret+'0'; end1--,end2--; } reverse(str.begin(),str.end()); if(next==1) str.insert(0,1,'1'); strN=str; } return strN; } //25 // 3 //next=0 //5*3+next=15 //next=1 //str:5 //2*3+next=7 //str:57 //75 string addStrings(string num1, string num2) { int end1=num1.size()-1,end2=num2.size()-1; int next=0; string str; while(end1>=0||end2>=0) { int x1=end1>=0?num1[end1]-'0':0; int x2=end2>=0?num2[end2]-'0':0; int ret=x1+x2+next; next=ret/10; ret=ret%10; str+=ret+'0'; end1--,end2--; } reverse(str.begin(),str.end()); if(next==1) str.insert(0,1,'1'); return str; } string multiply(string num1, string num2) { int end2=num2.size()-1; string strN("0"); int flag=-1; while(end2>=0&&(num1[0]!='0'&&num2[0]!='0')) { int end1=num1.size()-1; string str; int next=0; int x2=num2[end2]-'0'; while(end1>=0) { int x1=num1[end1]-'0'; int ret=x1*x2+next; next=ret/10; ret=ret%10; str+=ret+'0'; end1--; } flag++; end2--; reverse(str.begin(),str.end()); int count=flag; while(count--) { str+='0'; } char ch=next+'0'; if(next!=0) str.insert(0,1,ch); strN=addStrings(strN, str); } return strN; } int main() { string s1,s2; cin>>s1>>s2; size_t begin_1=clock(); cout<<"累加法的值:"< 结果
结果:
999999 999999
累加法的值:999998000001
累加法的时间:51161310^-3ms
直接乘积法的值:999998000001
直接乘积法的时间:1210^-3ms
如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家!