一般大家提到的方法是用数组,每个数字要么表示一个10进制位,要么表示几个10进制位。我觉得这样虽然在对“人”是直观了,但是对“电脑”却非常不直观,所以我觉得应该按照计算机的2进制表示方式来实现。
按照自己的想法,我写了这样一个大整数类,内部用long的数组来表示,是在2进制层面,即2个long表示了2^64 bits以内的数值,4个long表示了2^128 bits以内的数值。
为了与原始整数类型一致(我在设计时考虑的最多的就是这个因素了),我分了signed和unsigned,在运算符重载,类型转化,使用方式等方面尽量接近原始的long和unsigned long类型。但是有些“死角”在不同的编译器里都有不同的表现,所以我实际上是按照VS2005编译器下的原始类型的行为来设计的,而且还不能做到完全一样。不过我觉得有差异的那些“死角”并不是很重要。
其实我现在贴出来的是一个早先的版本,因为最新的版本还没有经过测试,所以稳定性和正确性还不能得到保证。不过贴出来的这个版本已经完成了我想要的所有功能,新的修改只是在锦上添花。
整个工程其实只有6个代码文件,相当少了,当然没包括测试用的代码:
HugeLongNumber.h
UnsignedHugeLong.h
SignedHugeLong.h
HugeNumberBase.h
Helper.h
DataAllocation.h
我从外面的包装代码开始介绍吧。
1.HugeLongNumber.h
——C++——————————————————————————————————
/*
* Copyright (c) 2005 by DoZerg. ALL RIGHTS RESERVED.
* Consult your license regarding permissions and restrictions.
*/
#pragma once
#include "UnsignedHugeLong.h"
#include "SignedHugeLong.h"
namespace DoZerg{
//typedefs:
typedef UnsignedHugeLong<1> ulong0;
typedef UnsignedHugeLong<2> ulong1;
typedef UnsignedHugeLong<4> ulong2;
typedef UnsignedHugeLong<8> ulong3;
typedef UnsignedHugeLong<16> ulong4;
typedef UnsignedHugeLong<32> ulong5;
typedef UnsignedHugeLong<64> ulong6;
typedef UnsignedHugeLong<128> ulong7;
typedef UnsignedHugeLong<256> ulong8;
typedef UnsignedHugeLong<512> ulong9;
typedef UnsignedHugeLong<1024> ulong10;
//typedefs:
typedef SignedHugeLong<1> slong0;
typedef SignedHugeLong<2> slong1;
typedef SignedHugeLong<4> slong2;
typedef SignedHugeLong<8> slong3;
typedef SignedHugeLong<16> slong4;
typedef SignedHugeLong<32> slong5;
typedef SignedHugeLong<64> slong6;
typedef SignedHugeLong<128> slong7;
typedef SignedHugeLong<256> slong8;
typedef SignedHugeLong<512> slong9;
typedef SignedHugeLong<1024> slong10;
//others:
#define GLOBAL_DEFINE_OPERATOR(oper) /
template<long N,class T1,class T2> /
inline const UnsignedHugeLong<N,T1> operator ##oper##(const SignedHugeLong<N,T2> & value1,const UnsignedHugeLong<N,T1> & value2){ /
return UnsignedHugeLong<N,T1>(value2).operator ##oper##=(value1); /
} /
template<long N,class T1,class T2> /
inline const UnsignedHugeLong<N,T1> operator ##oper##(const UnsignedHugeLong<N,T1> & value1,const SignedHugeLong<N,T2> & value2){ /
return UnsignedHugeLong<N,T1>(value1).operator ##oper##=(value2); /
}
GLOBAL_DEFINE_OPERATOR(+);
GLOBAL_DEFINE_OPERATOR(-);
GLOBAL_DEFINE_OPERATOR(*);
GLOBAL_DEFINE_OPERATOR(/);
GLOBAL_DEFINE_OPERATOR(%);
#undef GLOBAL_DEFINE_OPERATOR
}//namespace DoZerg
——————————————————————————————————————
这是对类UnsignedHugeLong和SignedHugeLong名字的包装,分别定义成了ulong和slong,表示无符号和有符号整数。
接下来的代码主要是对2者混合运算的处理,参考VS2005的原始整型的行为来定的。
2.UnsignedHugeLong.h
——C++——————————————————————————————————
/*
* Copyright (c) 2005 by DoZerg. ALL RIGHTS RESERVED.
* Consult your license regarding permissions and restrictions.
*/
#pragma once
#include "HugeNumberBase.h"
namespace DoZerg{
//For operator +,-,*,/ and % implementation
#define UNSIGNED_MEMBER_DEFINE_OPERATOR(oper) /
template<typename __ValueType> /
const UnsignedHugeLong operator ##oper##(const __ValueType & value) const{ /
return UnsignedHugeLong<N,__Alloc>(*this).operator ##oper##=(value); /
} /
const UnsignedHugeLong operator ##oper##(const UnsignedHugeLong & value) const{ /
return UnsignedHugeLong<N,__Alloc>(*this).operator ##oper##=(value); /
}
#define UNSIGNED_GLOBAL_DEFINE_OPERATOR(oper) /
template<typename __ValueType,long N,class T> /
inline const UnsignedHugeLong<N,T> operator ##oper##(const __ValueType & value1,const UnsignedHugeLong<N,T> & value2){ /
return UnsignedHugeLong<N,T>(value1).operator ##oper##=(value2); /
}//*/
//declaration.
template<
long N,
template<long,typename>class __Alloc = DataAutoSelect
>class UnsignedHugeLong:public HugeNumberBase<N,__Alloc>
{
public:
UnsignedHugeLong(){}
template<typename __ValueType>
UnsignedHugeLong(const __ValueType & value):HugeNumberBase<N,__Alloc>(value){}
UnsignedHugeLong & operator =(const std::string &);
const UnsignedHugeLong operator +() const;
const UnsignedHugeLong operator -() const;
const UnsignedHugeLong operator ~() const;
const UnsignedHugeLong operator >>(long) const;
const UnsignedHugeLong operator <<(long) const;
const UnsignedHugeLong & operator ++();
const UnsignedHugeLong operator ++(int);
const UnsignedHugeLong & operator --();
const UnsignedHugeLong operator --(int);
const UnsignedHugeLong & operator >>=(long);
const UnsignedHugeLong & operator <<=(long);
const UnsignedHugeLong & operator +=(const UnsignedHugeLong &);
const UnsignedHugeLong & operator -=(const UnsignedHugeLong &);
const UnsignedHugeLong & operator *=(const UnsignedHugeLong &);
const UnsignedHugeLong & operator /=(const UnsignedHugeLong &);
const UnsignedHugeLong & operator &=(const UnsignedHugeLong &);
const UnsignedHugeLong & operator |=(const UnsignedHugeLong &);
const UnsignedHugeLong & operator ^=(const UnsignedHugeLong &);
const UnsignedHugeLong & operator %=(const UnsignedHugeLong &);
bool operator ==(const UnsignedHugeLong &) const;
bool operator !=(const UnsignedHugeLong &) const;
const UnsignedHugeLong Power(const UnsignedHugeLong &);
const std::string ToString(int = 10) const;
UNSIGNED_MEMBER_DEFINE_OPERATOR(+);
UNSIGNED_MEMBER_DEFINE_OPERATOR(-);
UNSIGNED_MEMBER_DEFINE_OPERATOR(*);
UNSIGNED_MEMBER_DEFINE_OPERATOR(/);
UNSIGNED_MEMBER_DEFINE_OPERATOR(%);
//friend functions. for several reasons they can't be implemented outside
inline friend bool operator >(const UnsignedHugeLong & value1,const UnsignedHugeLong & value2){
return value1.OperatorLarger(value2);
}
inline friend bool operator <(const UnsignedHugeLong & value1,const UnsignedHugeLong & value2){
return value1.OperatorSmaller(value2);
}
inline friend bool operator >=(const UnsignedHugeLong & value1,const UnsignedHugeLong & value2){
return value1.OperatorNotSmaller(value2);
}
inline friend bool operator <=(const UnsignedHugeLong & value1,const UnsignedHugeLong & value2){
return value1.OperatorNotLarger(value2);
}
template<typename __OutStreamType>
inline friend __OutStreamType & operator <<(__OutStreamType & os,const UnsignedHugeLong & value){
return os<<value.ToString();
}
inline friend std::ostream & operator <<(std::ostream & os,const UnsignedHugeLong & value){
return os<<value.ToString((0xc00&os.flags())>>7); //is there a better way to deal with the base(8,10 or16)?
}
};
//definition
//public:
template<long N,template<long,typename>class __Alloc>
inline UnsignedHugeLong<N,__Alloc> & UnsignedHugeLong<N,__Alloc>::operator =(const std::string & value){
FromString(value);
return *this;
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> UnsignedHugeLong<N,__Alloc>::operator +() const{
return UnsignedHugeLong<N,__Alloc>(*this);
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> UnsignedHugeLong<N,__Alloc>::operator -() const{
return UnsignedHugeLong<N,__Alloc>(*this).Minus();
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> UnsignedHugeLong<N,__Alloc>::operator ~() const{
return UnsignedHugeLong<N,__Alloc>(*this).Complement();
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> UnsignedHugeLong<N,__Alloc>::operator >>(long value) const{
return UnsignedHugeLong<N,__Alloc>(*this).RightShift(value);
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> UnsignedHugeLong<N,__Alloc>::operator <<(long value) const{
return UnsignedHugeLong<N,__Alloc>(*this).LeftShift(value);
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> & UnsignedHugeLong<N,__Alloc>::operator ++(){ //you could throw "overflow" if you want
Increase();
return *this;
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> UnsignedHugeLong<N,__Alloc>::operator ++(int){
UnsignedHugeLong<N,__Alloc> tmp(*this);
operator ++();
return tmp;
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> & UnsignedHugeLong<N,__Alloc>::operator --(){
Decrease();
return *this;
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> UnsignedHugeLong<N,__Alloc>::operator --(int){
UnsignedHugeLong<N,__Alloc> tmp(*this);
operator --();
return tmp;
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> & UnsignedHugeLong<N,__Alloc>::operator >>=(long value){
RightShift(value);
return *this;
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> & UnsignedHugeLong<N,__Alloc>::operator <<=(long value){
LeftShift(value);
return *this;
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> & UnsignedHugeLong<N,__Alloc>::operator +=(const UnsignedHugeLong & value){
OperatorAdd(value);
return *this;
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> & UnsignedHugeLong<N,__Alloc>::operator -=(const UnsignedHugeLong & value){
OperatorSub(value);
return *this;
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> & UnsignedHugeLong<N,__Alloc>::operator *=(const UnsignedHugeLong & value){
OperatorMult(value);
return *this;
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> & UnsignedHugeLong<N,__Alloc>::operator /=(const UnsignedHugeLong & value){
OperatorDiv(value);
return *this;
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> & UnsignedHugeLong<N,__Alloc>::operator &=(const UnsignedHugeLong & value){
OperatorAnd(value);
return *this;
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> & UnsignedHugeLong<N,__Alloc>::operator |=(const UnsignedHugeLong & value){
OperatorOr(value);
return *this;
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> & UnsignedHugeLong<N,__Alloc>::operator ^=(const UnsignedHugeLong & value){
OperatorXor(value);
return *this;
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> & UnsignedHugeLong<N,__Alloc>::operator %=(const UnsignedHugeLong & value){
OperatorDiv(value,false);
return *this;
}
template<long N,template<long,typename>class __Alloc>
inline bool UnsignedHugeLong<N,__Alloc>::operator ==(const UnsignedHugeLong & value) const{
return OperatorEqual(value);
}
template<long N,template<long,typename>class __Alloc>
inline bool UnsignedHugeLong<N,__Alloc>::operator !=(const UnsignedHugeLong & value) const{
return !operator ==(value);
}
template<long N,template<long,typename>class __Alloc>
inline const UnsignedHugeLong<N,__Alloc> UnsignedHugeLong<N,__Alloc>::Power(const UnsignedHugeLong & value){
return UnsignedHugeLong<N,__Alloc>(*this).OperatorPower(value);
}
template<long N,template<long,typename>class __Alloc>
inline const std::string UnsignedHugeLong<N,__Alloc>::ToString(int BaseValue) const{
return HugeNumberBase<N,__Alloc>::ToString(BaseValue);
}
//others:
template<typename __ValueType,long N,class __Alloc>
inline bool operator ==(const __ValueType & value1,const UnsignedHugeLong<N,__Alloc> & value2){
return value2.operator ==(value1);
}
template<typename __ValueType,long N,class __Alloc>
inline bool operator !=(const __ValueType & value1,const UnsignedHugeLong<N,__Alloc> & value2){
return value2.operator !=(value1);
}
UNSIGNED_GLOBAL_DEFINE_OPERATOR(+);
UNSIGNED_GLOBAL_DEFINE_OPERATOR(-);
UNSIGNED_GLOBAL_DEFINE_OPERATOR(*);
UNSIGNED_GLOBAL_DEFINE_OPERATOR(/);
UNSIGNED_GLOBAL_DEFINE_OPERATOR(%);
#undef UNSIGNED_MEMBER_DEFINE_OPERATOR
#undef UNSIGNED_GLOBAL_DEFINE_OPERATOR
} //namespace DoZerg
——————————————————————————————————————
这段代码要说的内容就多一些了。
首先UnsignedHugeLong是表示无符号大整数的类模版,模版参数有2个:
long N,
template<long,typename>class __Alloc
前者N表示大整数内部有多少个long的数据,也就能表示2^(32 * N)以内的整数。
后者__Alloc是表示内部的long数组采用哪种存储方式,具体可选的的类定义在DataAllocation.h中,后面会讲道。
UnsignedHugeLong主要的工作就是对运算符进行重载,从代码里可以看出来,它基本上都是调用基类HugeNumberBase的Operator...函数来完成实际的运算。
UnsignedHugeLong还有一个重要的任务,就是对各种原始数据类型的兼容,这曾经是我很头疼的问题之一。代码中的那些可恶的宏基本上就是完成这部分工作的。