本代码可以获取命令行输入的数字和加减运算
因为较大整数的相加很可能超出整型的32位限制,或者本身就是超出限制的大数之间的加减运算。
所以我们需要单独写一个能大数相加减的函数
基本原理:把数字用字符串的形式来保存加减的结果或大数字本身就不会超出限制,比如“999999999999999999999999999999” 多长都可以
一.加法
从右往左加,要考虑相加超过10,向前进位(用bool类型的标记),个位数则push_back进结果容器中
还要考虑相加的两个字符串分别有位数剩余的情况,即比如string1比string2更长,或反之。
二.减法
考虑相减为负数,所以要先找出更大的字符串(先看是否更长),再看长度一样时哪个更大(可以直接字符串比较),让大的减小的,负号后面再加上去
而且相减时往往还需要向上一位借个1,如2 - 6,应该是12 - 6,所以为 2 - 6 + 10 = 6
也就是说,个位相减后再+10
三.改进
因为是由低到高push_back进数组,再reverse,所以push进去时,是10000,反转后是00001,我们应该去掉多余的0,让其输出1;——写个while循环解决
另外,由控制台输入数据比写死在代码中好,将其读取为字符串,注意getline(cin, m)的第二个参数只能是string类型的,所以+和-也得定义为string类型
运行结果展示:
大数相减:
1的前面没有多余的0
大数相加:
完整代码:
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
class BigInt
{
public:
BigInt(string str) : strDigit(str){ }
private:
string strDigit;//使用字符串存储大整数
//都是全局函数声明为友元
friend ostream& operator<<(ostream& out, const BigInt& src);
friend BigInt operator+(const BigInt& lhs, const BigInt& rhs);
friend BigInt operator-(const BigInt& lhs, const BigInt& rhs);
};
//打印函数
ostream& operator<<(ostream& out, const BigInt& src)
{
out << src.strDigit;
return out;
}
//大数加法
BigInt operator+(const BigInt& lhs, const BigInt& rhs) {
//从后往前遍历字符串lhs,和rhs,用flag来标记是否需要进位,结果存在result数组中(反向的)
string result;
bool flag = false;
int i = lhs.strDigit.length() - 1;//string的length和size没有区别,length是沿用C语言习惯,早先只有length
int j = rhs.strDigit.length() - 1;
for (; i >= 0 && j >= 0; --i, --j) //i 和 j其中一个会被减到负数然后退出for循环
{
int ret = lhs.strDigit[i] - '0' + rhs.strDigit[j] - '0';//单个位加减时需要减'0'转成整型,每次都重新定义一个新的ret
if (flag)
{
ret += 1;//flag为true说明此位因为上一位进位而需要多加一个1
flag = false;//再将其重新置为false
}
//两个if不能互换,否则不是下一位进1
if (ret >= 10)
{
ret %= 10;
flag = true;
}
result.push_back(ret + '0');
}
//如果遍历完,i还有剩下,第一个字符串没完
if (i >= 0)//注意要取等,因为更短的那个字符串的下标是被减到-1,而不是0,0依然说明还剩余1位
{
while (i >= 0)
{
int ret = lhs.strDigit[i] - '0';
if (flag) //前面加过来可能还有进位,然后当前可能为9,加了1之后又 = 10,又得进位,所以直接复制前面的代码
{
ret += 1;
flag = false;
}
if (ret >= 10)
{
ret %= 10;
flag = true;
}
result.push_back(ret + '0');
i--;
}
}
//第二个字符串没完
else if (j >= 0)
{
while (j >= 0)
{
int ret = lhs.strDigit[j] - '0';
if (flag) //前面加过来可能还有进位,然后当前可能为9,加了1之后又 = 10,又得进位,所以直接复制前面的代码
{
ret += 1;
flag = false;
}
if (ret >= 10)
{
ret %= 10;
flag = true;
}
result.push_back(ret + '0');
j--;
}
}
//最高位可能也进位
if (flag) {
result.push_back('1');
}
reverse(result.begin(), result.end());
return result;//result是string类,而不是BigInt,因为隐式转换,p263
//因为编译器看到该类的构造函数只接受一个实参(而且是string类的),所以可以触发隐式转换机制,定义string result时编译器也会构建一个BigInt类的临时对象,并把result赋值给他
//函数里的return本来就是返回临时对象,这个时候就返回的就是那个BigInt类的临时对象
//当然,参考书上的例子,即使后面函数用string类的result,编译器实际传入的也是BigInt的临时对象
//如某成员函数定义为func(BigInt& a){...}; 调用时传入string类 func(result);也是合法的
}
//大数减法
BigInt operator-(const BigInt& lhs, const BigInt& rhs) {
//让大的减小的,如果lhs比rhs小,则让rhs - lhs,然后最后添加负号
string result;
bool flag = false;
bool minor = false;//标记lhs是否和rhs互换了
string maxStr = lhs.strDigit;
string minStr = rhs.strDigit;
if (maxStr.length() < minStr.length())
{
//互换,让maxStr一直是最长的
maxStr = rhs.strDigit;
minStr = lhs.strDigit;
minor = true;
}
//长度一样也得比较
else if (maxStr.length() == minStr.length())
{
if (maxStr < minStr)
{
maxStr = rhs.strDigit;//让maxStr是最大的
minStr = lhs.strDigit;
minor = true;
}
else if (maxStr == minStr)
{
return string("0");
}
}
int i = maxStr.length() - 1;//i肯定大于等于j,所以后面j会先完
int j = minStr.length() - 1;
for (; i >= 0 && j >= 0; --i, --j) {
int ret = maxStr[i] - minStr[j];//减法的话,char类型相减就是int型了,不用+‘0’再相减
/*if (ret >= 0)
{
result.push_back(ret + '0');
} 一定要先看标记,因为被借位的话,当前ret需要减1*/
if (flag)
{
ret -= 1;
flag = false;
}
//当前位有可能因为被借位了而减,小于0,所以紧接着判断是否为负
if (ret < 0)
{
ret += 10;// 如2 - 6,应该是12 - 6,所以为 2 - 6 + 10 = 6
flag = true;
}
result.push_back(ret + '0');
}
//肯定是j先完,所以不用再像加法那样判断,而是直接把i多余的处理完
while (i >= 0) {
int ret = maxStr[i] - '0';
if (flag) {
ret -= 1;
flag = false;
}
//同样的,ret可能原本是0,被借位了又为-1了
if (ret < 0) {
ret += 10;
flag = true;
}
result.push_back(ret + '0');
i--;
}
//翻转前先看看末尾有没有0,如1000,否则反转后就是0001
while(result.back() == '0')
{
result.pop_back();
}
if (minor) {
result.push_back('-');
}
reverse(result.begin(), result.end());
return result;
}
int main()
{
string s1;
string A;
string s2;
getline(cin, s1);
getline(cin, A);//把加减号定义为char会报错,getline第二个参数只能是string类型
getline(cin, s2);
BigInt int1(s1);
BigInt int2(s2);
if (A == "+") {
cout << int1 + int2 << endl;
}
if (A == "-") {
cout << int1 - int2 << endl;
}
return 0;
}