本文仅做参考,主要是体现大数实现原理。
大数操作是使用计算机计算经常遇到的问题。
使用VS2005,在32位的机器上
各个类型的大小:
sizeof(int): 4
sizeof(unsigned): 4
sizeof(long): 4
sizeof(long long): 8
sizeof(char): 1
因此,unsigned的二进制位数为:4*8=32位,能够表示的最大数为:4294967295 即
11111111 11111111 11111111 11111111
而 long long 最大能够表示的无符号数为2^64 -1=18446744073709551615
因此,实现一个大数类是很有必要的。
网上有很多以实现不错的大数类,我这里只是练习练习。
使用数组记录大数据:
* 这里列举vector<char> dats表示大数
*100000的二进制为:
* 1111 01000010 01000000
*将之存放到数组中为:
* ----------------- ----------------- -----------------
* | 第2个元素 | | 第1个元素 | | 第0个元素 |
* ----------------- ----------------- -----------------
* | | | | |1|1|1|1| | |1|0|0|0|0|1|0| | |1|0|0|0|0|0|0|
* ----------------- ----------------- -----------------
* 即:dats[0] = 64,dats[1] =66,dats[2]=15
* 还原方法:((dats[2]*2^8)+dats[1])*2^8+dats[0] = 100000
定义一个大数类的结构:
class bigint
{
char sign; //符号0:+, 1:-
vector<unsigned> dats;
}
1.将string转到dats中,可以通过用2除来转为二进制。
例如:string numStr = ‘76543210’;
首先由于末位为0,为偶数,所以记录0,结果为0
7&1==1 有补位给6, 7>>1 = 3
16&1==0 无补位, 16>>1 = 8
5&1 ==1 有补位给4, 5>>1 = 2
14&1 ==0 无补位…
最后得到38271605
由于末位为5,为奇数,所以再记录1,结果为10
在次除2得到19135802
由于末位为2,为偶数,所以再记录0,结果为010
….
最后当末位为1,为奇数,再记录1,结果为100100011111111010011101010
当然也可以采用分块计算,即把numStr分成多个整数,如:
numStr = “755432109876543210”;
可以每次取8位放入到vector<unsigned> arr中,得到:
Arr = {75,54321098,76543210};
同样,也可以按照上面的除法,只是数组元素之间的补位值相当于10^8。
如,第一个数75&1==1,所以补位为1,也就说,
下一个数是154321098>>1.
2.加操作:
对应dats各块,进行加,数组的每个位置和用long long carry记录,则该为的值 = carry & (1<<32 -1)
而进位值为carry>>32.具体需要注意位对齐细节,以及最后的进位处理,可能会进位多次。还要注意数的符号。
3.减操作:
减法是通过反码来实现的,其实就是利用越界来实现。
如:正数A – 正数B,首先求正数B的反码
若当相减之后为正数,那就是(正数A + 正数B的反码)再加1.
若相减之后为负数,那么就是(正数A + 正数B的反码)再取反码。当然别忘了修改符号sign。
对于乘除,则需要对数组各个部分进行分开来看,考虑进位即可。
跟加法很相似,只是原来各位置相加变为一个位置对应多个位置的相加。
4.除法操作:
按照位运算来操纵。
贴上代码,代码只是半成品,未经过测试,不能直接使用。