转载自:点击打开链接
乘法规律,一个数的第i位和另一个数的第j位相乘,一定会累加到结果的第i+j位,结果的数组一个数组元素存2位数,最后对结果处理进位,最后打印出来
方法一见上面链接https://www.cnblogs.com/king-ding/p/bigIntegerMul.html
方法二
void IntMultiply(int a[], int b[], int c[], int ma, int nb) {int i, j;memset(c, 0, (ma + nb)*sizeof(c[0]));for(i = 0; i < ma; ++i) {for(j = 0; j < nb; ++j) {c[i + j + 1] = c[i + j + 1] + a[i] * b[j];//printf("%d ",c[i + j + 1]);}//printf("\n");}for(i = ma + nb - 1; i > 0 ; --i) {if(c[i] > 9) {c[i - 1] = c[i - 1] + c[i] / 10;c[i] = c[i] % 10;}}
}
思路:
简单来说,方法二就是先不算任何的进位,也就是说,将每一位相乘,相加的结果保存到同一个位置,到最后才计算进位。
例如:result[200]用来保存结果,计算98×21,步骤如下

由上面可以看出,result的数据为result[100] = {0, 18, 27, 9}
接下来就处理进位,注意看,巧妙的地方来了:
有result末尾到首位计算:
第一次:result[3] = 9; result[2] = 27;
A.先将result[3]除个位以外的数加给前一位,也就是result[2]:result[2] = result[2]+result[3]/10 = 27 + [9/10]=27; 注:数学里面的[]为取整符。如[0.9] = 0
B.然后把result[3]的个位保存到result[3]:
>> result[3] = result[3]%10 = 9;
第二次,向前一位,result[2] = 27, result[1] = 18;
重复第一次的A、B步骤,求得result[1] = result[1]+result[2] / 10=18+[27/10] = 20;
>> result[2] = result[2] % 10 = 7
第三次,再向前一位,result[1] = 20, result[0] = 0
重复之前的步骤,
>> result[0] = result[0]+result[1]/10=0+[20]/10=2
>> result[1] = result[1] % 10 = 0;
至此,已经算到首位,result此时的结果为:result[100] = {2, 0, 7, 9}可以知道这就是结果:99×21=2079;
核心代码:
先是不进位的各位之和:
for(j = 0; j < num2Len; j++)
{for(i = 0; i < num1Len; i++){/* result第一位是用来保存result长度的,而第二位是保存结果最后的进位的* 没有进位,则result[1]为0,所以每位相乘之和是从第三位(即result[2])* 开始。这里是本程序的比较巧妙的地方,需要仔细想想。* */result[i+j+2] += Int(num1[i]) * Int(num2[j]);}
}
接下来是处理进位的代码:
/* 这个循环用来处理进位的,所以要从result的最后一位一直处理到首位。* 要注意result的总长度是resultLen+1,有一位是保存result的长度,而* C语言下标是从0开始,所以result的最后一位的下标就是resultLen,而* 第一位就是1。*/
for(i = resultLen; i > 1; i--)
{result[i-1] += result[i]/10;result[i] = result[i]%10;
}
注意:这个方法有一个大坑,就是保存结果的result的数据类型必须至少是int,而不能是char,为什么呢?先想想再打开答案。
#include<stdio.h>
#include<string.h>
#include<malloc.h>#define and && /**************/
#define or || /* python风格 */
#define not ! /* */
#define Int(X) (X - '0') /**************/int *multiBigInteger(const char *, const char *);
int checkNum(const char *);int main(void)
{char num1[100] = {'\0'}, num2[100] = {'\0'};printf("Please input two nunber(less than 100 digits):\n> ");while(scanf("%s%s", num1, num2) != EOF){int *result = NULL;int i, change = 0;//对输入的数据进行检验if(strlen(num1) > 100 or strlen(num2) > 100){printf("per number must less than 100 digits\n");return 1;}if(checkNum(num1) or checkNum(num2)){printf("ERROR: input must be an Integer\n");return 1;}printf("num1:\t%s\nnum2:\t%s\n", num1, num2);result = multiBigInteger(num1, num2);/* 输出结果result,result[0]保存着result的长度,* 所以下标要从1开始 */printf("result:\t");for(i = 1; i <= result[0]; i++){if(result[i] != 0) //这一步用来去掉前导0,第一位为0跳过不输出change = 1;if(not change){if(i > 1) //这一步用来判断结果是否为0,{ //如果结果第二位还是0,就判断为0printf("0");break;}continue;}printf("%d", result[i]);}printf("\n");printf("\nPlease input two nunber(less than 100 digits):\n> ");}return 0;
} //用于检测输入的是否是数字,如果是就返回0,不是就返回1
int checkNum(const char *num)
{int i;for(i = 0; (size_t)i < strlen(num); i++){if(num[i] < '0' or num[i] > '9'){return 1;}}return 0;
}//返回结果result,为一片内存块,类似数组
int *multiBigInteger(const char *num1, const char *num2)
{int *result = NULL; //用来保存最终结果int num1Len = strlen(num1); //num1的长度int num2Len = strlen(num2); //num2的长度int resultLen; //结果的最大长度int i, j; //循环计数器resultLen = num1Len + num2Len; //结果长度最大为num1长度和num2长度之和//初始化result为0result = (int *)malloc((resultLen+1)*sizeof(int));memset(result, 0, (resultLen+1)*sizeof(int));result[0] = resultLen; //result的第一位是用来保存result的长度的。/* num1乘以num2,由于这里采用先不进位的算法,所以算法是按从左到右* 按顺序来乘,然后将每位的结果保存到result的每一位中,循环一次* reult就从下一位开始求和。如下:(左边为正常算法,右边为本程序算法)** 54321 | 54321* × 123 | × 123* ------- | --------* 162963 | 54321* 108642 | 108642* 54321 | 162963* -------- | ---------* 6681483 | 6681483** */for(j = 0; j < num2Len; j++){for(i = 0; i < num1Len; i++){/* result第一位是用来保存result长度的,而第二位是保存结果最后的进位的* 没有进位,则result[1]为0,所以每位相乘之和是从第三位(即result[2])* 开始。这里是本程序的比较巧妙的地方,需要仔细想想。* */result[i+j+2] += Int(num1[i]) * Int(num2[j]);}}/* 这个循环用来处理进位的,所以要从result的最后一位一直处理到首位。* 要注意result的总长度是resultLen+1,有一位是保存result的长度,而* C语言下标是从0开始,所以result的最后一位的下标就是resultLen,而* 第一位就是1。*/for(i = resultLen; i > 1; i--){result[i-1] += result[i]/10;result[i] = result[i]%10;}printf("num1Len:%d\nnum2Len:%d\n", num1Len, num2Len);return result;
}大整数相乘2完整代码
程序运行结果:
总结:
这是一道非常经典而且必须要掌握的题目,所以看到这篇文章的你最好能认真理解一下。