700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 循环相乘取整法C语言 华为OJ机试题目:两个大整数相乘(纯C语言实现两个大整数相乘

循环相乘取整法C语言 华为OJ机试题目:两个大整数相乘(纯C语言实现两个大整数相乘

时间:2023-02-11 07:36:15

相关推荐

循环相乘取整法C语言 华为OJ机试题目:两个大整数相乘(纯C语言实现两个大整数相乘

题目描述:

输出两个不超过100位的大整数的乘积。

输入:

输入两个大整数,如1234567 123

输出:

输出乘积,如:151851741

样例输入:

1234567 123

样例输出:

151851741

注意:在oj上不能直接套用我的代码,需要将无关的输出去除才行

方法一

思路:

解这道题目最简单的方法就是模拟我们笔算乘法的过程,如:1234×123

只要把这个过程实现,无论多大的数我们都能解决了,是不是很简单。

程序实现:

首先,我们用两个字符串来保存我们的大整数,num1[100], num2[100]

scanf("%s%s", num1, num2);

然后,求num2的每一位与num1的乘积,保存到tempRes中。

过程为:res保存每位相乘的结果,carry用来保存进位,每位相乘之后还要加上进位才是真的结果。将res的个位保存到tempRes中,其他位则为下一位相乘的进位。

for(j = num2Len - ; j >= ; j--)

{

/*计算num1与num2各位相乘的结果,保存到tempRes中

*每一位相乘后与之前的进位相加得出res,将res的个

*位(res%10)保存到tempRes里,然后将res的其余位数

*(res/10)则为进位carry*/

for(i = num1Len-; i >= ; i--)

{

res = Int(num1[i]) * Int(num2[j]) + carry;

tempRes[tempResLen--] = Char(res % );

carry = res / ;

}

//tempRes第一位为进位,刚刚的循环是没有算的,最后把进位算上

tempRes[tempResLen] = Char(carry);

tempResLen = num1Len;

carry = ;

}

再然后,将tempRes与result求和,每求一次,向左偏移一位。res为每位之和再加上进位,这里很重要,然后保存到result里只是res的个位,res为下一位计算的进位。

//由result的末尾开始计算和,算完一次,向左偏移一位

for(k = resultLen-offset; k > (resultLen-offset-num1Len); k--)

{

res = Int(result[k]) + Int(tempRes[tempResLen--]) + carry;

result[k] = Char(res%);

carry = res/;

}

result[k] += Int(tempRes[tempResLen] + carry);

offset++;

以上两步就是我程序最核心的部分。以下是程序的全部代码。

#include

#include

#include

#define and &&

#define or ||

#define not !

#define Int(X) (X - '0')

#define Char(X) (X + '0')

char *multiBigInteger(const char *, const char *);

int checkNum(const char *);

int main(void)

{

char num1[] = {'\0'}, num2[] = {'\0'};

while(scanf("%s%s", num1, num2) != EOF)

{

char *result = "";

if(strlen(num1) > or strlen(num2) > )

{

printf("ERROR\n");

return ;

}

if(checkNum(num1) or checkNum(num2))

{

printf("ERROR: input must be an Integer\n");

return ;

}

printf("num1:\t%s\nnum2:\t%s\n", num1, num2);

result = multiBigInteger(num1, num2);

if(result[] == '')

{

int i;

printf("result:\t");

for(i = ; (size_t)i < strlen(result); i++)

{

printf("%c", result[i]);

}

printf("\n");

}

else

{

printf("result:\t%s\n", result);

}

printf("\n");

}

return ;

}

int checkNum(const char *num)

{

int i;

for(i = ; (size_t)i < strlen(num); i++)

{

if(num[i] < '' or num[i] > '')

{

return ;

}

}

return ;

}

char *multiBigInteger(const char *num1, const char *num2)

{

char *tempRes = NULL; //用来保存每次相乘的结果

char *result = NULL; //用来保存最终结果

int tempResLen; //每次相乘结果的最大长度

int num1Len = strlen(num1); //num1的长度

int num2Len = strlen(num2); //num2的长度

int resultLen; //结果的最大长度

int i, j, k; //循环计数器

int res; //每次一位相乘/相加的结果

int carry = ; //进位

int offset = ; //加法的偏移位

resultLen = num1Len + num2Len - ; //结果长度最大为num1长度和num2长度之和,由于下标从0开始,所以要减一

tempResLen = num1Len; //每次num1乘以num2每一位的结果最大长度是num1Len+1,由于下标从0开始,所以减一后约去1,只剩num1Len

//初始化result为0

result = (char *)malloc((resultLen+)*sizeof(char));

memset(result, '', (resultLen+)*sizeof(char));

result[resultLen+] = ;

tempRes = (char *)malloc((tempResLen+)*sizeof(char));

for(j = num2Len - ; j >= ; j--)

{

//初始化tempRes每位为0

memset(tempRes, '', (tempResLen+)*sizeof(char));

/*计算num1与num2各位相乘的结果,保存到tempRes中

*每一位相乘后与之前的进位相加得出res,将res的个

*位(res%10)保存到tempRes里,然后将res的其余位数

*(res/10)则为进位carry*/

for(i = num1Len-; i >= ; i--)

{

res = Int(num1[i]) * Int(num2[j]) + carry;

tempRes[tempResLen--] = Char(res % );

carry = res / ;

}

//tempRes第一位为进位,刚刚的循环是没有算的,最后把进位算上

tempRes[tempResLen] = Char(carry);

tempResLen = num1Len;

carry = ;

//由result的末尾开始计算和,算完一次,向左偏移一位

for(k = resultLen-offset; k > (resultLen-offset-num1Len); k--)

{

res = Int(result[k]) + Int(tempRes[tempResLen--]) + carry;

result[k] = Char(res%);

carry = res/;

}

result[k] += Int(tempRes[tempResLen] + carry);

carry = ;

tempResLen = num1Len;

offset++;

}

printf("num1Len:%d\nnum2Len:%d\n", num1Len, num2Len);

return result;

}

大整数相乘完整代码

以下是程序执行的结果:

看了以上的代码,感觉思路虽然很简单,但是实现起来却很麻烦,那么我们有没有别的方法来实现这个程序呢?答案是有的,接下来我来介绍第二种方法。

方法二:

思路:

简单来说,方法二就是先不算任何的进位,也就是说,将每一位相乘,相加的结果保存到同一个位置,到最后才计算进位。

例如: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 = ; j < num2Len; j++)

{

for(i = ; i < num1Len; i++)

{

/* result第一位是用来保存result长度的,而第二位是保存结果最后的进位的

* 没有进位,则result[1]为0,所以每位相乘之和是从第三位(即result[2])

* 开始。这里是本程序的比较巧妙的地方,需要仔细想想。

* */

result[i+j+] += Int(num1[i]) * Int(num2[j]);

}

}

接下来是处理进位的代码:

/* 这个循环用来处理进位的,所以要从result的最后一位一直处理到首位。

* 要注意result的总长度是resultLen+1,有一位是保存result的长度,而

* C语言下标是从0开始,所以result的最后一位的下标就是resultLen,而

* 第一位就是1。*/

for(i = resultLen; i > ; i--)

{

result[i-] += result[i]/;

result[i] = result[i]%;

}

注意:这个方法有一个大坑,就是保存结果的result的数据类型必须至少是int,而不能是char,为什么呢?先想想再打开答案。

/* 因为char类型的数据每个只有1个字节

* 也就是8位,所以保存的最大数值为256

* 而我们这个程序,每位最大为100个9×9=81

* 之和,也就是每个数据必须最大要能保存的数

* 值为8100, 所以char数据类型就不够保存了。

* good luck :-)*/

答案

接下来程序的完整代码:

#include

#include

#include

#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[] = {'\0'}, num2[] = {'\0'};

printf("Please input two nunber(less than 100 digits):\n> ");

while(scanf("%s%s", num1, num2) != EOF)

{

int *result = NULL;

int i, change = ;

//对输入的数据进行检验

if(strlen(num1) > or strlen(num2) > )

{

printf("per number must less than 100 digits\n");

return ;

}

if(checkNum(num1) or checkNum(num2))

{

printf("ERROR: input must be an Integer\n");

return ;

}

printf("num1:\t%s\nnum2:\t%s\n", num1, num2);

result = multiBigInteger(num1, num2);

/* 输出结果result,result[0]保存着result的长度,

* 所以下标要从1开始 */

printf("result:\t");

for(i = ; i <= result[]; i++)

{

if(result[i] != ) //这一步用来去掉前导0,第一位为0跳过不输出

change = ;

if(not change)

{

if(i > ) //这一步用来判断结果是否为0,

{ //如果结果第二位还是0,就判断为0

printf("");

break;

}

continue;

}

printf("%d", result[i]);

}

printf("\n");

printf("\nPlease input two nunber(less than 100 digits):\n> ");

}

return ;

}

//用于检测输入的是否是数字,如果是就返回0,不是就返回1

int checkNum(const char *num)

{

int i;

for(i = ; (size_t)i < strlen(num); i++)

{

if(num[i] < '' or num[i] > '')

{

return ;

}

}

return ;

}

//返回结果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+)*sizeof(int));

memset(result, , (resultLen+)*sizeof(int));

result[] = resultLen; //result的第一位是用来保存result的长度的。

/* num1乘以num2,由于这里采用先不进位的算法,所以算法是按从左到右

* 按顺序来乘,然后将每位的结果保存到result的每一位中,循环一次

* reult就从下一位开始求和。如下:(左边为正常算法,右边为本程序算法)

*

* 54321 | 54321

* × 123 | × 123

* ------- | --------

* 162963 | 54321

* 108642 | 108642

* 54321 | 162963

* -------- | ---------

* 6681483 | 6681483

*

* */

for(j = ; j < num2Len; j++)

{

for(i = ; i < num1Len; i++)

{

/* result第一位是用来保存result长度的,而第二位是保存结果最后的进位的

* 没有进位,则result[1]为0,所以每位相乘之和是从第三位(即result[2])

* 开始。这里是本程序的比较巧妙的地方,需要仔细想想。

* */

result[i+j+] += Int(num1[i]) * Int(num2[j]);

}

}

/* 这个循环用来处理进位的,所以要从result的最后一位一直处理到首位。

* 要注意result的总长度是resultLen+1,有一位是保存result的长度,而

* C语言下标是从0开始,所以result的最后一位的下标就是resultLen,而

* 第一位就是1。*/

for(i = resultLen; i > ; i--)

{

result[i-] += result[i]/;

result[i] = result[i]%;

}

printf("num1Len:%d\nnum2Len:%d\n", num1Len, num2Len);

return result;

}

大整数相乘2完整代码

程序运行结果:

总结:

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

作者:陈栋权

时间:/09/17

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,

且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

最后有兴趣的同学可以关注我的微信公众号,可以随时及时方便看我的文章。*^_^*

扫码关注或者搜索微信号:King_diary

华为OJ机试训练(一)

题目1 -- 通过输入英文句子.将每一个单词反过来,标点符号顺序不变.非26个字母且非标点符号的情况就可以标识单词结束. 标点符号包含,.!? 比如输入:Hello, I need an apple. ...

华为 机试 输出:数字后面的连续出现的(2个或多个)相同字符(数字或者字符),删去一个,非数字后面的不要删除,例如,对应输出为:33aabb55pin。

package 华为机试; //C++ 输入:由数字和字母组成的字符串,例如:333aaabb55ppin //输出:数字后面的连续出现的(2个或多个)相同字符(数字或者字符),删去一个,非数字后面的 ...

华为JAVA机试流程

1.JAVA机试流程:①打开IE浏览器,输入机试系统IP地址(以当天告知的地址为准):②输入姓名.手机,选择“C/C++”或“JAVA”,登录:③登录后显示题目,阅读题目并点击页面最下方的“下载框架文 ...

Hua Wei 机试题目三---

一.根据对应规则进行翻译输出 描述:已知有如下的对应规则: ,则输入任意个正整数,输出经过规则翻译以后对应的结果. 例如:输入:1234:输出bcde. 题目很简单,我觉得需要注意的问题就是对于大整数 ...

九度oj 题目1083:特殊乘法 清华大学机试题目

题目描述: 写个算法,对2个小于1000000000的输入,求结果. 特殊乘法举例:123 * 45 = 1*4 +1*5 +2*4 +2*5 +3*4+3*5 输入: 两个小于1000000000的 ...

九度oj 题目1085:求root&lpar;N&comma; k&rpar; 清华机试题目

题目描述: N

9月5日 华为校园招聘的机试题目&lowbar;C语言版答案

手有些生了. 题目: 通过键盘输入一串小写字母(a~z)组成的字符串.请编写一个字符串压缩程序,将字符串中连续出席的重复字母进行压缩,并输出压缩后的字符串.压缩规则:1.仅压缩连续重复出现的字符.比如 ...

一道来自华为的C机试题目

题目是这样的 求一个字符串中连续字母的个数 比如I have a book. : 1 I have a dog. : 0 I haavee aa dogg : 4 #include

华为西安java机试题目:如何过滤掉数组中的非法字符。

这道题目为记忆版本: 题目2描述: 编写一个算法,过滤掉数组中的非法字符,最终只剩下正式字符. 示例:输入数组:“!¥@&HuaWei*&%123” 调用函数后的输出结果,数组:“Hu ...

随机推荐

html中submit和button的区别&sol; window&period;location&period;href 不跳转 的问题

这两个的区别 是 button 不会自动提交表 ...

&lbrack;洛谷OJ&rsqb; P1114 &OpenCurlyDoubleQuote;非常男女”计划

洛谷1114 “非常男女”计划 本题地址:/problem/show?pid=1114 题目描述 近来,初一年的XXX小朋友致力于研究班上同学的配对问题(别想太 ...

Java 入门 代码2浮点数据类型

/** * 基本数据类型之浮点类型 */ public class DataTypeDemo2 { public static void main(String[] args) { double d1 ...

HTTPS-能否避免流量劫持

流量劫持是什么? EtherDream在一篇科普文章<>中详细介绍了流量劫持途径和方式. 流量劫持是一种古老的攻击方式,比如早已见惯的广告弹窗等,很多人已经对此麻木,并认为流量劫持不会造成 ...

使用Kinect2&period;0获取点云以在GLUT中显示

这篇文章用来记录Kinect2.0如何生成点云. 以下示例源自Kinect提供的example修改完成,其名称会在小标题下方注解. 首先,要获取点云需要获取图像的深度数据和颜色数据.最后再将深度数据与 ...

PHP请求页面

< ?php $file_contents = file_get_contents('/'); echo $file_contents; ?> 有 ...

Java8新特性 1——利用流和Lambda表达式操作集合

Java8中可以用简洁的代码来操作集合,比如List,Map,他们的实现ArrayList.以此来实现Java8的充分利用CPU的目标. 流和Lambda表达式都是Java8中的新特性.流可以实现对集 ...

SDUT 最短路径(二维SPFA)

http://acm./sdutoj/problem.php?action=showproblem&problemid=2622 #include

家居环境监測系统设计(PC上位机版)(手机APP版待定)

下面是我的毕业设计:家居环境监測系统设计(PC上位机临时版.手机app版待定).本系统採用STC12C5A60S2单片机.结合传感器.分别对空气湿度.空气温度.气压.海拔.进水温度.出水温度.光照强度 ...

解析PHP程序员需要掌握的必备技能

转自:/html/php/lei//0904/4199.html 作为PHP的爱好者,如果你想加入PHP程序的世界,一定要做好充分的准备.建议大家阅读 ...

循环相乘取整法C语言 华为OJ机试题目:两个大整数相乘(纯C语言实现两个大整数相乘 两种方法实现大数相乘)...

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。