大数类,数据结构
在这里我讲一下我刚实现的这个大数类的数据结构,事实上这也是整个大数类中我最感到高兴的部分之一。
首先我用typedef unsigned unit;定义了存储的单元,unit用于存储整数的位,之所以用typedef,是为了以后变更的考虑。我为什么选择unsigned呢?
unsigned是unsigned int(无符号整数),32位机里它的长度是32位,可以储存9个十进制位!有效利用30/32左右的空间。注意,我用一个单元存储9个十进制位!而不是一个!事实上,它可以说是一个10亿进制数,这样做相对10进制可以使空间的使用降低为1/9,而效率接近原来的9倍!
那么,我为什么不用2^32进制呢?这样不是可以对空间完全的使用吗?确实是,我也想。但是,虽然运算没问题,但是输出是由问题的,把2^32进制以10进制输出我没有想到和给出任何高效的算法,这一点上我认为少两位是可以接受的,我不会在乎运算上这么点效率差距的。而且我在后面需要用到它单位的额外空间,因为每一位在超过10亿后,不会溢出!我只要把多余部分传递给高位就可以,而不需要用额外的变量传递,这在某种程度上提高了后面加法和减法的效率,包括后面的除法,都需要用到这“额外的空间”。
刚说到输出问题,10进制的数,很方便的就可以以10进制输出。第一步是输出首位,这很简单,直接输出。然后是后面的10亿进制单位,我使用了函数printunit()来输出,函数接受每一个单位和10机制的位数(bit是9,之所以用bit额不是直接用9,为的是以后更改,比如64位机上,bit是类的成员变量),就能输出指定位数的10进制。函数使用了递归实现(不是非得这样),巧妙的利用求余和整除传递递归参数,当然这只是一个很基本的递归,有兴趣的话可以分析下我的代码。
现在分析下我的存储方式,我用了unit *型的number指针,分配new unit[limit]的空间(limit也是成员变量,用于指定number指针的空间,也是为了方便以后引入可变的长度当然目前我在这里没有实现它,你有兴趣的话可以自己实现)。我在类中给出的长度是100000,一般是够了,能够提供900000位的整数了已经。
现在来看number指针保存数据的方式,我用number[0]保存最低9位整数,number[1]保存10~18位,以此类推,成员变量length保存数据的长度,比如27位整数,length就是3,28位整数,length就是4.因为每一个单位存储9位整数!。
然后,非常重要的一点,初始化,非常严格的初始化。所有的函数必须保证这种严格。简单的说就是如果只有21位,那么所有number空间的其余高位(第22位及以上)必须全部置为0,而且length的值必须准确无误。因为所有函数都不会校验这个东西,所有函数都假定,传递过来的参数以及构造函数都是严格的。同时,如果函数的输出也必须保证对输出的初始话是严格的!