大整数问题 (除法暂时有问题)

Posted on 2020-05-17 08:04  黑炽  阅读(242)  评论(0编辑  收藏  举报
  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 
  5 typedef struct bigInt {
  6     char* num;//指向长整数数组,序号0中保存着最低位,也就是倒序存放
  7     char minus;//符号,1表示正数,-1表示符数
  8     int digit;//保存位数
  9 }BigInt, *pBigInt;
 10 
 11 void bigIntTrans(pBigInt num1);//将字符串转化成数字表示
 12 void bigIntTrim(pBigInt num1);//整理大整数,去掉前面得0
 13 void bigIntPrint(pBigInt result);
 14 int bigIntEqual(pBigInt num1, pBigInt num2);//比较两个大整数大小
 15 void bigIntAdd(pBigInt num1, pBigInt num2, pBigInt result);
 16 void bigIntAdd1(pBigInt num1, pBigInt num2, pBigInt result);//同号相加
 17 void bigIntSub1(pBigInt num1, pBigInt num2, pBigInt result);//用于异号相加
 18 void bigIntSub(pBigInt num1, pBigInt num2, pBigInt result);//减法
 19 void bigIntMul(pBigInt num1, pBigInt num2, pBigInt result);//乘法
 20 void bigIntDiv(pBigInt num1, pBigInt num2, pBigInt result, pBigInt residue);//除法
 21 
 22 int main(void) {
 23     bigInt num1, num2, result, residue;
 24     int i = 0, len;
 25     char op;
 26     
 27     printf("输入最大数的位数:");
 28     scanf("%d", &len);
 29     if (!(num1.num = (char*)malloc(sizeof(char) * (len + 1)))) { printf("内存分配失败\n"); exit(0); }
 30     num1.digit = len + 1;
 31     if (!(num2.num = (char*)malloc(sizeof(char) * (len + 1)))) { printf("内存分配失败\n"); exit(0); }
 32     num2.digit = len + 1;
 33     if (!(result.num = (char*)malloc(sizeof(char) * (len + 1)))) { printf("内存分配失败\n"); exit(0); }
 34     result.digit = 2 * len + 1;
 35     for (i = 0; i < result.digit; i++)    result.num[i] = 0;
 36     printf("选择大整数运算(+,-,*,/): ");
 37     fflush(stdin);//刷新标准输入缓冲区,把输入缓冲区里的东西丢弃
 38     scanf(" %c", &op);
 39     switch (op) {
 40     case '+':
 41         printf("\n输入被加数:");    scanf("%s", num1.num);
 42         printf("\n输入加数:");    scanf("%s", num2.num);
 43         bigIntTrans(&num1);
 44         bigIntTrans(&num2);
 45         bigIntAdd(&num1, &num2, &result);
 46         break;
 47     case '-':
 48         printf("\n输入被减数:");    scanf("%s", num1.num);
 49         printf("\n输入减数:");    scanf("%s", num2.num);
 50         bigIntTrans(&num1);
 51         bigIntTrans(&num2);
 52         bigIntSub(&num1, &num2, &result);
 53         break;
 54     case '*':
 55         printf("\n输入被乘数:");    scanf("%s", num1.num);
 56         printf("\n输入乘数:");    scanf("%s", num2.num);
 57         bigIntTrans(&num1);
 58         bigIntTrans(&num2);
 59         bigIntMul(&num1, &num2, &result);
 60         break;
 61     case '/':
 62         printf("\n输入被除数:");    scanf("%s", num1.num);
 63         printf("\n输入除数:");    scanf("%s", num2.num);
 64         bigIntTrans(&num1);
 65         bigIntTrans(&num2);
 66         if (num2.digit == 1 && num2.num[0] == '0')    printf("除数不能为0!\n");
 67         else bigIntDiv(&num1, &num2, &result, &residue);
 68         break;
 69     }
 70 
 71     if (op == '/') {
 72         if (!(num2.digit == 1 && num2.num[0] == '0')) {
 73             printf("商:");    bigIntPrint(&result);
 74             printf("\t余数:");    bigIntPrint(&residue);
 75         }
 76     }
 77     else {printf("结果:");    bigIntPrint(&result);}
 78 
 79 
 80     return 0;
 81 }
 82 
 83 void bigIntTrans(pBigInt num1) {
 84     char* t;
 85     int i, k, len;
 86 
 87     len = strlen(num1->num);
 88     if (!(t = (char*)malloc(sizeof(char) * len))){printf("内存分配失败!\n");exit(0); }
 89     i = 0;
 90     num1->minus = 1;//默认为正
 91     if (num1->num[0] == '-') { num1->minus = -1; i++; }//若第一个字符试'-',那么则是负数
 92     k = 0;
 93     while (num1->num[i] != '\0') {
 94         if (num1->num[i] >= '0' && num1->num[i] <= '9') { t[k++] = num1->num[i] - '0'; }//将ASCII码转化成对应得数字
 95         i++;
 96     }
 97 
 98     for (i = 0; i < num1->digit; i++)    num1->num[i] = 0;//数组清空
 99     num1->digit = k;//转换后得位数
100     for (i = 0, k--; k >= 0; k--, i++)    num1->num[i] = t[k];//将临时数组 各位 反置 后存到num中
101 
102     bigIntTrim(num1);
103 
104 }
105 
106 void bigIntTrim(pBigInt num1) {
107     int i;
108     //从高位检查是否为0
109     for (i = num1->digit - 1; i >= 0; i--) { if (num1->num[i] != 0)    break; }//遇到不为0得最高位,跳出循环
110     if (i < 0) { num1->digit = 1; num1->num[0] = 0; }
111     else num1->digit = i + 1;//余数位数,因为i对应的是下标,比如对应的i=4,那么下标为0,1,2,3,4的位置上都有数,则为5位数
112 
113 }
114 
115 void bigIntPrint(pBigInt result) {
116     int i;
117 
118     if (result->minus == -1) printf("-"); 
119     if (result->digit == 1 && result->num[0] == 0) printf("0\n");
120     else {
121         for (i = result->digit - 1; i >= 0; i--)
122             printf("%d", result->num[i]);
123     }
124 }
125 
126 int bigIntEqual(pBigInt num1, pBigInt num2) {
127     int i;
128 
129     if (num1->digit > num2->digit)    return 1;
130     else if (num1->digit < num2->digit)    return -1;
131     else {
132         i = num1->digit - 1;
133         while (i >= 0) {
134             if (num1->num[i] > num2->num[i])    return 1;
135             else if (num1->num[i] < num2->num[i])    return -1;
136             else i--;
137         }
138     }
139     return 0;
140 }
141 
142 void bigIntAdd(pBigInt num1, pBigInt num2, pBigInt result) {
143     int i = bigIntEqual(num1, num2);
144 
145     if (i < 0) { pBigInt t; t = num1; num1 = num2; num2 = t; }
146     if (num1->minus * num2->minus < 0) {//符号相同,则加法,不同则减法
147         if (i == 0) {//如果两个数是相等的
148             result->digit = 1;//结果长度为1位数,就是数值0
149             result->minus = 1;//结果为正号
150             result->num[0] = 0;//结果为0
151             return;
152         }
153         bigIntSub1(num1, num2, result);//减法
154     }
155     else bigIntAdd1(num1, num2, result);
156 }
157 
158 void bigIntAdd1(pBigInt num1, pBigInt num2, pBigInt result) {
159     int i, carry = 0;//carry代表的 进位
160     
161     result->minus = num1->minus;
162     for (i = 0; i < num1->digit; i++) { result->num[i] = num1->num[i]; }
163     for (i = 0; i < num2->digit; i++) {
164         result->num[i] = result->num[i] + num2->num[i] + carry;//将对应的数和进位数相加
165         carry = result->num[i] / 10;//计算进位数据
166         result->num[i] = result->num[i] % 10;//保留一位
167     }
168 
169     if (carry)    result->num[i] = result->num[i] + carry;//若最后还有进位
170     bigIntTrim(result);
171 }
172 
173 void bigIntSub1(pBigInt num1, pBigInt num2, pBigInt result) {//异号相减函数
174     int i, borrow = 0;//borrow低位的借位
175 
176     result->minus = num1->minus;
177     for (i = 0; i < num1->digit; i++)    result->num[i] = num1->num[i];
178     for (i = 0; i <= num2->digit; i++) {
179         result->num[i] = result->num[i] - num2->num[i] - borrow;
180         if (result->num[i] < 0) {
181             result->num[i] = 10 + result->num[i];
182             borrow = 1;
183         }
184         else borrow = 0;
185     }
186 
187     if (borrow == 1)    result->num[i] = result->num[i] - borrow;
188     i = num1->digit;
189     while (i > 0) {
190         if (result->num[i] == 0)    i--;
191         else break;
192     }
193 
194     result->digit = i + 1;
195     bigIntTrim(result);
196 }
197 
198 void bigIntSub(pBigInt num1, pBigInt num2, pBigInt result) {
199     num2->minus = -1 * num2->minus;//将减数符号取反
200     bigIntAdd(num1, num2, result);
201 }
202 
203 void bigIntMul(pBigInt num1, pBigInt num2, pBigInt result) {
204     char carry, t;
205     int i, j, pos;
206 
207     for (i = 0; i < num1->digit + num2->digit; i++)    result->num[i] = 0;//结果数组清零
208     for (i = 0; i < num2->digit; i++) {
209         carry = 0;//清除进位
210         for (j = 0; j < num1->digit; j++) {
211             t = num2->num[i] * num1->num[j] + carry;//两个数相乘,加上进位
212             carry = t / 10;//进位
213             t %= 10;//计算当前位的值
214             pos = i + j;//看t应该加在哪个位上
215             result->num[pos] += t;
216             carry = carry + result->num[pos] / 10;//主要防止num[pos]大于等于10
217             result->num[pos] = result->num[pos] % 10;
218         }
219 
220         if (carry > 0) {
221             result->num[i + j] = carry;//加上最高位的进位
222             result->digit = i + j + 1;
223         }
224         else result->digit = i + j;
225     }
226 
227     result->minus = num1->minus * num2->minus;
228 }
229 
230 void bigIntDiv(pBigInt num1, pBigInt num2, pBigInt result, pBigInt residue) {
231     bigInt quo1, quo2, residue1;
232     int i, j, k, m;//k保存试商结果,m保存商的位数
233     char t;
234 
235     result->minus = num1->minus * num2->minus;
236     residue->num = (char*)malloc(sizeof(char) * (num2->digit + 1));//分配余数空间
237     residue->digit = num2->digit + 1;
238     for (i = 0; i < residue->digit; i++)    residue->num[i] = 0;//将余数清零
239     m = 0;
240     for (i = num1->digit - 1; i >= 0; i--) {
241         for (j = residue->digit - 1; j > 0; j--) residue->num[j] = residue->num[j - 1];//移余数 (有问题,等会试一下)
242         residue->num[0] = num1->num[i];
243         bigIntTrim(residue);//整理余数
244         k = 0;
245         while (bigIntEqual(residue, num2) >= 0) {
246             bigIntSub1(residue, num2, residue);
247             k++;
248         }
249         result->num[m++] = k;
250 
251     }
252 
253     result->digit = m;
254     for (i = 0; i < m / 2; i++) {
255         t = result->num[i];
256         result->num[i] = result->num[m - 1 - i];
257         result->num[m - 1 - i] = t;
258     }
259 
260     bigIntTrim(result);
261     bigIntTrim(residue);
262 }