大整数类的实现(5)(原创)

5.HugeNumberBase.h

————————————————————————————————————————

/*
 * Copyright (c) 2005 by DoZerg.  ALL RIGHTS RESERVED.
 * Consult your license regarding permissions and restrictions.
 */
/************************Things to do***************************
1.Using Exception-Class to indicate whether to throw an exception or not when an error occurs
(DONE)2.Using Memory-Class to indicate Memory Allocation Strategy
(DONE)3.Type conversion with operator +,-,*,/,%
4.Using Traits to eliminate type specialization with unsigned long
5.Performance Profile,especially for operator << and >>
***************************************************************/
#pragma once
#include "Helper.h"
#include "DataAllocation.h"

namespace DoZerg{
//declaration.
    template<
        long N,
        template<long,typename>class __Alloc
    >class HugeNumberBase
    {
        __Alloc<N,unsigned long> data_;     //the highest byte is data_[0],and the lowest is data_[N-1]
        //unsigned long data_[N];
        static const long EachBits;         //bits per data_
        static const long TotalBits;        //total bits of data_[N]
    public:
        static const long TotalBytes;       //total bytes of data_[N]
    private:
        static const unsigned long SignBit;
        void AddOne(long);                          //add 1 in a particular position
        bool EqualValue(unsigned long) const;       //test if *this is equal to a value
        long HighestBit() const;                    //return the highest bit position based on 0
        long LowestBit() const;                     //return the lowest bit position based on 0
        HugeNumberBase & ResetHigherBits(long);     //reset the higher bits than a value to 0
        HugeNumberBase & RightShift();
        HugeNumberBase & LeftShift();
    protected:
        HugeNumberBase(){}
        explicit HugeNumberBase(long);
        explicit HugeNumberBase(const std::string &);
        template<long M,class T>
            explicit HugeNumberBase(const HugeNumberBase<M,T> &);
        HugeNumberBase & FromLong(long);
        HugeNumberBase & FromString(const std::string &);
        template<long M,class T>
            HugeNumberBase & FromSelf(const HugeNumberBase<M,T> &);
        HugeNumberBase & Increase();                        //operator ++()
        HugeNumberBase & Decrease();                        //operator --()
        HugeNumberBase & Complement();                      //self ~()
        HugeNumberBase & Minus();                           //self -()
        HugeNumberBase & RightShift(long,bool = false);     //the bool means whether to treat *this as a signed value
        HugeNumberBase & LeftShift(long);
        HugeNumberBase & OperatorAdd(const HugeNumberBase &);
        HugeNumberBase & OperatorSub(const HugeNumberBase &);
        HugeNumberBase & OperatorMult(const HugeNumberBase &);
        HugeNumberBase & OperatorAnd(const HugeNumberBase &);
        HugeNumberBase & OperatorOr(const HugeNumberBase &);
        HugeNumberBase & OperatorXor(const HugeNumberBase &);
        HugeNumberBase & OperatorDiv(const HugeNumberBase &,bool = true);   //return divided result if bool==true by default,otherwise return the modulus
        HugeNumberBase & OperatorPower(const HugeNumberBase &);
        bool OperatorEqual(const HugeNumberBase & value) const;
        bool OperatorSmaller(const HugeNumberBase & value) const;
        bool OperatorLarger(const HugeNumberBase & value) const;
        bool OperatorNotSmaller(const HugeNumberBase & value) const;
        bool OperatorNotLarger(const HugeNumberBase & value) const;
        const std::string ToString(int = 10,bool = false) const;    //the bool means whether to treat *this as a signed value
    public:
        long ToLong() const;
        bool GetSignBit() const;
        const bool NonZero() const;
        const bool operator !() const;
        const void * DataPointer(long = 0) const;   //return the n-th data_'s pointer
//temporary functions
        void show() const{
            for(long i=0;i<N;i++)
                cout<<hex<<data_[i]<<' ';
            cout<<dec<<"Highbit:"<<HighestBit()
                <<" Lowbit:"<<LowestBit();
            cout<<endl;
        }
//friend functions. for several reasons they can't be implemented outside
        friend std::istream & operator >>(std::istream & is,HugeNumberBase & value){
            std::string tmp;
            is>>tmp;
            value.FromString(tmp);
            return is;
        }
    };
    template<class T>class HugeNumberBase<0,T>{};

 

......

————————————————————————————————————————

 

终于轮到HugeNumberBase了,其实我早就已经迫不及待了。但是不幸的是,当我看到HugeNumberBase.h的代码才知道,继续采用前面的“代码+解说”形式会有什么后果:要么就是这篇文章过长,要么就是读者不停的在代码页面和解说页面间切换。
所以我决定作一个变革,我先把HugeNumberBase的定义给出来,也就是HugeNumberBase.h的前半部分;然后在以后的文章里给出实现代码,并一一讲解。我想这样作者和读者都要方便很多。
HugeNumberBase的内部成员变量只有一个data_。它的定义如下:

__Alloc<N,unsigned long> data_;
//unsigned long data_[N];

下面的代码很好的解释了data_的本质。实际上这2行代码可以相互替换,不影响HugeNumberBase的行为。数据的高位存于data_[0]内,低位存于data_[N-1]内,这是一个设计决定,对HugeNumberBase的性能并不会有太大影响。
__Alloc就是我前面介绍的DataAllocation.h中的3个类模板之一。其实它作为一个Traits,可以是任何实现了相关接口和功能的类模板,并且我在后来的版本中还实现了采用“Copy On Write”和引用计数策略的Alloc。
我提醒读者注意几个常量的意义和私有的成员函数,因为它们是HugeNumberBase的基石,也是最先被实现的部分,我的讲解也将从它们开始。

1)
————————————————————————
//definition
//private:
    template<long N,template<long,typename>class __Alloc>
        const long HugeNumberBase<N,__Alloc>::EachBits = 8 * sizeof(unsigned long);
    template<long N,template<long,typename>class __Alloc>
        const long HugeNumberBase<N,__Alloc>::TotalBits = N * EachBits;
    template<long N,template<long,typename>class __Alloc>
        const long HugeNumberBase<N,__Alloc>::TotalBytes = N * sizeof(unsigned long);
    template<long N,template<long,typename>class __Alloc>
        const unsigned long HugeNumberBase<N,__Alloc>::SignBit = unsigned long(1)<<(EachBits-1);
    template<long N,template<long,typename>class __Alloc>
        void HugeNumberBase<N,__Alloc>::AddOne(long Position){  //no asserts,so be careful
            long at(N-1-Position/EachBits);
            unsigned long tmp(data_[at]);
            if((data_[at--]+=unsigned long(1)<<(Position%EachBits))<tmp)
                while(at>=0 && !++data_[at])
                    --at;    //if at<0 then overflow
        }
————————————————————————
这是紧接HugeNumberBase定义的一段代码,我以数字来表示一段代码在HugeNumberBase定义后的顺序。
这里对几个常量进行了定义。这个版本的HugeNumberBase是用unsigned long的数组记录数据的,EachBits就是每个unsigned long的比特位长,TotalBits自然就是整个HugeNumberBase能表示的比特位长。SignBit在32位机器上就是unsigned long(0x80000000),用来提取long的符号位。

函数AddOne的作用在申明的时候有描述,即在HugeNumberBase的某个比特位置上加1,位置Position是指从最低比特位为0开始。注意我这里所说的HugeNumberBase,是指一个TotalBits比特的大整数,具体一点就是data_数组。

long at(N-1-Position/EachBits);
unsigned long tmp(data_[at]);

得到需要改变的data_数组下标at,并记录下data_[at]的原始值。
接下来的代码似乎有点复杂,我们从简单的开始。首先应该给data_[at]加上某个数值,我们可以这样写:

data_[at] += unsigned long(1) << (Position % EachBits);

但是这会漏掉一种情况,就是发生“进位”。比如data_[at]是0xFFFF...,在16~32任何比特位加1,都导致进位。此时应该在更高的data_上加1。
那么怎么判断是否发生了“进位”?把新的data_[at]与原始的值比较,如果变大了,那么没有进位;如果反而变小了,则发生了进位。于是我们修改一下这样写:

data_[at] += unsigned long(1) << (Position % EachBits);
if(data_[at] < tmp)
    ......

接下来应该给data_[at - 1]加1,同样考虑是否进位,并决定是否给data_[at - 2]加1,......
这些都在while循环里。最后我们把代码紧缩一下,就变成了原文的样子(读者可能也发现了,我的代码风格是很“紧缩”的)。

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值