1. 程式人生 > >C++實現大數運算(加減乘除求餘)

C++實現大數運算(加減乘除求餘)

前言:
只有部分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);
}

執行結果展示:
例子:多位數的小數相加:

這下子就不怕資料超出範圍了,歡迎一起探討,一起交流。