zoukankan      html  css  js  c++  java
  • c语言 大数加法、阶乘和乘法

    一.大数加法

    定义两个足够大的数字,其数值远超过long的取值范围,设该大数的位数有两百位,求其相加所得

    大数加法的核心思想详见此链接,内有详细的动画演示,这里不再赘述

    大数加法、大数阶乘

    直接上代码:

    #include<string.h>
    #include<stdio.h>
    #define N 10//定义当前一个足够大的数字为10位,可任意更改
    void print_num(int a[],int n)
    {
        int i=n-1;//从逆序数组的最后一项开始查找,进行反逆序
        while(a[i]==0)//由于规定的数组比真实计算的数字大,所以数组最后几位必定存在0的情况
            --i;//这种情况下一定要将0舍去,否则会抬高数组的位数
        for(;i>=0;i--)//找到非零的数组,进行反逆序输出
            printf("%d",a[i]);
    }
    void plus(int num1[],int num2[],int n)
    {//尤其注意!由于数组是逆序的,所以num[0]是个位,num[1]是十位,num[2]是百位
        for(int i=0,up=0;i<n;i++)//算法参考小学加法,这里定义一个up进位标记
        {
            int temp=num1[i]+num2[i]+up;//up最开始设为0,因为在个位无法获取进位
            num1[i]=temp%10;//若产生进位行为,则选取个位部分赋给num1
            up=temp/10;//在个位上,若个位相加产生进位,则用temp/10取整加到下一次的十位上
        }
        print_num(num1, n);
    }
    int main(){
        char buffer1[]="123456";//缓冲数组,将当前数组倒序写入num1中
        char buffer2[]="78951234";//同上,写入num2中
        int num1[N]={0};//将num1,2全部置为0,用来将缓冲数组写入到num数组当中
        int num2[N]={0};
        int n=N;//定义上述两个数组的长度为10
        for(int i=0,temp=(int)strlen(buffer1)-1;temp>=0;temp--)
            num1[i++]=buffer1[temp]-'0';//用倒序的方式将缓冲数组写入num中,意味着num的第一位是个位,第二位是十位,三是百位...
        for(int i=0,temp=(int)strlen(buffer2)-1;temp>=0;temp--)
            num2[i++]=buffer2[temp]-'0';
        
        plus(num1, num2, n);//将两数字相加
        printf("
    ");
    }

    二.大数阶乘

    大数阶乘的中心思想参考上述视频和一篇博客,博客详情:大数阶乘运算

    但是,这里需要说明一个点:

    1*2=2,将2存到a[0]中,

    接下来是用a[0]*3;

        2*3=6,将6储存在a[0]中,

    接下来是用a[0]*4;

        6*4=24,是两位数,那么24%10==4存到a[0]中,24/10==2存到a[1]中,

    接下来是用a[0]*5;a[1]*5+num(如果前一位相乘结果位数是两位数,那么num就等于十位上的那个数字;如果是一位数,num==0)

        24*5=120,是三位数,那么120%10==0存到a[0]中,120/10%10==2存到a[1]中,120/100==1存到a[2]中

    由于上述博客存在某些地方没有说清楚的情况,这里解释一下

    关于上述博客的Q&A:

    1.这里的num指的是什么?

    答:这里的num指的是前面两数值相乘后进位数位多少:例如6*4得24,这里的num值的是24/10=2,进位数为2,num=2

    2.下面代码为什么要充i=2开始?

    答:如果这里看懂了代码其实理解2不是很难,但是没有看懂是真的难懂:

    首先明确一点:5的阶乘是1*2*3*4*5,我定义的value数组的第一位为1,而我的i是从2起的,这样以来不就直接凑出了1*2了吗?当我的i自增到3,我直接在value数组中找出1*2的值,拿他们去和3相乘,也就凑成了1*2*3了

    3.如何在代码当中表现出进位的思想?

    答:我们以5!为例,当计算到1*2*3*4的时候,value当中的表现形式是42000000,从左到右依次是个位,十位,百位,千位...etc

    (value表示的是24这个数字)

    我们在关于j的循环当中拿i=5去和value数组求乘积:

    5先和位于个位的4求积得20:20%10得0,0放入个位中;20/10得2,进位为2,up=2。(此时个位为0)

    j++后,5再和value中的value[1]=2做乘积并且加上up进制:5*2+2=12,12%10=2放入十位,12%10=1放入up中(此时十位为2)

    j++后,5再和value中百位value[2]=0做乘积同时加上up:5*0+1=1,1%10=1放入百位,1/10=0放入up中(此时百位为1)

    j++,5再和千位做运算,运算结果为0,重复上述循环一直到关于i=5的j循环结束,开始下一轮。

    4.若上述举例子的不再是5而是20呢?最后几项如何处理

    答:假设1*2...19为止其结果==‘56’(纯假设),

    那么最后一项如何处理:56*20?

    首先拿个位6和20相乘得120,120%10得0,0放到个位;120/10得12,up=12;(个位为0)

    十位5和20相乘+up=112,112&10=2,2放到十位,112/10得11,up=11;(十位为2)

    百位0与20相乘+up=11,11&10=1放到百位,11/10=1,up=1;(百位为1)

    千位0与20相乘+up=1,1&10=1放到千位,1/10=0,up=0;(千位为1)

    下面全都是0了,循环一直持续到value数组的末尾,方法同上一致。

    最后value数组为0211000000

    倒序之后就是1120,即56*20的结果就是1120。

    #define n 13
    int main(){
        int number=11;//定义要求阶乘的数位number
        int value[n]={1};
    //将存放number的阶乘后结果的数组定义为value[]数组
    //根据算法,阶乘的第一项为1,因为阶乘运算中最小的数字为1
        
        for(int up=0,i=2;i<=number;i++)//定义俩变量up和i,up负责进制,i是阶乘当中的数字,i逐渐增大
            for(int j=0;j<n;j++)//我们是拿1*2*3*...,首先拿value[0]=1和2乘
            {
                int temp=value[j]*i+up;
                value[j]=temp%10;
                up=temp/10;
            }
        
        int i=n-1;//value是一个倒序的数组,第一位是个位,所以输出是需要倒置的
        while(value[i]==0)
            --i;
        for(;i>=0;i--)
            printf("%d",value[i]);
        printf("
    ");
    }

    三.大数乘法

    两个数值远大于long long的表示范围的数字相乘,用程序表示出来

    这里我模拟正常运算的对位相乘思想,但是把最后一步相加进位的步骤单独抽出来写出来,用convert_normal函数表示

    具体演示过程参考该视频前几分钟的讲解:高精度乘法

    在传统乘法中需要两数值对位运算,例如357*384:

    当位于个位上的4与7,5,3相乘的时候,其结果必须对应个位,十位,百位

    当位于百位上的8与7,5,3相乘的时候,结果必须要对应十位,百位,千位

    这也是为什么我要在multiply函数中引入k这个变量,k起到对位的作用。

    这个算法当中,将最后一步(即3排数字的相加进位过程抽离出来,当读写成一个convert_normal函数)

    在multiply函数中,result所得的结果直接将这三排数字对位相加,结果为28,76,73,39,9

    接着在normal函数中这些数字全按照上面大数加法的思想转化为正常数字

    #include<string.h>
    #define N 10
    void transition(char buffer[],int num[])//把输入的数组从char类型转为int类型
    {
        for(int i=(int)strlen(buffer)-1,j=0;i>=0;i--)
            num[j++]=buffer[i]-'0';
    }
    void bigdata_multiply(int num1[],int num2[],int after[])//大数乘法运算
    {//函数模拟乘法的过程
        for(int i=0;i<N;i++)//num1
        {
            int k=i;
            for(int j=0;j<N;j++)//num2
                after[k++]+=num1[i]*num2[j];
        }
    }
    void print(int num[])
    {
        int i=N-1;
        while(num[i]==0)
            --i;
        for(;i>=0;i--)
            printf("%d",num[i]);
    }
    void convert_normal(int number[])//转换函数,将result数组中的数值转化为正常数字
    {
        for(int i=0,up=0;i<N;i++)
        {
            int temp=number[i]+up;
            number[i]=temp%10;
            up=temp/10;
        }
    }
    int main(){
        char buffer1[N];//定义一个过渡数组
        char buffer2[N];
        int result[N]={0};//定义计算结果的数组
        int num1[10]={0};//定义第一个数字
        int num2[10]={0};//定义第二个数字
        
        printf("num1=");
        scanf("%s",buffer1);
        printf("num2=");
        scanf("%s",buffer2);
        
        transition(buffer1, num1);//将num1,2数组逆置转换为int数组
        transition(buffer2,num2);
        
        bigdata_multiply(num1,num2,result);
        convert_normal(result);
        print(result);
        printf("
    ");
    }
  • 相关阅读:
    关于机器人流量对抗的一点感想
    保卫"木叶",从火影剧情看网站攻防的演变
    自动化工具层级图
    对抗恶意机器人/自动化行为的新思路与方案
    C++ 数组、链表和二叉树的比较
    #ifndef和#define区别
    xavier上安装teamviewer
    Ubuntu16.04 下有关conda虚拟环境的一些使用方法
    vector中push_back和emplace_back的区别
    int、int16、int32、int64、float、float16、float32、float64
  • 原文地址:https://www.cnblogs.com/oldfish123/p/13557317.html
Copyright © 2011-2022 走看看