C++實現大數運算(加減乘除求餘)
阿新 • • 發佈:2019-02-11
前言:
只有部分GCC編譯器支援int128,而我們平常使用的軟體,最大隻有_int64.當這些不夠用時,我們該怎麼辦?
我本身想寫程式碼實現整數型大資料的加減乘除和求餘,結果寫著寫著想著連小數運算的也一起寫上(反正加的程式碼不多)
電腦是死的,人是活的,當資料超出範圍時,我們可以想其他方法去算,在這裡,我使用string類來存資料,string類的容量足夠大,相信夠一般大資料使用了吧。
編譯軟體:vs2013
程式功能: 大型整數、小數的加、減、乘、除、求餘
程式碼:
main.cpp
#include <iostream> #include<string> #include<cmath> #include "large.h" using namespace std; int main() { char ch; string m_snum1, m_snum2; while (cin>>m_snum1>>ch>>m_snum2) { large _large(m_snum1, ch, m_snum2); } return 0; }
large.h
#include <iostream> #include<string> using namespace std; class large { public: large(){} large(string m_str1, char m_ch, string m_str2); //兩數的運算 inline int compare(string str1, string str2); //相等返回0,大於返回1,小於返回-1 string SUB_INT(string str1, string str2); //高精度減法 string ADD_INT(string str1, string str2); //高精度加法 string MUL_INT(string str1, string str2); //高精度乘法 string DIVIDE_INT(string str1, string str2, int flag); //高精度除法,flag==1,返回商;flag==0時,返回餘數 string DIV_INT(string str1, string str2); //高精度除法,返回商 string MOD_INT(string str1, string str2); //高精度除法,返回餘數 large(large &e); //拷貝構造 ~large(){}; //解構函式 };
large.cpp
#include <iostream> #include<string> #include<cmath> #include "large.h" using namespace std; large::large(string m_str1, char m_ch, string m_str2)//兩數的運算 { int m_ilocation1 ; int m_ilocation2 ; string m_res; int m_istr; if (m_str1.find_first_of(".") == -1) m_ilocation1 = 0; else m_ilocation1 = m_str1.length() - m_str1.find_first_of(".") - 1; if (m_str2.find_first_of(".") == -1) m_ilocation2 = 0; else m_ilocation2 = m_str2.length() - m_str2.find_first_of(".") - 1; if (m_ilocation1 == 0 && m_ilocation2 == 0) { switch (m_ch) { case'+': m_res = ADD_INT(m_str1, m_str2); break; case'-': m_res = SUB_INT(m_str1, m_str2); break; case'*': m_res = MUL_INT(m_str1, m_str2); break; case'/': m_res = DIV_INT(m_str1, m_str2); break; case'%': m_res = MOD_INT(m_str1, m_str2); break; default: break; } } else { int m_ilocat = m_ilocation1 - m_ilocation2; int m_ilocation3; if (m_ilocation1!=0) m_str1.erase(m_str1.find_first_of("."), m_str1.find_first_not_of(".") + 1); if (m_ilocation2!=0) m_str2.erase(m_str2.find_first_of("."), m_str2.find_first_not_of(".") + 1); switch (m_ch) { case'+': if (m_ilocat >= 0) { for (int i = 0; i < m_ilocat; i++) m_str2 = m_str2 + '0'; m_ilocation3 = m_ilocation1; } else { for (int i = 0; i < -m_ilocat; i++) m_str1 = m_str1 + '0'; m_ilocation3 = m_ilocation2; } m_res = ADD_INT(m_str1, m_str2); m_istr = m_res.length(); for (int i = 0; i < m_ilocation3; i++) m_istr = m_istr - 1; m_res.insert(m_istr, "."); break; case'-': if (m_ilocat >= 0) { for (int i = 0; i < m_ilocat; i++) m_str2 = m_str2 + '0'; m_ilocation3 = m_ilocation1; } else { for (int i = 0; i < -m_ilocat; i++) m_str1 = m_str1 + '0'; m_ilocation3 = m_ilocation2; } m_res = SUB_INT(m_str1, m_str2); m_istr = m_res.length(); for (int i = 0; i < m_ilocation3; i++) m_istr = m_istr - 1; m_res.insert(m_istr, "."); break; case'*': m_ilocation3=m_ilocation1+m_ilocation2; m_res = MUL_INT(m_str1, m_str2); m_istr = m_res.length(); for (int i = 0; i < m_ilocation3; i++) m_istr = m_istr - 1; m_res.insert(m_istr, "."); break; case'/': if (m_ilocat >= 0) { for (int i = 0; i < m_ilocat; i++) m_str2 = m_str2 + '0'; } else { for (int i = 0; i < -m_ilocat; i++) m_str1 = m_str1 + '0'; } m_res = DIV_INT(m_str1, m_str2); break; case'%': m_res = MOD_INT(m_str1, m_str2); break; default: break; } } cout << endl; cout << m_res << endl; } inline int large::compare(string str1, string str2) //相等返回0,大於返回1,小於返回-1 { if (str1.size() > str2.size()) return 1; else if (str1.size() < str2.size()) return -1; else return str1.compare(str2); //若長度相等,則從頭到尾按位比較 } string large::ADD_INT(string str1, string str2) //高精度加法 { int sign = 1;//sign為符號為 string str; if (str1[0] == '-') { if (str2[0] == '-') //負負 { sign = -1; str = ADD_INT(str1.erase(0, 1), str2.erase(0, 1));//erase(first,last);刪除從first到last之間的字元 } else //負正 { str = SUB_INT(str2, str1.erase(0, 1)); } } else { if (str2[0] == '-') //正負 { str = SUB_INT(str1, str2.erase(0, 1)); } else //正正,把兩個整數對齊,短整數前面加0補齊 { string::size_type L1, L2; //string::size_type抽象意義是尺寸單位型別 int i; L1 = str1.size(); L2 = str2.size(); if (L1 < L2) { for (i = 0; i < L2 - L1; i++) str1 = "0" + str1; } else { for (i = 0; i < L1 - L2; i++) str2 = "0" + str2; } int int1 = 0, int2 = 0; //int2記錄進位 for (i = str1.size() - 1; i >= 0; i--) { int1 = (int(str1[i]) - '0' + int(str2[i]) - '0' + int2) % 10; int2 = (int(str1[i]) - '0' + int(str2[i]) - '0' + int2) / 10; str = char(int1 + '0') + str; } if (int2 != 0)str = char(int2 + '0') + str; } } //運算子處理符號 if ((sign == -1) && (str[0] != '0'))str = "-" + str; return str; } string large::SUB_INT(string str1, string str2) //高精度減法 { int sign = 1; //sign為符號位 string str; int i, j; if (str2[0] == '-') { str = ADD_INT(str1, str2.erase(0, 1)); } else { int res = compare(str1, str2); if (res == 0)return "0"; if (res < 0) { sign = -1; string temp = str1; str1 = str2; str2 = temp; } string::size_type tempint; tempint = str1.size() - str2.size(); for (i = str2.size() - 1; i >= 0; i--) { if (str1[i + tempint] < str2[i]) //借位 { j = 1; while (1) { if (str1[tempint - j + i] == '0') { str1[i + tempint - j] = '9'; j++; } else { str1[i + tempint - j] = char(int(str1[i + tempint - j]) - 1); break; } } str = char(str1[i + tempint] - str2[i] + ':') + str; } else { str = char(str1[i + tempint] - str2[i] + '0') + str; } } for (i = tempint - 1; i >= 0; i--) str = str1[i] + str; } //去出結果中多餘的前導0 str.erase(0, str.find_first_not_of('0')); if (str.empty())str = "0"; if ((sign == -1) && (str[0] != '0'))str = "-" + str; return str; } string large::MUL_INT(string str1, string str2) //高精度乘法 { int sign = 1; string str = "0"; //記錄當前值 if (str1[0] == '-') { sign *= -1; str1 = str1.erase(0, 1); } if (str2[0] == '-') { sign *= -1; str2 = str2.erase(0, 1); } int i, j; string::size_type L1, L2; L1 = str1.size(); L2 = str2.size(); for (i = L2 - 1; i >= 0; i--) //模擬手工乘法豎式 { string tempstr; int int1 = 0, int2 = 0, int3 = int(str2[i]) - '0'; if (int3 != 0) { for (j = 1; j <= (int)(L2 - 1 - i); j++) tempstr = "0" + tempstr; for (j = L1 - 1; j >= 0; j--) { int1 = (int3*(int(str1[j]) - '0') + int2) % 10; int2 = (int3*(int(str1[j]) - '0') + int2) / 10; tempstr = char(int1 + '0') + tempstr; } if (int2 != 0)tempstr = char(int2 + '0') + tempstr; } str = ADD_INT(str, tempstr); } //去除結果中的前導0 str.erase(0, str.find_first_not_of("0")); if (str.empty())str = "0"; if ((sign == -1) && (str[0] != '0'))str = "-" + str; return str; } string large::DIVIDE_INT(string str1, string str2, int flag) //高精度除法,flag==1,返回商;flag==0時,返回餘數 { string quotient, residue; //定義商和餘數 int sign1 = 1, sign2 = 1; if (str2 == "0") //判斷除數是否為0 { quotient = "ERROR!"; residue = "ERROR!"; if (flag == 1)return quotient; else return residue; } if (str1 == "0") //判斷被除數是否為0 { quotient = "0"; residue = "0"; } if (str1[0] == '-') { str1 = str1.erase(0, 1); sign1 *= -1; sign2 = -1; } if (str2[0] == '-') { str2 = str2.erase(0, 1); sign1 *= -1; } int res = compare(str1, str2); if (res < 0) { quotient = "0"; residue = str1; } else if (res == 0) { quotient = "1"; residue = "0"; } else { string::size_type L1, L2; L1 = str1.size(); L2 = str2.size(); string tempstr; tempstr.append(str1, 0, L2 - 1); //將str1中為值0到L2-1的字串追加到tempstr for (int i = L2 - 1; i < L1; i++) //模擬手工除法豎式 { tempstr = tempstr + str1[i]; tempstr.erase(0, tempstr.find_first_not_of('0')); //在字串中查詢第一個與'0'不匹配的字元,返回它的位置 if (tempstr.empty())tempstr = "0"; //q.empty(),當佇列空時,返回true for (char ch = '9'; ch >= '0'; ch--) //試商 { string str; str = str + ch; if (compare(MUL_INT(str2, str), tempstr) <= 0) { quotient = quotient + ch; tempstr = SUB_INT(tempstr, MUL_INT(str2, str)); break; } } } residue = tempstr; } //去除結果中的前導0 quotient.erase(0, quotient.find_first_not_of("0")); if (quotient.empty())quotient = "0"; if ((sign1 == -1) && (quotient[0] != '0'))quotient = "-" + quotient; if ((sign2 == -1) && (residue[0] != '0'))residue = "-" + residue; if (flag == 1)return quotient; else return residue; } string large::DIV_INT(string str1, string str2) //高精度除法,返回商 { return DIVIDE_INT(str1, str2, 1); } string large::MOD_INT(string str1, string str2) //高精度除法,返回餘數 { return DIVIDE_INT(str1, str2, 0); }
執行結果展示:
例子:多位數的小數相加:
這下子就不怕資料超出範圍了,歡迎一起探討,一起交流。