大数运算

本人在在写这个小项目的时候,首先考虑到数的存储问题。计算机能够表示的最大值为0x7FFFFFFFFFFFFFFF,最小值为0x8000000000000000,那么要运算比这个大的数字该怎么办呢?是否可以使用字符串来保存比计算机能够表示的最大的数呢?怎么初始化大数呢?字符串的加减乘除该怎么实现呢?成员变量需要怎么定义呢?

1.是否可以使用字符串来保存比计算机能够表示的最大的数呢?

学过c++的同学肯定对string很熟悉,是c++用来维护字符串的一个类。可以用来维护字符串。

1).加法:用字符串模仿加法,以此取到左右操作数的最低位相加模拟加法。

2).减法:同样可以取到左右操作数的最低位进行模拟减法。

3).乘法:同样可以取道左右操作数的最低位进行模拟乘法。

4).除法:可以取到和右操作数相同的位数或者大一位进行模拟除法。

相同这些那么类的成员变量就不难得出了。

class BigData
{

private:
     long long _value;
     string _strData;
};

2.怎么初始化大数呢?

初始化字符串是为了更好的支持,加减乘除的运算。那么初始化分为几个部分?显而易见分为两个部分---1.long long类型以内的整数 2.字符串类型。当然这里考虑的是字符串的初始化。

eg:传入字符串"123456" "+123456" "-123456" "    " "00000123456" "qwert123456" "1234567qwert" 该怎么样初始化呢?

1).为了后面的计算,我们首先需要在字符串的前面设置一个符号位用了保存字符串的属性。那么首当其冲就是判断符号位了。

2).接下来就要处理有效位前面有0的情况。

分析上面的字符串现在变成什么样的情况--"123456"  "123456" "123456" "123456" "1234567qwert"

3).那么就很好确定思路处理"1234567qwert"的情况然后将字符串保存在string _strData中。

4).会发现_strData中字符串是反序的 --- "654321",所以需要逆序字符串。

    BigData::BigData(INT64 x)
       :_value(x)
    {
    	_INIT64ToString();
    }
    
    
    BigData::BigData(const char* cData)
    {
    	if (cData == NULL)
    	{
    		assert(false);
    		return;
    	}
    
    	char* ptr = (char*)cData;
    	char cSymbol = cData[0];   //“0000”  ""
    
    	if (cSymbol == ‘-‘ || cSymbol == ‘+‘)
    	{
    		ptr++;
    	}
    	else if (cSymbol >= ‘0‘ && cSymbol <= ‘9‘)
    	{
    		cSymbol = ‘+‘;
    	}
    	else
    	{
    		return;
    	}
    
    	while (*ptr == ‘0‘)
    	{
    		++ptr;
    	}
    
    	_strData.resize(strlen(cData) + 1);
    	_strData[0] = cSymbol;
    
    	_value = 0;
    	int iCount = 1;
    
    	while (*ptr >= ‘0‘ && *ptr <= ‘9‘)
    	{
    		_value = _value * 10 + (*ptr - ‘0‘);
    		_strData[iCount++] = *ptr;
    		++ptr;
    	}
    
    	_strData.resize(iCount);
    
    	if (cSymbol == ‘-‘)
    	{
    		_value = 0 - _value;
    	}
    }
    
    void BigData::_INIT64ToString()
    {
    	char cSymbol = ‘+‘;
    	if (_value < 0)
    	{
    		cSymbol = ‘-‘;
    		//----------------------------------------------------
    	}
    
    	INT64 tmp = _value;
    	_strData.append(1, cSymbol);
    
    	while (tmp)
    	{
    		_strData.append(1, tmp % 10 + ‘0‘);
    		tmp /= 10;
    	}
    
    	char* pLeft = (char*)_strData.c_str() + 1;
    	char* pRight = pLeft + _strData.size() - 2;
    
    	while (pLeft < pRight)
    	{
    		char cmp = *pLeft;
    		*pLeft = *pRight;
    		*pRight = cmp;
    		pLeft++;
    		pRight--;
    	}
    }

3.字符串的加减乘除该怎么实现呢?

bool BigData::isOverFlowINT64()const    
    {
    	string tmp("9223372036854775807");
    
    	if (_strData[0] == ‘-‘)
    	{
    		tmp = "-9223372036854775808";
    	}
    
    	if (_strData.size() < tmp.size())
    	{
    		return true;
    	}
    	else if (_strData.size() == tmp.size() && _strData<tmp)
    	{
    		return true;
    	}
    
    	return false;
    }
    
    
    ostream& operator<<(ostream& out, const BigData& bigdata)
    {
    
    	if (bigdata.isOverFlowINT64())
    	{
    		out << bigdata._value;
    		return out;
    	}
    	else
    	{
    		char* pstr = (char*)bigdata._strData.c_str();
    
    		if (pstr[0] == ‘+‘)
    		{
    			pstr++;
    		}
    		out << pstr;
    	}
    	return out;
    }
    
    
    BigData BigData::operator+(const BigData& bigdata)
    {
    	if (isOverFlowINT64() && bigdata.isOverFlowINT64())
    	{
    		if (_strData[0] != bigdata._strData[0])
    		{
    			return (_value + bigdata._value);
    		}
    		else
    		{
    			INT64 tmp = MIN_INT64;
    			if (_value > 0 && MAX_INT64 - _value >= bigdata._value
    				|| _value < 0 && tmp - _value <= bigdata._value)    //--------------
    			{
    				return (_value + bigdata._value);
    			}
    		}
    	}
    
    	if (_strData[0] == bigdata._strData[0])    //同号溢出的情况,调用jianfa------------------------------
    	{
    		return BigData(Add(_strData, bigdata._strData).c_str());   
    	}
    
    	return BigData(Sub(_strData, bigdata._strData).c_str()); //异号溢出的情况,调用jiafa
    }
    
    BigData BigData::operator-(const BigData& bigdata)
    {
    	if (isOverFlowINT64() && bigdata.isOverFlowINT64())
    	{
    		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());
    	}
    
    	return BigData(Sub(_strData, bigdata._strData).c_str());
    }
    
    BigData BigData::operator*(const BigData& bigdata)
    {
    	if (_value == 0 || bigdata._value == 0)
    	{
    		return BigData(INT64(0));
    	}
    	if (isOverFlowINT64() && bigdata.isOverFlowINT64())
    	{
    		if (_strData[0] == bigdata._strData[0])
    		{
    			if ((_value > 0 && MAX_INT64 / _value >= bigdata._value) ||
    				(_value < 0 && MIN_INT64 / _value <= bigdata._value))    //  -10 -2 = 5 
    			{
    				return BigData(_value * bigdata._value);
    			}
    		}
    		else
    		{
    			//-10 2 -5
    			if ((_value > 0 && MIN_INT64 / _value <= bigdata._value) ||      //-10  2  = -5 <= -3 
    				(_value < 0 && MIN_INT64 / _value >= bigdata._value))        //-10 -2  =  5  >= 3
    			{
    				return BigData(_value * bigdata._value);
    			}
    		}
    	}
    
    	return BigData(Mul(_strData, bigdata._strData).c_str());
    }
    
    
    BigData BigData::operator/(const BigData& bigdata)
    {
    	if (bigdata._strData[1] == ‘0‘)      //处理除数为0的情况
    	{
    		assert(false);
    	}
    
    	if (isOverFlowINT64() && bigdata.isOverFlowINT64())   //处理不溢出的情况
    	{
    		return BigData(_value / bigdata._value);
    	}
    
    	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 (bigdata._strData == "-1" || bigdata._strData == "+1")    //处理除数为+1 -1的情况
    	{
    		string ret = _strData;
    
    		if (_strData[0] != bigdata._strData[0])
    		{
    			ret[0] = ‘-‘;
    		}
    		return BigData(ret.c_str());
    	}
    
    	if (_strData.size() == bigdata._strData.size()              //处理除数与被除数一样的情况(除过符号位)
    		&& strcmp(_strData.c_str() + 1, bigdata._strData.c_str() + 1) == 0)
    	{
    		string ret = "+1";
    
    		if (_strData[0] != bigdata._strData[0])
    		{
    			ret[0] = ‘-‘;
    		}
    
    		return BigData(ret.c_str());
    	}
    
    	return BigData(Div(_strData, bigdata._strData).c_str());
    }
    
    
    string BigData::Add(string left, string right)
    {
    
    	int leftsize = left.size();
    	int rightsize = right.size();
    
    	if (leftsize < rightsize)
    	{
    		swap(left, right);
    		swap(leftsize, rightsize);
    	}
    
    	string iRet;
    	iRet.resize(leftsize + 1);
    	iRet[0] = left[0];
        int step = 0;
    
    	for (int i = 1; i < leftsize; i++)
    	{
    		char cRet = left[leftsize - i] - ‘0‘ + step;
    
    		if (i < rightsize)
    		{
    			cRet += right[rightsize - i] - ‘0‘;
    		}
    
    		iRet[leftsize - i + 1] = cRet % 10 + ‘0‘;
    
    		step = cRet/10;
    	}
    	iRet[1] = step + ‘0‘;
    
    	return iRet;
    
    }
    
    
    string BigData::Sub(string left, string right)
    {
    	int leftsize = left.size();
    	int rightsize = right.size();
    
    	char cSymbol = ‘+‘;
    	//10 - 11 = -1
    	//-3 - -7 = 4
    	if (leftsize < rightsize || leftsize == rightsize && left<right)
    	{
    		swap(left, right);
    		swap(leftsize, rightsize);
    		if (cSymbol == ‘+‘)
    		{
    			cSymbol = ‘-‘;
    		}
    		else
    		{
    			cSymbol = ‘+‘;
    		}
    	}
    
    	string strRet;
    	strRet.resize(left.size());
    	strRet[0] = cSymbol;
    
    
    	for (int Idx = 1; Idx < leftsize; ++Idx)
    	{
    		char cRet = left[leftsize - Idx] - ‘0‘;
    		if (Idx < rightsize)
    		{
    			cRet -= right[rightsize - Idx] - ‘0‘;
    		}
    
    		if (cRet < 0)
    		{
    			left[leftsize - Idx - 1] -= 1;
    			cRet += 10;
    		}
    
    		strRet[leftsize - Idx] = cRet + ‘0‘;
    	}
    
    	return strRet;
    }
    
    
    string BigData::Mul(string left, string right)
    {
    	char cSymbol = ‘+‘;
    	if (left[0] != right[0])
    	{
    		cSymbol = ‘-‘;
    	}
    	int leftsize = left.size();
    	int rightsize = right.size();
    
    	if (leftsize < rightsize)
    	{
    		swap(left, right);
    		swap(leftsize, rightsize);
    	}
    
    	string sRet;
    	sRet.assign(leftsize + rightsize - 1,‘0‘);
    	sRet[0] = cSymbol;
    	int iDataLen = sRet.size();
    	int ioffset = 0;
    
    	for (int iLIdx = 1; iLIdx < leftsize; iLIdx++)
    	{
    		char cLeft = left[leftsize - iLIdx] - ‘0‘;
    		char cStep = 0;
    		if (cLeft == ‘0‘)
    		{
    			ioffset++;
    			continue;
    		}
    
    		for (int iRIdx = 1; iRIdx < rightsize; iRIdx++)
    		{
    			char cRet = cLeft*(right[rightsize - iRIdx] - ‘0‘) + cStep;
    			cRet += sRet[iDataLen - iRIdx - ioffset] - ‘0‘;
    			sRet[iDataLen - iRIdx - ioffset] = (cRet % 10 + ‘0‘);
    			cStep = cRet/10;
    		}
    		sRet[iDataLen - rightsize - ioffset] += cStep;
    		ioffset++;
    	}
    	return sRet;
    }
    
    string BigData::Div(string left, string right)
    {
    	string sRet;
    	sRet.append(1, ‘+‘);
    	if (left[0] != right[0])
    	{
    		sRet[0] = ‘-‘;
    	}
    
    	char* pLeft = (char*)(left.c_str() + 1);
    	char* pRight = (char*)(right.c_str() + 1);
    	int DataLen = right.size() - 1;
    	int Lsize = left.size() - 1;
    
    	for (int iIdx = 0; iIdx < Lsize;)
    	{
    		if (*pLeft == ‘0‘)
    		{
    			sRet.append(1, ‘0‘);
    			pLeft++;
    			iIdx++;
    			continue;
    		}
    
    		if (!IsLeftStrBig(pLeft, DataLen, pRight, right.size() - 1))
    		{
    			sRet.append(1, ‘0‘);
    			DataLen++;
    			if (DataLen + iIdx > Lsize)
    			{
    				break;
    			}
    		}
    		else
    		{
    			sRet.append(1, subloop(pLeft, DataLen, pRight, right.size() - 1));
    
    			while (*pLeft == ‘0‘ && DataLen > 0)
    			{
    				pLeft++;
    				iIdx++;
    				DataLen--;
    			}
    
    			DataLen++;
    			if (DataLen + iIdx > Lsize)
    			{
    				break;
    			}
    		}
    	}
    	return sRet;
    }
    
    
    bool BigData::IsLeftStrBig(const char* pLeft, int Lsize, const char* pRight, int Rsize)
    {
    	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 && pRight);
    
    	char cRet = ‘0‘;
    
    	while (1)
    	{
    		if (!IsLeftStrBig(pLeft, Lsize, pRight, Rsize))
    		{
    			break;
    		}
    
    		int LDataLen = Lsize - 1;
    		int RDataLen = Rsize - 1;
    
    		while (LDataLen >= 0 && RDataLen >= 0)
    		{
    			char ret = pLeft[LDataLen] - ‘0‘;
    			ret -= pRight[RDataLen] - ‘0‘;
    
    			if (ret < 0)
    			{
    				pLeft[LDataLen - 1] -= 1;
    				ret += 10;
    			}
    
    			pLeft[LDataLen] = ret + ‘0‘;
    			LDataLen--;
    			RDataLen--;
    		}
    
    		while (*pLeft == ‘0‘ && Lsize > 0 )
    		{
    			pLeft++;
    			Lsize--;
    		}
    		cRet++;
    	}
    	return cRet;
    }

4.BigData类

#pragma once
#include<iostream>
#include<string>
#include<assert.h>
using namespace std;

typedef long long INT64;
#define MIN_INT64 0x8000000000000000
#define MAX_INT64 0x7FFFFFFFFFFFFFFF

class BigData
{
public:
	BigData(INT64 x);
	BigData(const char* cData);

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

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

	friend ostream& operator<<(ostream& out, const BigData& bigdata);
	bool isOverFlowINT64()const;
	bool IsLeftStrBig(const char* pLeft, int Lsize, const char* pRight, int Rsize);
	char subloop(char* pLeft, int Lsize, char* pRight, int Rsize);
	void _INIT64ToString();

private:
	INT64 _value;
	string _strData;
};

总结:分为两种思路,处理long long 类型的方法 && 处理溢出的情况。

以上就是本人在学习过程中的一些经验总结。当然,本人能力有限,难免会有纰漏,希望大家可以指正。

时间: 2024-10-28 22:13:47

大数运算的相关文章

关于大数运算

在接触计算机这么久以来,我一直被大数运算困扰,确切的说是在一些特定方面非常有受挫感,在计算机中的数据类型对数字支持的数位有限制,例如: 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

C++实现大数运算

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

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++编程实现 大数的加减乘除四则运算 <思路与方法同样都在程序内部> 这次通过标