ZZ:高精度的数据运算

大多数的编译器只能支持到64位的整数运算,即我们在运算中所使用的整数必须小于等于64位,即:
0xffffffffffffffff,也就是18446744073709551615,这远远达不现代大数的要求。于是需要专门建立大数运算库来解决这一问题。

最简单的办法是将大数当作数组进行处理,也就是将大数用0—9这十个数字组成的数组进行表示,然后模拟人们手工进行“竖式计算”的过程编写其加减乘除函数。但是这样做效率很低,因为二进制为1024位的大数其十进制也有三百多位,对于任何一种运算,都需要在两个有数百个元素的数组空间上做多重循环,还需要许多额外的空间存放计算的进退位标志及中间结果。另外,对于某些特殊的运算而言,采用二进制会使计算过程大大简化,这种大数表示方法转化成二进制显然非常麻烦,所以在某些实例中则干脆采用了二进制数组的方法来记录大数,这样效率就更低了。

一个有效的改进方法是将大数/100000000,假如将一个二进制为1024位的大数转化成0x100000000进制,它就变成了32位,而每一位的取值范围就不是二进制的0—1或十进制的0—9,而是0-0xffffffff,我们正好可以用一个无符号长整数来表示这一数值。所以1024位的大数就是一个有32个元素的unsigned long数组,针对unsigned long数组进行各种运算所需的循环规模至多32次而已。而且0x100000000 进制与二进制,对于计算机来说,几乎是一回事,转换非常容易。

例如大数18446744073709551615,等于 ffffffff ffffffff,就相当于十进制的99:有两位,每位都是ffffffff。而18446744073709551616 等于00000001 00000000 00000000,就相当于十进制的100:有三位,第一位是1 ,其它两位是0,如此等等。在实际应用中,“数字”数组的排列顺序采用低位在前高位在后的方式,这样,大数A 就可以方便地用数学表达式来表示其值:A=Sum[i=0 to n](A[i]*0x100000000^i)(其中Sum 表示求和,A[i]表示用以记录A 的数组的第i 个元素,^表示乘方)。


任何整数运算最终都能分解成数字与数字之间的运算,在0x100000000 进制下其“数字”最大达到0xffffffff,其数字与数字之间的运算,结果也必然超出了目前32系统的字长。在VC++中,存在一个__int64 类型可以处理64位的整数,所以不用担心这一问题,而在其它编译系统中如果不存在64位整形,就需要采用更小的进制方式来存储大数,例如WORD类型(16位)可以用来表示0x10000 进制,但效率更高的办法还是采用32位的DWORD 类型。

View Code
  1 #include <iostream>
2 #include <string>
3 using namespace std;
4
5 inline int compare(string str1, string str2)
6 {
7 if(str1.size() > str2.size()) //长度长的整数大于长度小的整数
8 return 1;
9 else if(str1.size() < str2.size())
10 return -1;
11 else
12 return str1.compare(str2); //若长度相等,从头到尾按位比较,compare函数:相等返回0,大于返回1,小于返回-1
13 }
14 //高精度加法
15 string ADD_INT(string str1, string str2)
16 {
17 string MINUS_INT(string str1, string str2);
18 int sign = 1; //sign 为符号位
19 string str;
20 if(str1[0] == '-') {
21 if(str2[0] == '-') {
22 sign = -1;
23 str = ADD_INT(str1.erase(0, 1), str2.erase(0, 1));
24 }else {
25 str = MINUS_INT(str2, str1.erase(0, 1));
26 }
27 }else {
28 if(str2[0] == '-')
29 str = MINUS_INT(str1, str2.erase(0, 1));
30 else {
31 //把两个整数对齐,短整数前面加0补齐
32 string::size_type l1, l2;
33 int i;
34 l1 = str1.size(); l2 = str2.size();
35 if(l1 < l2) {
36 for(i = 1; i <= l2 - l1; i++)
37 str1 = "0" + str1;
38 }else {
39 for(i = 1; i <= l1 - l2; i++)
40 str2 = "0" + str2;
41 }
42 int int1 = 0, int2 = 0; //int2 记录进位
43 for(i = str1.size() - 1; i >= 0; i--) {
44 int1 = (int(str1[i]) - 48 + int(str2[i]) - 48 + int2) % 10; //48 为 '0' 的ASCII 码
45 int2 = (int(str1[i]) - 48 + int(str2[i]) - 48 +int2) / 10;
46 str = char(int1 + 48) + str;
47 }
48 if(int2 != 0) str = char(int2 + 48) + str;
49 }
50 }
51 //运算后处理符号位
52 if((sign == -1) && (str[0] != '0'))
53 str = "-" + str;
54 return str;
55 }
56
57
58 //高精度减法
59 string MINUS_INT(string str1, string str2)
60 {
61 string MULTIPLY_INT(string str1, string str2);
62 int sign = 1; //sign 为符号位
63 string str;
64 if(str2[0] == '-')
65 str = ADD_INT(str1, str2.erase(0, 1));
66 else {
67 int res = compare(str1, str2);
68 if(res == 0) return "0";
69 if(res < 0) {
70 sign = -1;
71 string temp = str1;
72 str1 = str2;
73 str2 = temp;
74 }
75 string::size_type tempint;
76 tempint = str1.size() - str2.size();
77 for(int i = str2.size() - 1; i >= 0; i--) {
78 if(str1[i + tempint] < str2[i]) {
79 str1[i + tempint - 1] = char(int(str1[i + tempint - 1]) - 1);
80 str = char(str1[i + tempint] - str2[i] + 58) + str;
81 }
82 else
83 str = char(str1[i + tempint] - str2[i] + 48) + str;
84 }
85 for(i = tempint - 1; i >= 0; i--)
86 str = str1[i] + str;
87 }
88 //去除结果中多余的前导0
89 str.erase(0, str.find_first_not_of('0'));
90 if(str.empty()) str = "0";
91 if((sign == -1) && (str[0] != '0'))
92 str = "-" + str;
93 return str;
94 }
95
96 //高精度乘法
97 string MULTIPLY_INT(string str1, string str2)
98 {
99 int sign = 1; //sign 为符号位
100 string str;
101 if(str1[0] == '-') {
102 sign *= -1;
103 str1 = str1.erase(0, 1);
104 }
105 if(str2[0] == '-') {
106 sign *= -1;
107 str2 = str2.erase(0, 1);
108 }
109 int i, j;
110 string::size_type l1, l2;
111 l1 = str1.size(); l2 = str2.size();
112 for(i = l2 - 1; i >= 0; i --) { //实现手工乘法
113 string tempstr;
114 int int1 = 0, int2 = 0, int3 = int(str2[i]) - 48;
115 if(int3 != 0) {
116 for(j = 1; j <= (int)(l2 - 1 - i); j++)
117 tempstr = "0" + tempstr;
118 for(j = l1 - 1; j >= 0; j--) {
119 int1 = (int3 * (int(str1[j]) - 48) + int2) % 10;
120 int2 = (int3 * (int(str1[j]) - 48) + int2) / 10;
121 tempstr = char(int1 + 48) + tempstr;
122 }
123 if(int2 != 0) tempstr = char(int2 + 48) + tempstr;
124 }
125 str = ADD_INT(str, tempstr);
126 }
127 //去除结果中的前导0
128 str.erase(0, str.find_first_not_of('0'));
129 if(str.empty()) str = "0";
130 if((sign == -1) && (str[0] != '0'))
131 str = "-" + str;
132 return str;
133 }
134 //高精度除法
135 string DIVIDE_INT(string str1, string str2, int flag)
136 {
137 //flag = 1时,返回商; flag = 0时,返回余数
138 string quotient, residue; //定义商和余数
139 int sign1 = 1, sign2 = 1;
140 if(str2 == "0") { //判断除数是否为0
141 quotient = "ERROR!";
142 residue = "ERROR!";
143 if(flag == 1) return quotient;
144 else return residue;
145 }
146 if(str1 == "0") { //判断被除数是否为0
147 quotient = "0";
148 residue = "0";
149 }
150 if(str1[0] == '-') {
151 str1 = str1.erase(0, 1);
152 sign1 *= -1;
153 sign2 = -1;
154 }
155 if(str2[0] == '-') {
156 str2 = str2.erase(0, 1);
157 sign1 *= -1;
158 }
159 int res = compare(str1, str2);
160 if(res < 0) {
161 quotient = "0";
162 residue = str1;
163 }else if(res == 0) {
164 quotient = "1";
165 residue = "0";
166 }else {
167 string::size_type l1, l2;
168 l1 = str1.size(); l2 = str2.size();
169 string tempstr;
170 tempstr.append(str1, 0, l2 - 1);
171 //模拟手工除法
172 for(int i = l2 - 1; i < l1; i++) {
173 tempstr = tempstr + str1[i];
174 for(char ch = '9'; ch >= '0'; ch --) { //试商
175 string str;
176 str = str + ch;
177 if(compare(MULTIPLY_INT(str2, str), tempstr) <= 0) {
178 quotient = quotient + ch;
179 tempstr = MINUS_INT(tempstr, MULTIPLY_INT(str2, str));
180 break;
181 }
182 }
183 }
184 residue = tempstr;
185 }
186 //去除结果中的前导0
187 quotient.erase(0, quotient.find_first_not_of('0'));
188 if(quotient.empty()) quotient = "0";
189 if((sign1 == -1) && (quotient[0] != '0'))
190 quotient = "-" + quotient;
191 if((sign2 == -1) && (residue[0] != '0'))
192 residue = "-" + residue;
193 if(flag == 1) return quotient;
194 else return residue;
195 }
196
197 //高精度除法,返回商
198 string DIV_INT(string str1, string str2)
199 {
200 return DIVIDE_INT(str1, str2, 1);
201 }
202 //高精度除法,返回余数
203 string MOD_INT(string str1, string str2)
204 {
205 return DIVIDE_INT(str1, str2, 0);
206 }
207
208 int main()
209 {
210 char ch;
211 string s1, s2, res;
212 while(cin >> ch) {
213 cin >> s1 >> s2;
214 switch(ch) {
215 case '+': res = ADD_INT(s1, s2); break; //高精度加法
216 case '-': res = MINUS_INT(s1, s2); break; //高精度减法
217 case '*': res = MULTIPLY_INT(s1, s2); break; //高精度乘法
218 case '/': res = DIV_INT(s1, s2); break; //高精度除法, 返回商
219 case 'm': res = MOD_INT(s1, s2); break; //高精度除法, 返回余数
220 default : break;
221 }
222 cout << res << endl;
223 }
224 return(0);
225 }



posted @ 2012-02-20 10:54  ITfresh  阅读(330)  评论(0编辑  收藏  举报