C++实现大数运算

项目背景:

大数运算,顾名思义,就是很大的数值的数进行一系列的运算。

我们知道,在数学中,数值的大小是没有上限的,但是在计算机中,由于字长的限制,计算机所能表示的范围是有限的,当我们对比较小的数进行运算时,如:1234+5678,这样的数值并没有超出计算机的表示范围,所以可以运算。但是当我们在实际的应用中进行大量的数据处理时,会发现参与运算的数往往超过计算机的基本数据类型的表示范围,比如说,在天文学上,如果一个星球距离我们为100万光年,那么我们将其化简为公里,或者是米的时候,我们会发现这是一个很大的数。这样计算机将无法对其进行直接计算。

可能我们认为实际应用中的大数也不过就是几百位而已,实际上,在某些领域里,甚至可能出现几百万位的数据进行运算,这是我们很难想象的。如果没有计算机,那么计算效率可想而知。

由于编程语言提供的基本数值数据类型表示的数值范围有限,不能满足较大规模的高精度数值计算,因此需要利用其他方法实现高精度数值的计算,于是产生了大数运算。本项目实现了大数运算主要的加、减、乘除四种方法。

BigData.h

#ifndef BIG_DATA_H
#define BIG_DATA_H

#include <string>

#define MAX_INT64 (INT64)0x7FFFFFFFFFFFFFFF
#define MIN_INT64 (INT64)0x8000000000000000 //如果不强转,系统会定义为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()) //两个数都没有溢出
	{
		if (_strData[0] != bigdata._strData[0]) //两个数异号
		{
			return BigData(_value + bigdata._value);
		}
		else //两个数同号
		{
			if ((_value >= 0 && bigdata._value <= MAX_INT64 - _value) || 
				(_value < 0 && bigdata._value >= MIN_INT64 - _value)) //相加后的和没有溢出
				return BigData(_value + bigdata._value);
		}
	}

	//两个数至少有一个溢出
	//相加后的和溢出
	if (_strData[0] == bigdata._strData[0]) //同号相加,调用加法
		return BigData(Add(_strData, bigdata._strData).c_str());
	else //异号相加,调用减法
		return BigData(Sub(_strData, bigdata._strData).c_str());
}

BigData BigData::operator-(const BigData& bigdata)
{
	if (!IsINT64Overflow() && !bigdata.IsINT64Overflow()) //两个数都没有溢出
	{
		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)) //结果没有溢出
				return BigData(_value - bigdata._value);
		}
	}

	//至少有一个数溢出或结果溢出
	if (_strData[0] != bigdata._strData[0]) //异号相减,调用加法
		return BigData(Add(_strData, bigdata._strData).c_str());
	else //同号相减,调用减法
		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)
{
	//除数不能为0
	if (‘0‘ == bigdata._strData[1])
		assert(false);

	//	都没溢出

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

	//	至少有一个溢出

	//除数 == ±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保存位数大的数
	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()); //先设置和左操作数一样大的空间
	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 = ‘-‘;

	//使左操作数位数小于右操作数位数
	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) //当左操作数中有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; //被除数长度
	int iDataLen = right.size()-1; //取iDataLen位被除数

	int iIdx = 0; //iIdx和pLeft同步走,用来判断是否走到被除数结尾
	while (iIdx < iLSize)
	{
		if (*pLeft == ‘0‘)
		{
			strRet.append(1, ‘0‘);
			pLeft++;
			iIdx++;
			continue;
		}

		if (!IsLeftStrBig(pLeft, iDataLen, pRight, right.size()-1)) //取的iDataLen位被除数 < 除数
		{
			strRet.append(1, ‘0‘);
			iDataLen++;
			if (iDataLen + iIdx > iLSize)
				break;
		}
		else
		{
			//循环相减
			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<<"|                            大 数 计 算 器                            |"<<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<<"结果:  "<<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<<"结果:  "<<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<<"结果:  "<<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<<"结果:  "<<bigdata1/bigdata2<<endl;
			continue;
		}

	}
}

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

	return 0;
}

下面是一个简单的测试:

时间: 2024-10-12 11:51:25

C++实现大数运算的相关文章

关于大数运算

在接触计算机这么久以来,我一直被大数运算困扰,确切的说是在一些特定方面非常有受挫感,在计算机中的数据类型对数字支持的数位有限制,例如: long   long  int  a = 0; 这里的a 最多可以表示一个9位的长整型数字,要想存储超过9位的数字,最可行的方法是使用数组来存储每一位的值.所以在遇到大数运算的时候可以借用数组来完成相应的运算操作.

大数运算(python2)

偶然又遇到了一道大数题,据说python大数运算好屌,试了一发,果然方便- 1 a = int( raw_input() ); //注意这里是按行读入的,即每行只读一个数 2 b = int( raw_input() ); 3 print a+b; 4 print a*b; 5 print a/b; 6 print a%b;

大数运算之字符串模拟

相信大家被特别大的两个数据做运算折磨过.当两个操作数或者运算结果超过类型的表示范围后会有意想不到的错误,这时候我们的电脑还不如我们高中用过的科学计算器,这是作为一个程序员所不能忍受的.所以我们得找到其他的方式来计算.这就是我们今天要讨论的字符串模拟大数运算. 我们的运算一般使用int类型来算的,那么首先我们先复习一下各种int类型的数据表示范围: unsigned int 0-4294967295    int   -2147483648-2147483647  unsigned long 0-

HDU 4927 大数运算

模板很重要 #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define MAXN 9999 #define MAXSIZE 10 #define DLEN 4 class BigInt { private: int a[500]; //可以控制大数的位数 i

Big Number------HDOJ杭电1212(大数运算)

Problem Description As we know, Big Number is always troublesome. But it's really important in our ACM. And today, your task is to write a program to calculate A mod B. To make the problem easier, I promise that B will be smaller than 100000. Is it t

lua实现大数运算

lua实现的大数运算,代码超短,目前只实现的加减乘运算 local mod = 10000 function add(a, b) t, c = 0, {} for i = 1, math.max(#a,#b) do t = t + (a[i] or 0) + (b[i] or 0) c[i], t = t%mod, math.floor(t/mod) end while t ~= 0 do c[#c + 1], t = t%mod, math.floor(t/mod) end return c

大数运算——加法

作为一个对编程没有很深研究的初学者,对于这些虽然没有任何算法的题仍然觉得很难很难,但是或许都是需要一个过渡时期吧,这是这几天的结果,很多有自己的考虑,自己的想法在里面,但是也百度查了很多,也看了很多别人写的关于这方面的. 先看一下关于大数方面的知识: bool型为布尔型,占1个字节,取值0或1. BOOL型为int型,一般认为占4个字节,取值TRUE/FALSE/ERROR. sbyte型为有符号8位整数,占1个字节,取值范围在128~127之间. bytet型为无符号16位整数,占2个字节,取

java 大数运算[转]

用JAVA 实现算术表达式(1234324234324 + 8938459043545)/5 + 343434343432.59845 因为JAVA语言中的long 定义的变量值的最大数受到限制,例如123456789987654321这样的整数就不能存放在long类型的变量中,如果这样两个大数相加或相乘,产生的结果会更大.比如,JAVA语言中如果使用long l = 1000000000这样定义没错,但如果加上2000000000变成 1000000000+2000000000测试结果就为-1

大数运算实现加减乘除四则运算

首先,让我们先来熟悉一下两种防止头文件被重复引用的处理#pragma once和#ifndef的区别 http://10739786.blog.51cto.com/10729786/1730827 接下来,开始我们的主题 <大数运算>    在平时生活中细心的你可能会发现,好多时候我们使用计算器时,总有一个显示的最大值,当计算超过这个值时就不能再计算了,那如果我们想要计算更大的数值要怎么办? 本文通过C++编程实现 大数的加减乘除四则运算 <思路与方法同样都在程序内部> 这次通过标