专栏中心

EEPW首页 > 专栏 > C语言实现大数运算

C语言实现大数运算

发布人:电子禅石 时间:2019-08-17 来源:工程师 发布文章

由于整型数的位数有限,因此整型数不能满足大整数(超长整数)的运算要求 。大整数计算是利用字符串来表示大整数,即用字符串的一位字符表示大整数的一位数值,然后根据四则运算规则实现大整数的四则运算。

大数的结构

typedef struct bigint

{

    char *num;                //指向长整数数组(序号0中保存着最高位) 

    char sign;               //符号(1表示正数,-1表示负数) 

    int digit;                 //保存该数的位数(实际位数)

}BIGINT, *pBIGINT; 

123456

加法运算

执行加法之前,先判断两数是同号相加还是异号相加,同号则执行加法运算,异号则执行减法运算。在加法运算中,首先将被操作的两个数对齐,然后从低位向高位逐渐相加,在对应位置相加时,要考虑是否有地位相加的进位。

实现代码:

首先将被加数中的内容复制到结果数组中,然后从低位逐渐加到结果中去,最后判断加数各位加完之后是否还有进位,如果有则要累加到高位中去。BigintTirm()用于整理大数,去掉前多余的0,并调整其位数。

void BigIntAdd(pBIGINT num1,pBIGINT num2,pBIGINT result)

{

    int i,carry;

    carry=0;                              //清除进位

    result->sign =num1->sign;           //保存符号

    //将被加数复制到结果数组中

    for(i=0;i<num1->digit;i++)

        result->num[i]=num1->num[i];

    //num2中的数小,可能位数也少些

    for(i=0;i<num2->digit;i++)

    {

        //将对应位的数和进位数相加
        result->num[i]=result->num[i]+num2->num[i]+carry;   
        carry=result->num[i]/10;       //计算进位数据

        result->num[i]=result->num[i]%10;     //保留一位 

    }

    if(carry)                       //若最后还有进位
        result->num[i]=result->num[i]+carry;

    BigIntTrim(result);                //整理结果 

减法运算

减法运算可以看做异号加法,结果的最大位数和较大的减数位数相同,可以把被减数缺少的位数用零补全然后相减,也可以只减到被减数的位数,然后将减数的高位直接写到结果的数组中。
实现代码:
void BigIntSub1(pBIGINT num1,pBIGINT num2,pBIGINT result)    
{
    int i,borrow;
    result->sign =num1->sign;         //结果符号
    borrow=0;
    //将被减数的内容复制到结果中
    for(i=0;i<num1->digit;i++)               
        result->num[i]=num1->num[i];
    for(i=0;i<=num2->digit;i++)
    {
        //num1减去num2,并减去低位的借位
        result->num[i]=result->num[i]-num2->num[i]-borrow;                                          
        if(result ->num[i]<0)             //若为负数
        {
            result->num[i]=10+result->num[i];    //向高位借位
            borrow=1;                   //设置借位数
        }else
            borrow=0;
    }
    if(borrow==1)
        result->num[i]=result->num[i]-borrow;
    i=num1->digit;
    while(i>0)
    {
        if(result->num[i]==0)
            i--;
        else
            break;
    }
    result->digit=i+1;               //保存结果位数
    BigIntTrim(result);              //整理结果
}
1234567891011121314151617181920212223242526272829303132
乘法运算
对于乘法运算,以乘法的每一位去乘以被乘数。例如,首先以乘数的个位去乘被乘数,将结果通过进位处理后保存到结果位中。接着用乘数的十位去乘以被乘数,将每位计算结果累加到最终结果中。
实现代码:
两个数相乘最大的位数是两个乘数的位数之和,在乘法中我们需要每执行一次乘法就要对数组进行进位的处理。
void BigIntMul(pBIGINT num1,pBIGINT num2,pBIGINT result)
{
    char carry,temp;
    int i,j,pos;
    //结果数组和中间数清0
    for(i=0;i<num1->digit+num2->digit;i++)    
        result->num[i]=0;
    //用乘数的每一位乘以被乘数
    for(i=0;i<num2->digit;i++)              
    {
        carry=0;                              //清除进位
        //被乘数的每一位
        for(j=0;j<num1->digit;j++)                 
        {
            //相乘并加上进位
            temp=num2->num[i] * num1->num[j]+carry;   
             //计算进位carry
            carry =temp/10;
            //计算当前位的值                      
            temp=temp%10;                        
            pos=i+j;
            //计算结果累加到临时数组中
            result->num[pos]+=temp;            
            carry=carry+result->num[pos]/10;           //计算进位
            result->num[pos]=result->num[pos]%10;
        }
        if(carry>0)
        {
            result->num[i+j]=carry;                //加上最高位进位
            result->digit=i+j+1;                  //保存结果位数
        }else
            result->digit=i+j;                   //保存结果位数
    }
    result->sign=num1->sign * num2->sign;        //结果的符号
}
1234567891011121314151617181920212223242526272829303132333435
除法运算
对于大数除法运算,首先取被除数的最高两位作为部分被除数,去除以除数,根据该部分被除数与除数的结果——商,得到一位数的商。
除法对数据有限制不能分母为零,分母为零没有意义;不能用小数除以大数
实现代码:
返回的结果是保存商的数组的指针,不包含余数。
void BigIntDiv(pBIGINT num1,pBIGINT num2,pBIGINT result,pBIGINT residue)
{
    BIGINT residol;
    int i,j,k,m;               //k保存试商结果,m保存商的位数
    char t;
    result->sign = num1->sign * num2->sign;        //商的符号
     //分配余数的内存空间
    residue->num =(char *)malloc(sizeof(char) * num2->digit);  
    for(i=0;i<residue->digit;i++)            //将余数全部清0
        residue->num[i]=0;
    m=0;
    for(i=num1->digit-1;i>=0;i--)
    {
        //重新设置余数的位数比除数多一位
        residue->digit=num2->digit+1;      
        for(j=num2->digit-1;j>0;j--)               //移余数
            residue->num[j]=residue->num[j-1];
        //复制被除数中的一位到余数的最低位中
        residue->num[0]=num1->num[i];         
        BigIntTrim(residue);                  //整理余数
        k=0;                                      //试商
         //比较余数与除数的大小
        while(BigIntEqual(residue,num2)>=0)   
        {
            BigIntSub1(residue,num2,residue);     //用余数减去除数,差值保存在余数中
            k++;                       //试商加1
        }
        result->num[m++]=k;           //保存商
    }
    result->digit=m;                 //保存商的位数
    for(i=0;i<m/2;i++)              //反转商的值           
    {
        t=result->num[i];
        result->num[i]=result->num[m-1-i];
        result->num[m-1-i]=t;
    }
    BigIntTrim(result);          //整理商
    BigIntTrim(residue);            //整理余数
 }
12345678910111213141516171819202122232425262728293031323334353637383940
                                   
               
 ————————————————
版权声明:本文为CSDN博主「Teresa0312」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_36894136/article/details/79074728

专栏文章内容及配图由作者撰写发布,仅供工程师学习之用,如有侵权或者其他违规问题,请联系本站处理。 联系我们

关键词:

相关推荐

比亚迪为什么没有拿下电耗水平领先的标签?

荣芯半导体:实现与客户共进退的定制化服务

EEPW 2006年精选实用电子设计100例第一部分-通用电路

飞思卡尔展望智能本市场

展示现代安全技术的气囊系统模型车

电子技术如何助力高铁节能?

端到端来了,激光雷达就没有明天了吗?

EasyARM1138嵌入式专题讲座

视频 2010-02-05

Vishay安规电容-汽车EMI解决方案的优质选择

汽车电子 2025-01-10

EEPW 2006年精选实用电子设计100例第四部分-工控电路

EEPW 2006年精选实用电子设计100例目录

S12XE 16位微控制器应用

BOE(京东方)全新概念级“AI视听中心”亮相CES 2025

Vishay HV 系列高压 MLCC 赋能工业应用

EEPW 2006年精选实用电子设计100例第二部分-通信电路

EEPW 2006年精选实用电子设计100例第三部分-消费电子

AURIX™ TC4x网络安全架构及对ISO/SAE 21434的支持

汽车电子 2025-01-10

高频、薄型,且可像折纸一样弯曲加工的村田多层LCP基板

采用9S08LG32的汽车LCD仪表板设计

视频 2010-02-10

村田新品 | 配备MCU、支持多无线标准的微小型通信模块

更多 培训课堂
更多 焦点
更多 视频

技术专区