目录
1. 大数之四则运算总结
1.1 加法
从后往前算(即由低位向高位运算),计算的结果依次添加到结果中去,最后将结果字符串反转。
1.2 减法
原理同加法,将进位改为借位
1.3 乘法
第一个数据的第i位与第二个数据的第j位相乘存放在结果的第[i+j]个元素中,因为结果的每一位不是顺序得出,所以不方便用字符串存储,转而用数组存储。另一方面,第一步不考虑进位的问题,先将相乘的结果保存在数组中,然后对数组中的元素需要进位的按进位规则处理。
1.4 除法
利用了前面的大数相减的部分,主要思路为:以999除以9为例,两数相差两位,想让9*100=900,999可以减去9个100,然后9*10=90,余下的99可以减10个90,然后余下的9可以减去1个9,那么从前往后依次拼接每阶段得到的结果,最终得到111。
2. 加法
#include <string>
#include <iostream>
#include <sstream>
#include <algorithm>
using namespace std;
string add(string& data1, string &data2){
int len1 = data1.length();
int len2 = data2.length();
int len = min(len1,len2);
string res = "";
int carry = 0; //进位
int cur = 0; //当前位
string tmp;
size_t i = 0;
for (; i < len; i++)
{
cur = data1[len1-i-1] + data2[len2-i-1] - 2*'0' + carry; //计算当前位 从后往前算
carry = cur/10; //计算进位
cur = cur%10; //计算当前位
stringstream ss;
ss<<cur;
tmp = ss.str();
res += tmp; //添加到结果中
// cout<<res<<endl;
}
if (len1 < len2)
{
data1 = data2; //直接把较长的数给data1
}
for (; i < data1.length(); i++)
{
cur = data1[data1.length() - i - 1] - '0' + carry; //将较长的数的剩下部分添加到结果中
carry = cur/10;
cur = cur % 10;
stringstream ss;
ss<<cur;
tmp = ss.str();
res += tmp;
}
if (carry > 0)
{
res += carry;
}
// cout<<"res:"<<res<<endl;
reverse(res.begin(), res.end()); //将结果反转
// cout<<"res:"<<res<<endl;
return res;
}
int main()
{
string data1 = "123456";
string data2 = "1234567";
string res = add(data1,data2);
cout<<"res:"<<res<<endl;
return 0;
}
3. 减法
基本思路和加法类似,进位变为借位,在运算之前需要判断正负,将大的数放在被减数上,因此,在需要的时候将被减数和减数调换一下位置。
#include <string>
#include <iostream>
#include <sstream>
#include <algorithm>
using namespace std;
string sub(string &data1, string &data2)
{
int len1 = data1.length();
int len2 = data2.length();
bool isNeg = false; //判断是否为负
int cur = 0; // 当前位
int carry = 0; //借位
string res = "";
if (len1 < len2) //很重要,在做运算前,将大的数作为被减数,这样可以避免很多问题
{
isNeg = true;
string tmp = data1; //被减数小于减数,则调换位置,数据和长度都要调换
data1 = data2;
data2 = tmp;
len1 = data1.length();
len2 = data2.length();
}else if (len1 == len2) //当两个字符串的长度相等时,怎么判断哪个字符串比较大,这个逻辑比较有意思
{
for (size_t i = 0; i < len1; i++)
{
if (data1[i] < data2[i])
{
isNeg = true;
string tmp = data1;
data1 = data2;
data2 = tmp;
break;
}else if (data1[i] > data2[i])
{
isNeg = false;
}
}
}
int len = min(len1, len2);
size_t i = 0;
for (; i < len; i++)
{
cur = data1[len1 - i - 1] - data2[len2 - i - 1] - carry; //字符相减与整数相减一样,不用减'0'
if (cur < 0)
{
cur = cur + 10;
carry = 1;
}else
{
carry = 0;
}
stringstream ss;
ss<<cur;
string tmp = ss.str();
res += tmp;
}
for (; i < len1; i++) //将最长的字符串的剩余部分添加到结果当中
{
cur = data1[len1 - i - 1] - '0' - carry; //减去借位, 这里必须减‘0’,容易忽略
if (cur < 0)
{
cur = cur + 10;
carry = 1;
}else
{
carry = 0;
}
stringstream ss;
ss<<cur;
string tmp = ss.str();
res += tmp;
}
int index = len1 - 1;
while (res[index] == '0') //从后面开始的“0”全部去掉,找到不为0的第一个下标
{
index --;
}
res = res.substr(0,index+1);
if (res.length() == 0) //特殊情况,为零则返回“0”,避免-0的情况出现
{
return "0";
}
if (isNeg) //负数则加负号
{
res += "-";
}
reverse(res.begin(), res.end()); //与加法一样,反转
return res;
}
int main()
{
string data1 = "1234567";
string data2 = "1234567";
string res = sub(data1,data2);
cout<<"res:"<<res<<endl;
return 0;
}
4. 乘法
第一个数据的第i位与第二个数据的第j位相乘存放在结果的第[i+j]个元素中,因为结果的每一位不是顺序得出,所以不方便用字符串存储,转而用数组存储。另一方面,第一步不考虑进位的问题,先将相乘的结果保存在数组中,然后对数组中的元素需要进位的按进位规则处理。
#include <string>
#include <iostream>
#include <sstream>
#include <algorithm>
using namespace std;
string multi(string &data1, string &data2)
{
int len1 = data1.length();
int len2 = data2.length();
int cur = 0; // 当前位
int carry = 0; //借位
string result = "";
int res[5000] = {0}; //借用数组暂时存储,因为第一步不考虑进位,所以每一次相乘的结果可能大于0
for (size_t i = 0; i < len1; i++)
{
for (size_t j = 0; j < len2; j++)
{
res[i+j] += (data1[len1 - i - 1] - '0') * (data2[len2 - j - 1] - '0'); //第一个数据的第i个元素和第二个数据的第j和元素相乘存到结果的第【i+j】个元素中
//暂时不考虑进位
}
}
for (size_t i = 0; i < len1+len2+1; i++) //依次往后进位,len1长度和len2长度的数据相乘,结果的长度不超过len1+len2
{
cur = (res[i] + carry) % 10;
carry = (res[i] + carry) / 10;
res[i] = cur;
}
size_t index = len1+len2;
for (; index >=0; index--)
{
if (res[index] != 0)
{
break;
}
}
for (int i = index; i >= 0; i--)
{
stringstream ss;
ss<<res[i];
string tmp = ss.str();
result += tmp;
}
return result;
}
int main()
{
string data1 = "999";
string data2 = "99";
string res = multi(data1,data2);
cout<<"res:"<<res<<endl;
return 0;
}
5. 除法
利用了前面的大数相减的部分,主要思路为:以999除以9为例,两数相差两位,想让9*100=900,999可以减去9个100,然后9*10=90,余下的99可以减10个90,然后余下的9可以减去1个9,那么从前往后依次拼接每阶段得到的结果,最终得到111。
#include <string>
#include <iostream>
#include <sstream>
#include <algorithm>
using namespace std;
bool sub(string &data1, string &data2)
{
int len1 = data1.length();
int len2 = data2.length();
bool isNeg = false; //判断是否为负
int cur = 0; // 当前位
int carry = 0; //借位
string res = "";
if (len1 < len2) //很重要,在做运算前,将大的数作为被减数,这样可以避免很多问题
{
return false;
}else if (len1 == len2) //当两个字符串的长度相等时,怎么判断哪个字符串比较大,这个逻辑比较有意思
{
for (size_t i = 0; i < len1; i++)
{
if (data1[i] < data2[i])
{
return false;
}else if (data1[i] > data2[i])
{
isNeg = false;
}
}
}
int len = min(len1, len2);
size_t i = 0;
for (; i < len; i++)
{
cur = data1[len1 - i - 1] - data2[len2 - i - 1] - carry; //字符相减与整数相减一样,不用减'0'
if (cur < 0)
{
cur = cur + 10;
carry = 1;
}else
{
carry = 0;
}
stringstream ss;
ss<<cur;
string tmp = ss.str();
res += tmp;
}
for (; i < len1; i++) //将最长的字符串的剩余部分添加到结果当中
{
cur = data1[len1 - i - 1] - '0' - carry; //减去借位, 这里必须减‘0’,容易忽略
if (cur < 0)
{
cur = cur + 10;
carry = 1;
}else
{
carry = 0;
}
stringstream ss;
ss<<cur;
string tmp = ss.str();
res += tmp;
}
int index = len1 - 1;
while (res[index] == '0') //从后面开始的“0”全部去掉,找到不为0的第一个下标
{
index --;
}
res = res.substr(0,index+1);
if (res.length() == 0) //特殊情况,为零则返回“0”,避免-0的情况出现
{
data1 = res;
return true;
}
if (isNeg) //负数则加负号
{
res += "-";
}
reverse(res.begin(), res.end()); //与加法一样,反转
data1 = res;
return !isNeg;
}
string div(string &data1, string &data2)
{
int len1 = data1.length();
int len2 = data2.length();
int cur = 0; // 当前位
int carry = 0; //借位
string result = "";
if (len1 < len2) //如果被除数小于除数则直接返回“0”
{
return "0";
}else if (len1 == len2)
{
for (size_t i = 0; i < len1; i++)
{
if (data1[i] < data2[i])
{
return "0";
}else if (data1[i] > data2[i])
{
break;
}
}
}
int count = len1 - len2; //两个数相差几位
int res[100] = {0};
for (int i = count; i >=0; i--)
{
string data2_copy = data2;
for (size_t j = 0; j < i; j++)
{
data2_copy += "0"; //后面补0,如果补两个0则为100倍
}
while (sub(data1,data2_copy))
{
res[count - i] ++; //能减多少个,从能减的最大数开始减起,直到不能减
}
stringstream ss;
ss<< res[count - i];
string tmp = ss.str();
result += tmp; //依次将能减的数拼接,利用前面写的大数相减
}
return result;
}
int main()
{
string data1 = "999";
string data2 = "99999";
string res = div(data1,data2);
cout<<"res:"<<res<<endl;
return 0;
}
6. 参考文献
1. https://www.cnblogs.com/wuqianling/p/5387099.html (大数的四则运算(加法、减法、乘法、除法))