C语言实现大整数乘法

C语言实现大整数乘法转载自:点击打开链接乘法规律,一个数的第i位和另一个数的第j位相乘,一定会累加到结果的第i+j位,结果的数组一个数组元素存2位数,最后对结果处理进位,最后打印出来方法一见上面链接https://www.cnblogs.com/king-ding/p/bigIntegerMul.html方法二voidIntMultiply(inta[],intb[],intc[],intma,in…

大家好,又见面了,我是你们的朋友全栈君。

转载自:点击打开链接

乘法规律,一个数的第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,步骤如下

C语言实现大整数乘法

由上面可以看出,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] = {'
#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,就判断为0
printf("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为0
result = (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完整代码
'}, num2[100] = {'
#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,就判断为0
printf("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为0
result = (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完整代码
'}; 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,就判断为0 printf("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为0 result = (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完整代码

程序运行结果:

C语言实现大整数乘法

总结:

这是一道非常经典而且必须要掌握的题目,所以看到这篇文章的你最好能认真理解一下。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/137287.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 台式机插入网线无网络问题

    台式机插入网线无网络问题1、先查看是否是ip地址无法获取:先找到“以太网”-“详细信息”像这样,就是表示无法正确获取ip地址及网关,接下来,就是手动配置ip及网关等参数这回还是点击“以太网”,点击属性点击协议版本4,点击属性,然后手动输入ip地址等参数即可。…

  • python数据分析源码_python 统计分析

    python数据分析源码_python 统计分析以后都在github更新,请参考CpythonInternals版本第一步克隆Cpython仓库到本地,切换到我当前的版本,我当前的版本号是3.8.0a0gitclonehttps://github.com/python/cpython.gitgitreset–hardab54b9a130c88f708077c2ef6c4963b632c132b…

  • java集合系列——Set之HashSet和TreeSet介绍(十)

    Set是一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2) 的元素。对 e1 和 e2,并且最多包含一个为 null 的元素。

  • Linux下忽略信号SIGPIPE的方法[通俗易懂]

    Linux下忽略信号SIGPIPE的方法[通俗易懂]为了客户端进程收到SIGPIPE不退出,我打算忽略该信号,下面是我用过的方法:(1)间接忽略staticvoidSignalHandler(intnSigno){signal(nSigno,SignalHandler);switch(nSigno){caseSIGPIPE:printf(“Processwillnote…

  • 黑苹果 MacOS 10.15 Catalina 安装详细教程带工具资料「建议收藏」

    黑苹果 MacOS 10.15 Catalina 安装详细教程带工具资料「建议收藏」图文教程悦享地址:点击打开链接视频教程B站地址:点击打开链接​一、准备工作  一个8G以上的U盘(有的U盘标的是8G,实际只有X,实际容量小于7.5G的会失败)  MacOS镜像、TransMac(刻录工具)、DiskGenius(分区工具)、EasyUEFI(引导工区)、EFI驱动文件。    二、制作启动U盘  1、将您的U盘插入电脑,为保证成功,首先将U盘以默认值格…

  • Centos7安装mysql+keepalived 高可用环境[通俗易懂]

    Centos7安装mysql+keepalived 高可用环境[通俗易懂]一、环境准备1.节点信息节点IP 节点名称 系统 软件及版本 192.168.51.187 node187 CentOS7 keepalived-1.3.5 mysql-5.7.24 192.168.51.226 node226 CentOS7 2.虚拟VIP虚拟VIP 192.168.51.170 3.初始化,在两个节点上进行常用工具的安装yuminstallgccgcc…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号