对我们已知的能进行四则运算的数据类型,就算最长的长长整型也是拥有它的极限长度的,所以对于更大的数的四则运算,我们就要选择其他的类型进行接收,并定义适合它们的算法:
这个案例中建议选择,string类型数据去接收要计算的大数,再将其转成int型储存在动态容器vector中,可以方便的去实现我们这个案例
具体实现代码和算法都放在了下面,注释很详细。
实现效果:(测试懒得敲太多数,用小一点的数方便检测)直接上代码:
具体思路看注释:
#include <iostream> #include <vector> #include <string> #include <cmath> #include<algorithm> using namespace std; class Compute { public: Compute() {}; ~Compute() {}; virtual void compute(string& strA, string& strB) = 0; }; class Add : public Compute //这是加法类 { public: virtual void compute(string& strA, string& strB) override; }; void Add::compute(string& strA, string& strB) { vector<int> a; //第一个容器存放第一个数 vector<int> b; //第二个容器存放第二个数 vector<int> sum; //和容器存放俩数之和 int index = 0; //设置进位 //首先将俩个数保存在容器中 //并且是逆序保存 为了迎合容器的Pushback添加函数 for (int i = strA.size() - 1; i >= 0; i--) { a.push_back(strA[i] - '0'); } for (int i = strB.size() - 1; i >= 0; i--) { b.push_back(strB[i] - '0'); } //然后开始加法算法,对两个数逐位相加 //首先我们不管俩个数的长度大小,一直加到最短的那个数完全被加 for (int i = 0; i < strA.size() && i < strB.size(); i++) { sum.push_back((a[i] + b[i] + index) % 10); //将逐位相加的结果储存在sum容器中 index = (a[i] + b[i] + index) / 10; //满10则进行进位 } //然后开始考虑长度比较长的数的多余位置没有参加算法 if (strA.size() > strB.size()) { //这是A的长度比b大的情况,这时候已经计算到了b的长度位上 for (int i = strB.size(); i < strA.size(); i++) { sum.push_back((index + a[i]) % 10); index = (a[i] + index) / 10; } } if (strB.size() > strA.size()) { //这是B的长度比A大的情况,这时候已经计算到了a的长度位上 for (int i = strA.size(); i < strB.size(); i++) { sum.push_back((index + b[i]) % 10); index = (index + b[i]) / 10; } } //计算完毕后判断进位 如果进位不为空那么还要往前进1 if (index != 0) { sum.push_back(1); index = 0; //并且清空进位 } //到这里已经完成加法算法 //下面为输出代码 //由于使用的容器较多,我选择使用迭代器输出sum vector容器里的数据 即为最后的结果 cout << strA << "+" << strB << "="; for (vector<int>::iterator it = sum.end() - 1; it >= sum.begin(); it--) { cout << *it; if (it == sum.begin()) { break; } } cout << endl; //最后一步使用vector容器与自身交换 用来清空多余的无用内存 vector<int>().swap(a); vector<int>().swap(b); vector<int>().swap(sum); //函数结束 } class Sub : public Compute //这是减法类 { public: virtual void compute(string& strA, string& strB) override; int Comparevector(vector<int>a, vector<int>b);//声明减法内置比较函数 }; void Sub::compute(string& strA, string& strB) //对基类计算函数进行重写 { vector<int> a; //容器a存入第一个数据 vector<int> b; //容器b存入第二个数据 vector<int> difvalue; //差值容器存入最后结果 int lend = 0; //定义借位数 //添加这一步是若两数相等则直接给结果,不需要经过算法; if (strA == strB) { difvalue.push_back(0); goto flag; } //因为减法运算还是从低位开始 那么我们还是 将数据倒序存入 for (int i = strA.size() - 1; i >= 0; i--) { a.push_back(strA[i] - '0'); } for (int i = strB.size() - 1; i >= 0; i--) { b.push_back(strB[i] - '0'); } //下面开始减法算法 //我选择使用绝对值算法 -> 首先放正负到一边,计算之前判断谁大谁小,保证永远使用大数减小数,最后再进行符号讨论; if (Comparevector(a, b) != 0) { //首先计算位数相同的地方 for (int i = 0; i < strB.size(); i++) { if (a[i] < b[i]) { for (int j = i + 1; j < strA.size(); j++) { //向高位借位,如果高位不为0,则可以正常借到; if (a[j] != 0) { lend = 1; a[j] -= 1; break; } //如果高位为0,则向更高位借,0上有借位看为9; else { a[j] = 9; } } difvalue.push_back(lend * 10 + a[i] - b[i]); lend = 0; } else { difvalue.push_back(a[i] - b[i]); } } for (int i = strB.size(); i < strA.size(); i++) { difvalue.push_back(a[i]); } } else { //之后算法和之前相同 //首先计算位数相同的地方 for (int i = 0; i < strA.size(); i++) { if (b[i] < a[i]) { for (int j = i + 1; j < strB.size(); j++) { //向高位借位,如果高位不为0,则可以正常借到; if (b[j] != 0) { lend = 1; b[j] -= 1; break; } //如果高位为0,则向更高位借,0上有借位看为9; else { b[j] = 9; } } difvalue.push_back(lend * 10 + b[i] - a[i]); lend = 0; } else { difvalue.push_back(b[i] - a[i]); } } for (int i = strA.size(); i < strB.size(); i++) { difvalue.push_back(b[i]); } } //删 除 前 导 0 for (int i = difvalue.size() - 1; i >= 0; i--) { if (difvalue[i] == 0) { difvalue.erase(difvalue.begin() + i); } else { break; } } //减法算法结束 //下面为用迭代器输出 flag: cout << strA << "-" << strB << "="; //如果A比B小需要输出负号 if (Comparevector(a, b) == 0) { cout << "-"; } for (vector<int>::iterator it = difvalue.end() - 1; it >= difvalue.begin(); it--) { cout << *it; if (it == difvalue.begin()) { break; } } cout << endl; //清内存 vector<int>().swap(a); vector<int>().swap(b); vector<int>().swap(difvalue); } int Sub::Comparevector(vector<int>a, vector<int>b)//比较俩个vector容器内置的数的大小,传入的容器存的数是倒序的! { //a比b打则返回1 a比b小则返回0 a与b等于则返回3 //首先将数变成正序 reverse(a.begin(), a.end()); reverse(b.begin(), b.end()); if (a.size() > b.size()) return 1; if (a.size() < b.size()) return 0; if (a.size() == b.size()) { for (int i = 0; i < a.size(); i++) { if (a[i] > b[i]) return 1; if (a[i] < b[i]) return 0; } return 3; } } class Mul : public Compute //这是乘法类 { virtual void compute(string& strA, string& strB) override; vector<int> Muladd(vector<int>& a, vector<int>& b); //定义 乘法内置加法函数 }; void Mul::compute(string& strA, string& strB) { vector<int> a; // a容器中存放第一个数 vector<int> b; // b容器中存放第二个数 vector<int> product; // product容器中存放俩数的乘积 vector<int> temp; // temp容器为工具容器 用于储存 计算过程中的步骤 int index = 0; //定义进位为0 Index //乘法也是从小位开始算起 所以也采用逆序储存逆序输出 for (int i = strA.size() - 1; i >= 0; i--) { a.push_back(strA[i] - '0'); } for (int i = strB.size() - 1; i >= 0; i--) { b.push_back(strB[i] - '0'); } for (int i = 0; i < b.size(); i++) { for (int j = 0; j < a.size(); j++) { temp.push_back((a[j] * b[i] + index) % 10); index = (a[j] * b[i] + index) / 10; } for (int j = 0; j < i; j++) { temp.insert(temp.begin(), 0); } //执行加法 加法执行完毕后清空temp容器 product = Muladd(temp, product); temp.clear(); } if (index != 0) { product.push_back(index); } //乘法计算结束 //接下来为 迭代器输出储存乘积的容器 product cout << strA << "*" << strB << "="; for (vector<int>::iterator it = product.end() - 1; it >= product.begin(); it--) { cout << *it; if (it == product.begin()) { break; } } cout << endl; //输出完毕 接下来进行容器清内存 vector<int>().swap(a); vector<int>().swap(b); vector<int>().swap(temp); vector<int>().swap(product); } //对乘法内置加法函数的类外定义 vector<int> Mul::Muladd(vector<int>& a, vector<int>& b) { //这个函数是实现两个容器的大数数据相加 与加法类一致 int index = 0; //设置进位 vector<int> sum; //设置存放俩数和的容器 最后需要返回这个容器 for (int i = 0; i < a.size() && i < b.size(); i++) { sum.push_back((index + a[i] + b[i]) % 10); index = (a[i] + b[i] + index) / 10; } //相等的位数已经相加完毕 //接下来相加 独立的位数 if (a.size() > b.size()) { for (int i = b.size(); i < a.size(); i++) { sum.push_back((a[i] + index) % 10); index = (a[i] + index) / 10; } } if (a.size() < b.size()) { for (int i = a.size(); i < b.size(); i++) { sum.push_back((b[i] + index) % 10); index = (b[i] + index) / 10; } } if (index != 0) { sum.push_back(1); } //计算完毕 返回算出的和容器vector //注意 这时候的 vector 仍然是小数在左。大数在右 return sum; } class Division :public Compute//除法类 { virtual void compute(string& strA, string& strB) override; vector <int> divsub(vector<int>a, vector<int>b);//声明除法内置减法运算 运行的是第一个数减去第二个数 int Compatrvector(vector<int>& a, vector<int>& b);//声明比较容器储存的数的大小的函数 }; void Division::compute(string& strA, string& strB) { vector<int>a;//a容器存放第一个数 vector<int>b;//b容器存放第二个数 vector<int>div;//div容器存放商 //读取环节 //因为除法的运算是从高位往低位进行运算 那么我们选择正向输入以方便运算 for (int i = 0; i < strA.size(); i++) { a.push_back(strA[i] - '0'); } for (int i = 0; i < strB.size(); i++) { b.push_back(strB[i] - '0'); } //开始除法算法 //1.将被除数位数用0补齐使得其长度和除数的长度相等 //为了保留ab容器 利用复制构造创建新容器 vector<int> B(b); vector<int> temp(a); //首先可以直接判断 俩数大小关系 如果前小于后直接输出0,没必要进行以下算法 if (Compatrvector(a, b) == 0) { cout << strA << "/" << strB <<"=" << 0; return; } if (b.size() == a.size()) { int j = 0; while (Compatrvector(temp, B)!=0) { temp = divsub(temp, B); j++; } cout << strA << "/" << strB << "=" << j << endl; return; } int i; for (int i = B.size(); i < a.size(); i++) { B.push_back(0); } //2.判断补齐后的被除数与除数的大小关系(过程中不断更新除数,即每次差求商的余数) //->如果被除数的数值大于除数的数值 那么对被补齐的被除数进行退位操作,即退掉末位0 (似乎可以使用肯尼汉算法) //->如果被除数的数值小于除数的数值 那么进行除数循环减被除数求商 直到除数小于被除数 //对以上操作进行循环 //退出循环的条件 :补足的0已经退完 并且此时的除数小于被除数 while (B.size() > b.size()) { //这个只限于长度不相等 如果长度相等直接做减法很快得出答案! if (Compatrvector(B, temp) == 1) { B.pop_back(); if (Compatrvector(B, temp) == 1) { div.push_back(0); } } if (Compatrvector(B, temp) != 1) { for (i = 1; i != 1.1; i++) { temp = divsub(temp, B); if (Compatrvector(temp, B) == 0) { div.push_back(i); i = 1; break; } } } } //除法算法结束 //接下来为迭代器输出 cout << strA << "/" << strB << "="; for (vector<int>::iterator it = div.begin(); it < div.end(); it++) { cout << *it; } //清理内存 vector<int>().swap(a); vector<int>().swap(b); vector<int>().swap(temp); vector<int>().swap(div); } vector<int>Division::divsub(vector<int>a, vector<int>b)//为了防止参数被改变 采用 值传递 { vector<int> difvalue; //既然在除法里面的减法合理,那么一定是大数减小数 这里默认a>b //因为传进来的容器是正序的 所以为了计算方便 我们需要做倒序处理 reverse(a.begin(), a.end()); reverse(b.begin(), b.end()); int lend = 0;//初始化借位 //既然已经默认了 a>b 那么a的位数一定大于等于b的位数 for (int i = 0; i < b.size(); i++) { if (a[i] < b[i]) { for (int j = i + 1; j < a.size(); j++)//a向高位非0数借位 { if (a[j] != 0) { a[j] -= 1; lend = 1; break; } else { a[j] = 9;//向0借位为9 } } } difvalue.push_back(lend * 10 + a[i] - b[i]); lend = 0; } //接下来为a多出的位数 for (int i = b.size(); i < a.size(); i++) { difvalue.push_back(a[i]); } //然后要让差恢复正常顺序 reverse(difvalue.begin(), difvalue.end()); for (int i = 0; i != 1.1; i++) { //删除前导0 if (difvalue[0] == 0&&difvalue.size()!=1) { difvalue.erase(difvalue.begin(), difvalue.begin() + 1); } else { break; } } return difvalue; } int Division::Compatrvector(vector<int>& a, vector<int>& b)//这是内置在除法类中的比较函数 用于比较俩个正向储存的容器数的大小 //若a>b 则返回1 小于则返回0 相等则返回3 { if (a.size() > b.size()) return 1; if (a.size() < b.size()) return 0; if (a.size() == b.size()) { for (int i = 0; i < a.size(); i++) { if (a[i] > b[i]) return 1; if (a[i] < b[i]) return 0; } return 3; } } int main() { //首先询问用户需要输入的两个大数 string strA, strB; char idea; cout << "**************欢迎使用高精度计算器**************" << endl << endl; cout<< "**************输入E X E退出计算器**************" << endl << endl; cout << "请输入你要计算的算式(符号数字之间由空格隔开)<示例:1空格+空格1>:" << endl; flag: cin >> strA >> idea >> strB; if (strA == "E" && strB == "E" && idea == 'X') { goto tp; } //计算大类我使用了多态 下面对函数进行调用 基类指针指向派生类 switch (idea) { case '+': { Compute* add = new Add; add->compute(strA, strB); if (add != NULL) { delete add; add = nullptr; } break; } case '-': { Compute* sub = new Sub; sub->compute(strA, strB); if (sub != NULL) { delete sub; sub = nullptr; } break; } case '*': { Compute* mul = new Mul; mul->compute(strA, strB); if (mul != NULL) { delete mul; mul = nullptr; } break; } case'/': { Compute* division = new Division; division->compute(strA, strB); if (division != NULL) { delete division; division = nullptr; } break; } } cout<<endl << "————————————————————————" << endl; goto flag; tp: cout<< "*************--===感谢您的使用===--*************" << endl << endl; return 0; }