溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C++實現(xiàn)大數(shù)運算

發(fā)布時間:2020-10-13 20:20:14 來源:網(wǎng)絡(luò) 閱讀:2999 作者:zgw285763054 欄目:編程語言

項目背景:

    大數(shù)運算,顧名思義,就是很大的數(shù)值的數(shù)進行一系列的運算。

    我們知道,在數(shù)學(xué)中,數(shù)值的大小是沒有上限的,但是在計算機中,由于字長的限制,計算機所能表示的范圍是有限的,當我們對比較小的數(shù)進行運算時,如:1234+5678,這樣的數(shù)值并沒有超出計算機的表示范圍,所以可以運算。但是當我們在實際的應(yīng)用中進行大量的數(shù)據(jù)處理時,會發(fā)現(xiàn)參與運算的數(shù)往往超過計算機的基本數(shù)據(jù)類型的表示范圍,比如說,在天文學(xué)上,如果一個星球距離我們?yōu)?00萬光年,那么我們將其化簡為公里,或者是米的時候,我們會發(fā)現(xiàn)這是一個很大的數(shù)。這樣計算機將無法對其進行直接計算。

    可能我們認為實際應(yīng)用中的大數(shù)也不過就是幾百位而已,實際上,在某些領(lǐng)域里,甚至可能出現(xiàn)幾百萬位的數(shù)據(jù)進行運算,這是我們很難想象的。如果沒有計算機,那么計算效率可想而知。

    由于編程語言提供的基本數(shù)值數(shù)據(jù)類型表示的數(shù)值范圍有限,不能滿足較大規(guī)模的高精度數(shù)值計算,因此需要利用其他方法實現(xiàn)高精度數(shù)值的計算,于是產(chǎn)生了大數(shù)運算。本項目實現(xiàn)了大數(shù)運算主要的加、減、乘除四種方法。


BigData.h

#ifndef BIG_DATA_H
#define BIG_DATA_H

#include <string>

#define MAX_INT64 (INT64)0x7FFFFFFFFFFFFFFF
#define MIN_INT64 (INT64)0x8000000000000000 //如果不強轉(zhuǎn),系統(tǒng)會定義為unsigned INT64類型

#define UN_INIT 0xCCCCCCCCCCCCCCCC
typedef long long INT64;

class BigData
{
public:
	BigData(INT64 value);
	BigData(const char* pData);

public:
	BigData operator+(const BigData& bigdata);
	BigData operator-(const BigData& bigdata);
	BigData operator*(const BigData& bigdata);
	BigData operator/(const BigData& bigdata);

protected:
	std::string Add(std::string left, std::string right);
	std::string Sub(std::string left, std::string right);
	std::string Mul(std::string left, std::string right);
	std::string Div(std::string left, std::string right);	

protected:
	bool IsINT64Overflow() const;
	friend std::ostream& operator<<(std::ostream& _cout, const BigData& bigdata);
	void INT64ToString();
	bool IsLeftStrBig(const char* pLeft, int LSize, const char* pRight, int RSize);
	char SubLoop(char* pLeft, int LSize, char* pRight, int RSize);

protected:
	INT64 _value;
	std::string _strData;
};

#endif

BigData.cpp

#include "BigData.h"
#include <assert.h>

BigData::BigData(INT64 value)
	:_value(value)
{
	INT64ToString(); //將_value中的值保存在_strData中
}

BigData::BigData(const char* pData)
{
	//要處理的輸入:"12345678"   "234567qwe"    "+"    "    "     "0000123456"

	if (NULL == pData)
	{
		assert(false);
		return;
	}

	//處理符號位
	char* pStr = (char*)pData; 
	char cSymbol = pData[0];
	if ('+' == cSymbol || '-' == cSymbol)
		pStr++;
	else if (cSymbol >= '0' && cSymbol <= '9')
		cSymbol = '+';
	else
		return;

	//"0000123456"
	int iDataLen = strlen(pData);
	if (iDataLen > 1)
	{
		while ('0' == *pStr)
			pStr++;
	}

	_strData.resize(strlen(pData)+1); //為_strData分配空間
	_strData[0] = cSymbol; //第0位保存符號

	//"123456qwe"
	_value = 0;
	int iCount = 1;
	while (*pStr >= '0' && *pStr <= '9')
	{
		_value = _value*10 + (*pStr - '0');
		_strData[iCount++] = *pStr;
		pStr++;
	}

	_strData.resize(iCount);

	if (cSymbol == '-')
		_value = 0 - _value;
}

bool BigData::IsINT64Overflow() const
{
	std::string temp("+9223372036854775807");
	
	if (_strData[0] == '-')
		temp = "-9223372036854775808";

	if (_strData.size() < temp.size())
		return false;
	else if (_strData.size() == temp.size() && _strData <= temp)
		return false;

	return true;
}

void BigData::INT64ToString()
{
	//處理符號位
	char cSymbol = '+';
	if (_value < 0)
		cSymbol = '-';

	INT64 temp = _value;
	while (temp)
	{
		if (cSymbol == '+')
			_strData.append(1, temp%10 + '0');
		else
			_strData.append(1, -(temp%10) + '0');

		temp /= 10;
	}
	_strData.append(1, cSymbol);
	
	std::reverse(_strData.begin(), _strData.end());
}

bool BigData::IsLeftStrBig(const char* pLeft, int LSize, const char* pRight, int RSize)
{
	assert(pLeft != NULL && pRight != NULL);

	if ((LSize > RSize) || 
		(LSize == RSize && strcmp(pLeft, pRight) >= 0))
		return true;
	else
		return false;
}

char BigData::SubLoop(char* pLeft, int LSize, char* pRight, int RSize)
{
	assert(pLeft != NULL && pRight != NULL);

	char cRet = '0';

	while (true)
	{
		if (!IsLeftStrBig(pLeft, LSize, pRight, RSize))
			break;
		
		int iLIdx = LSize - 1;
		int iRIdx = RSize - 1;
		while (iLIdx >= 0 && iRIdx >= 0)
		{
			char ret = pLeft[iLIdx] - '0';
			ret -= pRight[iRIdx] - '0';
			
			if (ret < 0)
			{
				pLeft[iLIdx - 1] -= 1;
				ret += 10;
			}
			
			pLeft[iLIdx] = ret + '0';
			iLIdx--;
			iRIdx--;
		}

		while (*pLeft == '0' && LSize > 0)
		{
			pLeft++;
			LSize--;
		}

		cRet++;
	}

	return cRet;
}

std::ostream& operator<<(std::ostream& _cout, const BigData& bigdata)
{
	if (!bigdata.IsINT64Overflow()) //_value沒有溢出
	{
		_cout<<bigdata._value;
	}
	else //_value溢出
	{
		char* pData = (char*)bigdata._strData.c_str();
		if ('+' == pData[0])
			pData++;

		_cout<<pData;
	}

	return _cout;
}

BigData BigData::operator+(const BigData& bigdata)
{
	if (!IsINT64Overflow() && !bigdata.IsINT64Overflow()) //兩個數(shù)都沒有溢出
	{
		if (_strData[0] != bigdata._strData[0]) //兩個數(shù)異號
		{
			return BigData(_value + bigdata._value);
		}
		else //兩個數(shù)同號
		{
			if ((_value >= 0 && bigdata._value <= MAX_INT64 - _value) || 
				(_value < 0 && bigdata._value >= MIN_INT64 - _value)) //相加后的和沒有溢出
				return BigData(_value + bigdata._value);
		}
	}

	//兩個數(shù)至少有一個溢出
	//相加后的和溢出
	if (_strData[0] == bigdata._strData[0]) //同號相加,調(diào)用加法
		return BigData(Add(_strData, bigdata._strData).c_str());
	else //異號相加,調(diào)用減法
		return BigData(Sub(_strData, bigdata._strData).c_str());
}

BigData BigData::operator-(const BigData& bigdata)
{
	if (!IsINT64Overflow() && !bigdata.IsINT64Overflow()) //兩個數(shù)都沒有溢出
	{
		if (_strData[0] == bigdata._strData[0])//同號
		{
			return BigData(_value - bigdata._value);
		}
		else //異號
		{
			if ((_value >= 0 && MAX_INT64 + bigdata._value >= _value) || 
				(_value < 0 && MIN_INT64 + bigdata._value <= _value)) //結(jié)果沒有溢出
				return BigData(_value - bigdata._value);
		}
	}

	//至少有一個數(shù)溢出或結(jié)果溢出
	if (_strData[0] != bigdata._strData[0]) //異號相減,調(diào)用加法
		return BigData(Add(_strData, bigdata._strData).c_str());
	else //同號相減,調(diào)用減法
		return BigData(Sub(_strData, bigdata._strData).c_str());
}

BigData BigData::operator*(const BigData& bigdata)
{
	if (!IsINT64Overflow() && !bigdata.IsINT64Overflow()) //都沒有溢出
	{
		if (_value == 0 || bigdata._value == 0)
		{
			return BigData((INT64)0);
		}

		if (_strData[0] == bigdata._strData[0]) //同號,積為正
		{
			if ((_value > 0 && MAX_INT64/_value >= bigdata._value) || 
				(_value < 0 && MAX_INT64/_value <= bigdata._value)) //積沒有溢出
			{
				return BigData(_value * bigdata._value);
			}
		}
		else //異號,積為負
		{
			if ((_value > 0 && MIN_INT64/_value <= bigdata._value) || 
				(_value < 0 && MIN_INT64/_value >= bigdata._value)) //積沒有溢出
			{
				return BigData(_value * bigdata._value);
			}
		}
	}

	return BigData(Mul(_strData, bigdata._strData).c_str());
}

BigData BigData::operator/(const BigData& bigdata)
{
	//除數(shù)不能為0
	if ('0' == bigdata._strData[1])
		assert(false);

	//	都沒溢出


	if (!IsINT64Overflow() && !bigdata.IsINT64Overflow())
		return BigData(_value / bigdata._value);

	//	至少有一個溢出


	//除數(shù) == ±1
	if (bigdata._strData == "+1" && bigdata._strData == "-1") 
	{
		std::string strRet = _strData;

		if (_strData[0] != bigdata._strData[0])
			strRet[0] = '-';

		return BigData(strRet.c_str());
	}

	//左 < 右
	if ( (_strData.size() < bigdata._strData.size()) || 
		 (_strData.size() == bigdata._strData.size() && strcmp(_strData.c_str()+1, bigdata._strData.c_str()+1) < 0) ) 
		return BigData(INT64(0));

	//左 == 右
	if (strcmp(_strData.c_str()+1, bigdata._strData.c_str()+1) == 0) //左==右
	{
		std::string strRet = "+1";
		if (_strData[0] != bigdata._strData[0])
			strRet[0] = '-';
		else
			return BigData(strRet.c_str());
	}

	//左 > 右
	return BigData(Div(_strData, bigdata._strData).c_str());
}

std::string BigData::Add(std::string left, std::string right)
{
	//讓left保存位數(shù)大的數(shù)
	int iLeftSize = left.size();
	int iRightSize = right.size();
	if (iLeftSize < iRightSize)
	{
		std::swap(left, right);
		std::swap(iLeftSize, iRightSize);
	}

	//相加
	std::string strRet;
	strRet.resize(iLeftSize + 1);
	strRet[0] = left[0]; //符號位
	char Step = 0; //進位
	for (int iIdx = 1; iIdx < iLeftSize; ++iIdx)
	{
		char cRet = left[iLeftSize - iIdx] - '0' + Step;

		if (iIdx < iRightSize)
			cRet += right[iRightSize - iIdx] - '0';

		strRet[iLeftSize - iIdx + 1] = cRet % 10 + '0';
		Step = cRet / 10;
	}

	strRet[1] = Step + '0';
	
	return strRet;
}

std::string BigData::Sub(std::string left, std::string right)
{
	int iLeftSize = left.size();
	int iRightSize = right.size();
	char cSymbol = left[0]; //差的符號位

	if ((iLeftSize < iRightSize) || 
		(iLeftSize == iRightSize && left < right))
	{
		std::swap(left, right);
		std::swap(iLeftSize, iRightSize);

		if (cSymbol == '+')
			cSymbol = '-';
		else
			cSymbol = '+';
	}

	//相減
	std::string strRet; //保存差
	strRet.resize(left.size()); //先設(shè)置和左操作數(shù)一樣大的空間
	strRet[0] = cSymbol; //符號位

	for (int Idx = 1; Idx < iLeftSize; ++Idx)
	{
		char cRet = left[iLeftSize - Idx] - '0';
		
		if (Idx < iRightSize)
			cRet -= (right[iRightSize - Idx] - '0');

		if (cRet < 0) //有借位
		{
			left[iLeftSize - Idx - 1] -= 1;
			cRet += 10;
		}

		strRet[iLeftSize - Idx] = cRet + '0';
	}

	return strRet;
}

std::string BigData::Mul(std::string left, std::string right)
{
	//確定符號位
	char cSymbol = '+';
	if (left[0] != right[0])
		cSymbol = '-';

	//使左操作數(shù)位數(shù)小于右操作數(shù)位數(shù)
	int iLeftSize = left.size();
	int iRightSize = right.size();
	if (iLeftSize > iRightSize)
	{
		std::swap(left, right);
		std::swap(iLeftSize, iRightSize);
	}

	std::string strRet;
	//strRet.resize(iLeftSize+iRightSize-1);
	strRet.assign(iLeftSize+iRightSize-1, '0');
	strRet[0] = cSymbol;
	int iRetLen = strRet.size();
	int iOffset = 0; //偏移

	for (int iLeftIndex = 1; iLeftIndex < iLeftSize; ++iLeftIndex)
	{
		char cLeft = left[iLeftSize - iLeftIndex] - '0';
		
		if (cLeft == 0) //當左操作數(shù)中有0時,直接左移,不計算
		{
			++iOffset;
			continue;
		}

		char cStep = 0;
		for (int iRightIndex = 1; iRightIndex < iRightSize; ++iRightIndex)
		{
			char cRet = cLeft*(right[iRightSize - iRightIndex] - '0') + cStep;
			cRet += strRet[iRetLen - iRightIndex - iOffset] - '0';
			strRet[iRetLen - iRightIndex - iOffset] = (cRet%10) + '0';
			cStep = cRet/10;
		}
		strRet[iRetLen-iRightSize -iOffset] += cStep;
		++iOffset;
	}

	return strRet;
}

std::string BigData::Div(std::string left, std::string right)
{
	std::string strRet;
	
	//確定符號位
	strRet.append(1, '+');
	if (left[0] != right[0])
		strRet[0] = '-';

	char* pLeft = (char*)(left.c_str()+1);
	char* pRight = (char*)(right.c_str()+1);
	int iLSize = left.size()-1; //被除數(shù)長度
	int iDataLen = right.size()-1; //取iDataLen位被除數(shù)

	int iIdx = 0; //iIdx和pLeft同步走,用來判斷是否走到被除數(shù)結(jié)尾
	while (iIdx < iLSize)
	{
		if (*pLeft == '0')
		{
			strRet.append(1, '0');
			pLeft++;
			iIdx++;
			continue;
		}

		if (!IsLeftStrBig(pLeft, iDataLen, pRight, right.size()-1)) //取的iDataLen位被除數(shù) < 除數(shù)
		{
			strRet.append(1, '0');
			iDataLen++;
			if (iDataLen + iIdx > iLSize)
				break;
		}
		else
		{
			//循環(huán)相減
			strRet.append(1, SubLoop(pLeft, iDataLen, pRight, right.size()-1)); 
			while (*pLeft == '0')
			{
				pLeft++;
				iIdx++;
				iDataLen--;
			}

			iDataLen++;
		}
	}

	return strRet;
}

BigDataTest.cpp

#include <iostream>
using namespace std;
#include "BigData.h"

void AddTest()
{
	//BigData b1("12345678");
	//BigData b2("12345qwe");
	//BigData b3("+");
	//BigData b4("00001234");
	//BigData b5("   ");
	//BigData b6("99999999999999999999999999999999999999999999999999999999");
	//BigData b7 ("-123213");

	//cout<<b1<<endl;
	//cout<<b2<<endl;
	//cout<<b3<<endl;
	//cout<<b4<<endl;
	//cout<<b5<<endl;
	//cout<<b6<<endl;
	//cout<<b7<<endl;

	//BigData left1(1234);
	//BigData right1(4321);
	//cout<<left1+right1<<endl;

	//BigData left2(9223372036854775807);
	//BigData right2(3);
	//cout<<left2+right2<<endl;

	//BigData left3(-9223372036854775808);
	//BigData right3(-3);
	//cout<<left3+right3<<endl;

	//BigData left3("99999999999999999999999999999999999");
	//BigData right3("11111111111111111111111111111111111");
	//cout<<left3+right3<<endl;
}

void SubTest()
{
	//BigData left("1111111111111111111111111111111100");
	//BigData right("99");
	//cout<<left-right<<endl;

	//BigData left1("-2222222222222222222222222222222222222222");
	//BigData right1("22222");
	//cout<<left1+right1<<endl;
}

void MulTest()
{
	//BigData left("77777777777777777777777777777777777777777777777777777777777");
	//BigData right("66");
	//cout<<left*right<<endl;

	//BigData left1("99");
	//BigData right1("9999999999999999999999999999999999999999999");
	//cout<<left1*right1<<endl;


	//BigData left2("11111111111111111111111111111111111111111111111111111111111111111");
	//BigData right2("-99");
	//cout<<left2*right2<<endl;

	//BigData left3("-8");
	//BigData right3("66");
	//cout<<left3*right3<<endl;

	//BigData left4("10001");
	//BigData right4("666666666666666666666666666666666666");
	//cout<<left4*right4<<endl;
}

void DivTest()
{
	//BigData left("222222222222222222222222222222222222222222222222");
	//BigData right("33");
	//cout<<left/right<<endl;

	//BigData left1("-222222222222222222222222222222222222222222222222");
	//BigData right1("33");
	//cout<<left1/right1<<endl;

	//BigData left3("33333333333333333333333333333333333333333333333333333");
	//BigData right3("0");
	//cout<<left3/right3<<endl;

	//BigData left4("111");
	//BigData right4("222222222222222222222222222222222222222222222222");
	//cout<<left4/right4<<endl;

	//BigData left5("11111111111111111111111111111111111111111111111111");
	//BigData right5("-11111111111111111111111111111111111111111111111111");
	//cout<<left5/right5<<endl;
}

void PrintMenu()
{
	cout<<"------------------------------------------------------------------------"<<endl;
	cout<<"|                            大 數(shù) 計 算 器                            |"<<endl;
	cout<<"------------------------------------------------------------------------"<<endl;
	cout<<"請輸入:";
}

void Demo()
{
	while (true)
	{
		PrintMenu();
		string input;
		cin>>input;

		if (input == "quit")
		{
			break;
		}

		if (input.find('+') != -1)
		{
			string left = input.substr(0, input.find('+'));
			string right = input.substr(input.find('+')+1, input.length()-1);
			BigData bigdata1(left.c_str());
			BigData bigdata2(right.c_str());
			cout<<"結(jié)果:  "<<bigdata1+bigdata2<<endl;
			continue;
		}

		if (input.find('-') != -1)
		{
			string left = input.substr(0, input.find('-'));
			string right = input.substr(input.find('-')+1, input.length()-1);
			BigData bigdata1(left.c_str());
			BigData bigdata2(right.c_str());
			cout<<"結(jié)果:  "<<bigdata1-bigdata2<<endl;
			continue;
		}

		if (input.find('*') != -1)
		{
			string left = input.substr(0, input.find('*'));
			string right = input.substr(input.find('*')+1, input.length()-1);
			BigData bigdata1(left.c_str());
			BigData bigdata2(right.c_str());
			cout<<"結(jié)果:  "<<bigdata1*bigdata2<<endl;
			continue;
		}

		if (input.find('/') != -1)
		{
			string left = input.substr(0, input.find('/'));
			string right = input.substr(input.find('/')+1, input.length()-1);
			BigData bigdata1(left.c_str());
			BigData bigdata2(right.c_str());
			cout<<"結(jié)果:  "<<bigdata1/bigdata2<<endl;
			continue;
		}

	}
}

int main()
{
	//AddTest();
	//SubTest();
	//MulTest();
	//DivTest();
	Demo();

	return 0;
}


下面是一個簡單的測試:

C++實現(xiàn)大數(shù)運算

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI