1. 程式人生 > >c++ 大整數類CCBigInteger 加減法功能的實現

c++ 大整數類CCBigInteger 加減法功能的實現

同樣不說廢話了:

/*
 *  ccBigInteger.h
 *  c++_common_codes 
 *
 *  Created by xichen on 12-2-21.
 *  Copyright 2012 cc_team. All rights reserved.
 *
 */

#ifndef CC_BIG_INTEGER_H
#define	CC_BIT_INTEGER_H

#include <cstdlib>

// a kind of decimal big integer
class CCBigInteger
{
public:
	CCBigInteger(unsigned value = 0, bool sign = true);
	CCBigInteger(const char *value = "",  bool sign = true);
	~CCBigInteger();
	
public:
	CCBigInteger(const CCBigInteger &bigInteger);
	CCBigInteger &operator=(const CCBigInteger &bigInteger);
	
public:
	inline int	len() const { return _len; }
	inline char charValueAt(int index) const { return  _value[index]; }
	inline int	intValueAt(int index) const { return _value[index] - '0'; }
	
public:
	inline void	setLen(int newLen) { _len = newLen; } 
	inline void setCharAt(int index, char newChar) { _value[index] = newChar; }
	inline void setIntAt(int index, int newInt) { _value[index] = newInt + '0'; }
	
public:
	bool		canGetIntValue() const;	// if the unsigned value is overflowed, then returns false
	unsigned	uintValue() const;
	char	    *str() const;		// the char * format value, 239094843343 returns "239094843343"; caller should free the return value
	
public:
	CCBigInteger operator+(const CCBigInteger &bigInteger);
	CCBigInteger operator-(const CCBigInteger &bigInteger);	
	
public:
	CCBigInteger  operator-();		// neg

public:
	friend bool	operator<=(const CCBigInteger &leftBigInteger, 
						  const CCBigInteger &rightBigInteger);
	bool		absLessOrEqual(const CCBigInteger &bigInteger);
	
private:
	CCBigInteger addWithoutSign(const CCBigInteger &leftBigInteger,
								const CCBigInteger &rightBigInteger);
	CCBigInteger subWithoutSign(const CCBigInteger &leftBigInteger,
								const CCBigInteger &rightBigInteger);
	
private:
	// when subing, the function is called to update the high position value of the minuend
	int			updateHighPosValue(CCBigInteger &minuend,
												 const CCBigInteger &subtrahend, 
												 int pos);
	
private:
	enum { MACRO_MAX_LEN = 1024 };
	
private:
	char	_value[MACRO_MAX_LEN];	// "321" means the integer 123, not 321
	int		_len;				// the length of the value, should be less to MACRO_MAX_LEN
	bool	_positive;			// is positive or not
};

void ccTestCCBigInteger();

#endif

/*
 *  ccBigInteger.cpp
 * c++_common_codes  
 *
 *  Created by xichen on 12-2-21.
 *  Copyright 2012 cc_team. All rights reserved.
 *
 */

#include "ccBigInteger.h"
#include <iostream>
#include <cmath>
#include "ccIOBase.h"

using namespace std;

CCBigInteger::CCBigInteger(unsigned value, bool sign)
{
	_len = 0;
	int i = 0;
	while(value != 0)
	{
		_value[i++] = (value % 10) + '0';
		value /= 10;
	}
	_len = i;
	_positive = sign;
}

CCBigInteger::CCBigInteger(const char *value, bool sign)	// "123" means the int 123
{
	_len = 0;
	if(value != NULL)
	{
		for(int i = 0; i < strlen(value); ++i)
			_value[i] = value[strlen(value) - i - 1];
		_len = strlen(value);
	}
	_positive = sign;
}

CCBigInteger::~CCBigInteger()
{
	
}


CCBigInteger::CCBigInteger(const CCBigInteger &bigInteger)
{
	if(&bigInteger == this)
		return;
	
	strcpy(_value, bigInteger._value);
	_len = bigInteger._len;
	_positive = bigInteger._positive;
}

CCBigInteger &CCBigInteger::operator=(const CCBigInteger &bigInteger)
{
	if(&bigInteger == this)
		return *this;
	
	strcpy(_value, bigInteger._value);
	_len = bigInteger._len;
	_positive = bigInteger._positive;
	
	return *this;
}

bool		CCBigInteger::canGetIntValue() const
{
	bool ret = true;
	if(_len > 11)	// UINT_MAX 's length is 10
		return false;
	
	if(_len == 10)
	{
		for(int i = _len - 1; i >= 0; --i)
		{
			if(UINT_MAX / (int)pow((double)10, i) < _value[i] - '0')
			{
				ret = false;
				break;
			}
		}
	}
	return ret;
}


unsigned	CCBigInteger::uintValue() const
{
	unsigned ret = 0;
	int tempLen = _len - 1;
	while(tempLen >= 0)
	{
		ret = 10 * ret + _value[tempLen];
		--tempLen;
	}
	return ret * (_positive ? 1 : -1);
}

char	   *CCBigInteger::str() const
{
	char *temp = (char *)malloc(_len + 2);		// one is for _positive
	memset(temp, 0, _len + 2);
	int i = 0;
	if(!_positive)
	{
		temp[0] = '-';
		++i;
		for(; i < _len + 1; ++i)
		{
			temp[i] = _value[_len - i];
		}
	}
	else
	{
		for(; i < _len; ++i)
		{
			temp[i] = _value[_len - i - 1];
		}
	}
	
	
	return temp;
}

CCBigInteger CCBigInteger::operator+(const CCBigInteger &bigInteger)
{
	if(_positive && bigInteger._positive)	// + +	--> +
		return addWithoutSign(*this, bigInteger);
	if(_positive && !bigInteger._positive)	// + -	--> -
		return subWithoutSign(*this, bigInteger);
	if(!_positive && bigInteger._positive)	// - +	--> -
		return subWithoutSign(bigInteger, *this);
	if(!_positive && !bigInteger._positive)	// - -	--> +
		return -(addWithoutSign(*this, bigInteger));
}

CCBigInteger CCBigInteger::operator-(const CCBigInteger &bigInteger)
{
	if(_positive && bigInteger._positive)
		return subWithoutSign(*this, bigInteger);
	if(_positive && !bigInteger._positive)
		return addWithoutSign(*this, -const_cast<CCBigInteger &>(bigInteger));
	if(!_positive && bigInteger._positive)
		return -addWithoutSign(*this, bigInteger);
	if(!_positive && !bigInteger._positive)
		return subWithoutSign(bigInteger, *this);
}

bool	operator<=(const CCBigInteger &leftBigInteger, 
				  const CCBigInteger &rightBigInteger)
{
	if(!leftBigInteger._positive && rightBigInteger._positive)
		return true;
	if(leftBigInteger._positive && !rightBigInteger._positive)
		return false;
	if(leftBigInteger._positive && rightBigInteger._positive)
		return const_cast<CCBigInteger &>(leftBigInteger).absLessOrEqual(rightBigInteger);
	if(!leftBigInteger._positive && !rightBigInteger._positive)
		return const_cast<CCBigInteger &>(rightBigInteger).absLessOrEqual(leftBigInteger);
}

bool		CCBigInteger::absLessOrEqual(const CCBigInteger &bigInteger)
{
	if(_len > bigInteger._len)
		return false;
	if(_len < bigInteger._len)
		return true;
	for(int i = _len; i >= 0; --i)
	{
		if(_value[i] > bigInteger._value[i])
			return false;
		if(_value[i] < bigInteger._value[i])
			return true;
	}
	return true;
}


CCBigInteger  CCBigInteger::operator-()
{
	CCBigInteger ret(true);
	strncpy(ret._value, _value, _len);
	ret._len = _len;
	ret._positive = !_positive;
	return ret;
}

CCBigInteger CCBigInteger::addWithoutSign(const CCBigInteger &leftBigInteger, 
										  const CCBigInteger &rightBigInteger)
{
	CCBigInteger ret((unsigned)0, true);
	int minLen = min(leftBigInteger._len, rightBigInteger.len());
	int promoteValue = 0;
	for(int i = 0; i < minLen; ++i)
	{
		int temp = leftBigInteger._value[i] - '0' + rightBigInteger.intValueAt(i) + promoteValue;
		int temp1 = temp / 10;
		promoteValue = temp1;
		ret.setIntAt(i, temp - temp1 * 10);
	}
	if(leftBigInteger._len > minLen)
	{
		for(int i = minLen; i < _len; ++i)
		{
			int temp = leftBigInteger._value[i] - '0' + promoteValue;
			int temp1 = temp / 10;
			promoteValue = temp1;
			ret.setIntAt(i, temp - temp1 * 10);
		}
	}
	if(rightBigInteger.len() > minLen)
	{
		for(int i = minLen; i < rightBigInteger.len(); ++i)
		{
			int temp = rightBigInteger.intValueAt(i) + promoteValue;
			int temp1 = temp / 10;
			promoteValue = temp1;
			ret.setIntAt(i, temp - temp1 * 10);
		}
	}
	
	int maxLen = max(_len, rightBigInteger.len());
	ret.setLen(maxLen);
	if(promoteValue > 0)
	{
		ret.setLen(maxLen + 1);
		ret.setCharAt(maxLen, promoteValue + '0');
	}
	return ret;
}

CCBigInteger CCBigInteger::subWithoutSign(const CCBigInteger &leftBigInteger, 
										  const CCBigInteger &rightBigInteger)
{
	CCBigInteger tempMinuend(true);
	CCBigInteger ret(true);
	bool sign = true;
	if(const_cast<CCBigInteger &>(leftBigInteger).absLessOrEqual(rightBigInteger))
	{
		tempMinuend = rightBigInteger;
		sign = false;
		
		for(int i = 0; i < leftBigInteger._len; ++i)
		{
			int temp = tempMinuend.updateHighPosValue(tempMinuend, leftBigInteger, i);
			ret.setIntAt(i, temp);
		}
		for(int i = leftBigInteger._len; i < tempMinuend._len; ++i)
		{
			ret.setIntAt(i, tempMinuend._value[i] - '0');
		}
		if(ret._value[tempMinuend._len - 1] == '0')
			ret.setLen(tempMinuend._len - 1);
		else 
			ret.setLen(tempMinuend._len);
	}
	else
	{
		tempMinuend = leftBigInteger;
		for(int i = 0; i < rightBigInteger._len; ++i)
		{
			int temp = tempMinuend.updateHighPosValue(tempMinuend, rightBigInteger, i);
			ret.setIntAt(i, temp);
		}
		for(int i = rightBigInteger._len; i < tempMinuend._len; ++i)
		{
			ret.setIntAt(i, tempMinuend._value[i] - '0');
		}
		if(ret._value[tempMinuend._len - 1] == '0')
			ret.setLen(tempMinuend._len - 1);
		else 
			ret.setLen(tempMinuend._len);
	}
	return (sign ? ret : -ret);
}

int			CCBigInteger::updateHighPosValue(CCBigInteger &minuend,
											 const CCBigInteger &subtrahend, 
											 int pos)
{
	char minuendCh = minuend._value[pos];
	char subtrahendCh = subtrahend._value[pos];
	if(minuendCh >= subtrahendCh)
		return minuendCh - subtrahendCh;
	
	for(int i = pos + 1; i < minuend._len; ++i)
	{
		if(minuend._value[i] - '1' >= 0)
		{
			minuend._value[i]--;
			break;
		}
		else
		{
			minuend._value[i] = '9';
		}
	}
	return (10 + minuendCh - subtrahendCh);
}



測試程式碼:
void ccTestCCBigInteger()
{
#if 1		// ok
	CCBigInteger big1("1234567890");
	CCBigInteger big2("23456789010");
	CCBigInteger ret = big1 + big2;
	char *str;
	
	str = ret.str();
	COUT_2_VAR_ENDL("big1 + big2", str)
	free(str);
	
	ret = big1 - big2;
	str = ret.str();
	COUT_2_VAR_ENDL("big1 - big2", str)
	free(str);
	
	ret = big2 + big1;
	str = ret.str();
	COUT_2_VAR_ENDL("big2 + big1", str)
	free(str);
	
	ret = big2 - big1;
	str = ret.str();
	COUT_2_VAR_ENDL("big2 - big1", str)
	free(str);
	
	
	big1 = CCBigInteger("200010");
	big2 = CCBigInteger("12345");
	ret = big1 + big2;
	str = ret.str();
	COUT_2_VAR_ENDL("big1 + big2", str)
	free(str);
	
	ret = big1 - big2;
	str = ret.str();
	COUT_2_VAR_ENDL("big1 - big2", str)
	free(str);
	
	ret = big2 + big1;
	str = ret.str();
	COUT_2_VAR_ENDL("big2 + big1", str)
	free(str);
	
	ret = big2 - big1;
	str = ret.str();
	COUT_2_VAR_ENDL("big2 - big1", str)
	free(str);
	
	
	
	big1 = CCBigInteger("21234567890");
	big2 = CCBigInteger("23456789010", false);	// big2 is:  -23456789010
	// std::cout << big1.str() << std::endl;
	// std::cout << big2.str() << std::endl;
	
	ret = big1 + big2;
	str = ret.str();
	COUT_2_VAR_ENDL("big1 + big2", str)
	free(str);
	
	ret = big1 - big2;
	str = ret.str();
	COUT_2_VAR_ENDL("big1 - big2", str)
	free(str);
	
	ret = big2 + big1;
	str = ret.str();
	COUT_2_VAR_ENDL("big2 + big1", str)
	free(str);
	
	ret = big2 - big1;
	str = ret.str();
	COUT_2_VAR_ENDL("big2 - big1", str)
	free(str);
	
	
	big1 = CCBigInteger("920010");
	big2 = CCBigInteger("99345");
	ret = big1 + big2;
	str = ret.str();
	COUT_2_VAR_ENDL("big1 + big2", str)
	free(str);
	
	ret = big1 - big2;
	str = ret.str();
	COUT_2_VAR_ENDL("big1 - big2", str)
	free(str);
	
	ret = big2 + big1;
	str = ret.str();
	COUT_2_VAR_ENDL("big2 + big1", str)
	free(str);
	
	ret = big2 - big1;
	str = ret.str();
	COUT_2_VAR_ENDL("big2 - big1", str)
	free(str);
	
	
#endif
}

輸出結果:
big1 + big2 24691356900
big1 - big2 -22222221120
big2 + big1 24691356900
big2 - big1 22222221120
big1 + big2 212355
big1 - big2 187665
big2 + big1 212355
big2 - big1 -187665
big1 + big2 -2222221120
big1 - big2 44691356900
big2 + big1 -2222221120
big2 - big1 -44691356900
big1 + big2 1019355
big1 - big2 820665
big2 + big1 1019355
big2 - big1 -820665

注:

1、#include "ccIOBase.h" 標頭檔案:

/*
 *  ccIOBase.h
 *  c++_common_codes
 *
 *  Created by xichen on 12-2-15.
 *  Copyright 2012 cc_team. All rights reserved.
 *
*/
#ifndef CC_IO_BASE_H
#define CC_IO_BASE_H

#include <iostream>
using namespace std;

#define COUT_ENDL(message)	   std::cout << (message) << std::endl; 

#define COUT_LINE(str)		   std::cout << (str) << std::endl;
#define COUT_2_VAR_ENDL(str1, str2)			\
			std::cout << (str1) << " " << (str2) << std::endl;

#define PRINT_STARS                          std::cout << "********************************\n";

#endif