C语言大数运算-乘除法篇「建议收藏」

C语言大数运算-乘除法篇「建议收藏」前言:这是第三篇博客,也是一次介绍二个计算的博客,可能难度会比前两篇博客大一点,所以建议对于初学者来说一定要看完我的前两篇博客再来看本篇博客,关于本次实验的环境,和思想在第一篇博客已经简单介绍过了,所以不再赘述,我会先介绍大数的乘法载介绍大数的除法,乘法的难点在于要使用一个嵌套循环,除法的难点在于一个字使用符串比较方法的技巧,本次还是会将算法都写成函数,然后在main()函数中调用,原因是在第四

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

前言:
这是第三篇博客,也是一次介绍二个计算的博客,可能难度会比前两篇博客大一点,所以建议对于初学者来说一定要看完我的前两篇博客再来看本篇博客,关于本次实验的环境,和思想在第一篇博客已经简单介绍过了,所以不再赘述,我会先介绍大数的乘法载介绍大数的除法,乘法的难点在于要使用一个嵌套循环,除法的难点在于一个字使用符串比较方法的技巧,本次还是会将算法都写成函数,然后在main()函数中调用,原因是在第四篇我们要将整个大数运算的方法做成自己的一个库文件,可以供自己或他人使用。

大数乘法:
由于乘法可以互换所以对于输入的数字没有限制条件,计算方法还是模仿手工算法,由被乘数的低位开始和乘数的每一位相乘并且要将大于9的十位数向前进一位,存在3个问题需要我们解决。

问题:
1 我们要用多大的数组存储结果?
2 要使用嵌套循环吗?
3 如何在计算的过程中保证进位?

其实问题也很好解决,前两个问题都可以看出答案,最后一个问题和前两篇博客的进位问题很相似,所以简单的说明后再看注释的代码是很好懂的。
1 二个数相乘最大的位数是两个乘数的位数之和。
2 很明显由于乘法的特性使用嵌套循环很合适。
3 在大数加减中执行完毕后再对存储结果的result数组进行一次进位,但在乘法中我们需要每执行一趟就要对数组进行进位的处理。

实现:
下面是全面的含有注释的代码。

  1 //#include"big.h"
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include<string.h>
  5 char * bigmul(char *m,int lena,char *f,int lenb){  //乘法运算函数。
  6    int i,j,k,lensum,tmp_result,carry,num='0';
  7    lensum=lena+lenb;                               //确定结果数组的长度。
  8    for(i=0;i<lena;i++){                            //将ASCII码转为对应的数字存储。
  9       m[i]=m[i]-num;
 10    }
 11    for(i=0;i<lenb;i++){
 12       f[i]=f[i]-num;
 13    }
 14    char *result,final[BUFSIZ];
 15    result=(char*)calloc(lensum,1);
 16    for(i=0;i<lenb;i++){                      //为被乘数作一趟乘法。
 17       for(j=0;j<lena;j++){
 18          tmp_result=f[lenb-i-1]*m[lena-j-1];
 19          result[j+i]+=tmp_result;
 20       }
 21       for(k=0;k<=j+i-1;k++){                 //每作一趟乘法整理一次结果数组。
 22          if(result[k]>9){
 23             carry=result[k]/10;
 24             result[k]=result[k]%10;
 25             result[k+1] += carry;
 26          }
 27       }
 28    }
 29    j=0;
 30    if(result[lensum-1]!=0){                  //去除前导零将结果整理到final数组中。
 31       final[j]=result[lensum-1]+num;
 32       j++;
 33    }
 34    for(i=lensum-2;i>=0;i--){
 35       final[j++]=result[i]+num;
 36    }
 37    result=final;                             //将指针指向final数组并返回该指针。 
 38    return result;
 39 }
 40 int main(){                                                 //利用main测试方法,用puts打印结果。 
 41    int lena,lenb;
 42    char *result,sa[BUFSIZ],sb[BUFSIZ];
 43    scanf("%s",sa);
 44    scanf("%s",sb);
 45    lena=strlen(sa);
 46    lenb=strlen(sb);
 47    result=bigmul(sa,lena,sb,lenb);
 48    puts(result);
 49 
 50 }

下面是大数除法。

前言:
大数除法的难点在于思考算法,可以用连续的减法来实现,举个简单了例子:32/2可以用32连续减去2每减一次i加一,当差小于被减数时停止。i即为商,由于我们前面实现了大数减法所以用该方法可以实现,但是有一个问题就是如果用一亿除以一那么就需要执行一亿次,况且我们做的是大数数算,输入100位以上的数也都是有可能的,那么计算的时间就是几天,几年,几万年都有可能。所以只有模仿手工的方法,从高位开始计算。32/2从高位先用3-2只能减1次,将余数保留变成12/2,可以减6次,从而得到结果16极大的降低了循环减的次数。

大数除法:
有很多问题大多都是的我们前面遇到的问题,例如结果数组的位数,对数组的整理进位问题,嵌套循环和乘法相同按趟执行,既然是相似的问题我就不再说了。

注意:
除法对数据有限制不能分母为零,分母为零没有意义,不能用小数除以大数,因为小数除以大数本质还是大数除以小数结果加个分之一就可以了。
返回的结果是保存商的数组的指针,不包含余数。

实现:
下面是完整的含有注释的代码,如果想判断输入,或输入余数,可自行修改代码。

  1 //#include"big.h"
  2 #include<stdio.h>
  3 #include<string.h>
  4 char diva[BUFSIZ],divb[BUFSIZ];
  5 char result_tmp[BUFSIZ];
  6 char final[BUFSIZ];
  7 char * bigdiv(char *diva,int lena,char *divb,int lenb){        //大数除法函数。
  8     int i,j,k;
  9     char  * result;
 10 /* if((lena<lenb||lena==lenb)&&strcmp(diva,divb)<0){ //去除了以小除大的判断 11 printf("0 余数=");//求余数 12 for(i=0; i<lena; i++) 13 printf("%d",diva[i]-'0'); 14 printf("\n"); 15 return result; 16 } 17 */
 18             k=0;
 19             while(1){                        //死循环只有当lena和lenb相等时跳出循环,因为会不断的在divb数组前加0所以该数组的长度,
 20                                              //会不断的变化当两者相等时说明已经无法在作减法。
 21                 result_tmp[k]=0;
 22                 while(strcmp(diva,divb)>=0){ //用字符串比较的方法是一个亮点,很巧妙。因为strcmp()比较的方式是从前到后依次比较 
 23                  int i=0,j;                  //如果相等则向后移动一位一旦发现不等则立即返回忽略后面的所有数据。
 24                      while(1){
 25                         if(diva[i]=='0') i++;//去除diva高位前面的0
 26                         else{
 27                            j=i;              //去除divb高位填充的0
 28                          break;  
 29                         }  
 30                }
 31     
 32                for(; i<lenb; i++)            //作减法
 33                diva[i]=diva[i]-divb[i]+'0';
 34                for(i=lenb-1; i>j; i--)       //每作一组减法就整理数组,这种整理数组在前几篇中都有使用。
 35                if(diva[i]<'0'){              //不过在这里不是整理结果数组而是diva数组,结果保存在a数组中不用整理
 36                   diva[i]+=10;;
 37                   diva[i-1]--;
 38                }
 39                     result_tmp[k]++;
 40 
 41                }
 42                   k++;
 43                   if(lena==lenb)   break;
 44                   for(i=lenb-1; i>=0; i--)   //将divb中的元素先后移位,同时扩大divb长度并且在divb前端补一位0。
 45                     divb[i+1]=divb[i];
 46                   divb[0]='0';               //由于数组后移所以divb[0]每次移动后都为空,所以每次用0补齐。
 47                   lenb++;
 48                   divb[lenb]='\0';           //在结尾加上字符串的结束标记。
 49             }
 50             i=0;j=0;
 51             while(result_tmp[i]==0) i++;
 52             for(; i<k; i++){
 53                 final[j++]=result_tmp[i]+'0';
 54 
 55             }
 56             result=final;
 57 /* 58 printf(" 余数="); 59 j=0;//求余数 60 while(diva[j]=='0') j++; 61 if(j==lena) 62 { 63 printf("0\n"); 64 continue; 65 } 66 for(; j<n; j++) 67 printf("%d",diva[j]-'0'); 68 printf("\n"); 69 */
 70 
 71             return result;
 72 
 73 }
 74 int main(){                                                 //利用main测试方法,用puts打印结果。 
 75    int lena,lenb;
 76    char *result,sa[BUFSIZ],sb[BUFSIZ];
 77    scanf("%s",sa);
 78    scanf("%s",sb);
 79    lena=strlen(sa);
 80    lenb=strlen(sb);
 81    result=bigdiv(sa,lena,sb,lenb);
 82    puts(result);
 83 
 84 }

所有的运算到此完结最后一篇做一个大数运算库,有时间我会把库放到github如果以后有时间我会做些优化并且加入对浮点的支持。

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

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/185093.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java常用类之Calendar类[通俗易懂]

    java常用类之Calendar类[通俗易懂]java常用类之Calendar类Calendar类提供了获取或者设置各种日历的字段的方法。构造方法protectedCalendar():由于修饰符是prodected;所以无法直接创建该对象其他方法方法名说明staticCalendargetInstance()使用默认时区或区域获取日历voidset(intyear,intmonth,intdate,inthourofday,intminute,intsecond)设置日历的时分秒

    2025年12月2日
    3
  • Java线程(二):线程同步synchronized和volatile

    Java线程(二):线程同步synchronized和volatile要说明线程同步问题首先要说明Java线程的两个特性,可见性和有序性。多个线程之间是不能直接传递数据交互的,它们之间的交互只能通过共享变量来实现。拿上篇博文中的例子来说明,在多个线程之间共享了Count类的一个对象,这个对象是被创建在主内存(堆内存)中,每个线程都有自己的工作内存(线程栈),工作内存存储了主内存Count对象的一个副本,当线程操作Count对象时,首先从主内存复制Co…

    2022年7月15日
    16
  • Calendar类_java calendar

    Calendar类_java calendarCalendar类简介Calendar是javautil包下的一个工具类,提供了很方便的不同日期格式的处理。啥也不说了,直接撸代码:publicstaticvoidmain(String[]args){System.out.println(“————Calendar无参构造————“);//Cal…

    2022年9月24日
    2
  • 哈佛幸福课笔记中篇

    哈佛幸福课笔记中篇改变一生的课:哈佛幸福课笔记中篇第9课积极情绪第10课如何去改变第11课养成良好习惯第12课写日记第13课面对压力第14课过犹不及第15课完美主义第16课享受过程链接:哈佛大学公开课:幸福课.《哈佛幸福课》是改变我生活最大的一项事物,没有之一。我学习了5遍幸福课,并且用过去6年的时间去尝试它践行它,感觉完全改变了我的生活。第9课积极情绪1.感激练习,每天去做才能养成习惯,那样才能改变思维。每天变化,思考不同的方向去做。爱默生:如果星星每千年闪烁一次,我们都会仰视赞美这个世界的

    2022年7月25日
    7
  • 数据帧的学习整理

    数据帧的学习整理事先声明,本文档所有内容均在本人的学习和理解上整理,不具有权威性,甚至不具有准确性,本人也会在以后的学习中对不合理之处进行修改。在了解数据帧之前,我们得先知道OSI参考模型咱们从下往上数,数据帧在

    2022年8月5日
    4
  • .npy文件_文件后缀名是npy怎么打开

    .npy文件_文件后缀名是npy怎么打开深度学习–迁移学习在使用训练好的模型时,其中有一种保存的模型文件格式叫.npy。打开方式·实现代码:importnumpyasnptest=np.load(‘./bvlc_alexnet.npy’,encoding=”latin1″)#加载文件doc=open(‘1.txt’,’a’)#打开一个存储文件,并依次写入print(test,file=doc)#…

    2025年8月21日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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