C语言实现大数运算[通俗易懂]

C语言实现大数运算[通俗易懂]由于整型数的位数有限,因此整型数不能满足大整数(超长整数)的运算要求。大整数计算是利用字符串来表示大整数,即用字符串的一位字符表示大整数的一位数值,然后根据四则运算规则实现大整数的四则运算。大数的结构typedefstructbigint{char*num;//指向长整数数组(序号0中保存着最高位)charsign;

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

Jetbrains全系列IDE稳定放心使用

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

大数的结构

typedef struct bigint
{
    char *num;                //指向长整数数组(序号0中保存着最高位) 
    char sign;               //符号(1表示正数,-1表示负数) 
    int digit;                 //保存该数的位数(实际位数) 
}BIGINT, *pBIGINT; 

加法运算

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

这里写图片描述

实现代码:
首先将被加数中的内容复制到结果数组中,然后从低位逐渐加到结果中去,最后判断加数各位加完之后是否还有进位,如果有则要累加到高位中去。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);              //整理结果 
} 

乘法运算
对于乘法运算,以乘法的每一位去乘以被乘数。例如,首先以乘数的个位去乘被乘数,将结果通过进位处理后保存到结果位中。接着用乘数的十位去乘以被乘数,将每位计算结果累加到最终结果中。

这里写图片描述
实现代码:
两个数相乘最大的位数是两个乘数的位数之和,在乘法中我们需要每执行一次乘法就要对数组进行进位的处理。

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;        //结果的符号 
} 

除法运算
对于大数除法运算,首先取被除数的最高两位作为部分被除数,去除以除数,根据该部分被除数与除数的结果——商,得到一位数的商。
除法对数据有限制不能分母为零,分母为零没有意义;不能用小数除以大数

这里写图片描述
实现代码:
返回的结果是保存商的数组的指针,不包含余数。

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);            //整理余数 
 }

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

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

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


相关推荐

  • rapidxml 文件读写,增加删除节点「建议收藏」

    rapidxml 文件读写,增加删除节点「建议收藏」RapidXml是指XMLDOM解析工具包,是一个快速的读写xml文件的库文件(hpp)。本文旨在提供RapidXml文件读写操作,以及对节点的增加、删除、编译提供一个测试用例,以免忘记。1.读取XML#include”rapidxml.hpp”#include”rapidxml_utils.hpp”#include”rapidxml_print.hpp”#includ…

    2022年7月17日
  • springbean生命周期通俗一点_spring为啥是单例模式

    springbean生命周期通俗一点_spring为啥是单例模式一、Spring核心模块介绍1.SpringCore:Core封装包是框架的最基础部分,提供IOC和依赖注入特性。这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。2.SpringContext:构建于Core封装包基础上的Context封装包,提供了一种框架式的对象访问方法,有些象JNDI注册器。Context封装包的特性得自于Beans封装包,并添加了对国际化(I18N).

    2022年9月18日
  • C语言学习——指针精华(3)工程项目复习

    C语言学习——指针精华(3)工程项目复习编程题一、定义一个数组,从键盘输入10个整数,将10个数字中的最大值和最小值进行位置交换 (使用指针的方式)。代码如下:#include”pch.h”#include<stdio.h>void SWAP(int*p1, int*p2);int main(){ int a[10]; for (int i = 0; i < 10; i++) { scanf_…

    2022年8月18日
  • 【CEGUI】资源加载流程「建议收藏」

    【CEGUI】资源加载流程「建议收藏」CEGUI资源加载流程主要资源类型Schemescheme资源(包括图像集、字体资源、窗口外观信息、类型映射)等。可以通过“.scheme“”将CEGUI系统所需要的全部资源一次加载。例:TaharezLook.scheme<?xmlversion=”1.0″?> <GUISchemeversion=”5″name=”TaharezLook”> <Imagesetfilename=”TaharezLook.imagese

    2022年7月23日
  • 定时任务30秒执行一次_windows查看计划任务

    定时任务30秒执行一次_windows查看计划任务《定时执行专家》是一款制作精良、功能全面、使用简单的专业定时执行工具软件。支持18种任务类型,11种任务触发方式(包含Cron方式),触发精度达到“秒”级。软件无需安装,无使用时间限制,欢迎下载使用。软件使用Unicode编码,可以在英文、日文等所有外文Windows系统下正常使用,并且软件带有中、日、英多国语言界面版本,可自由切换。…

    2022年9月4日
  • 简单的激光干涉测距仪原理——为什么只能测量相对距离「建议收藏」

    简单的激光干涉测距仪原理——为什么只能测量相对距离「建议收藏」为什么要用激光来测量距离呢?这一切都是因为激光的波长很短,同频率的光波叠加会在波长级的尺度上产生周期性的变化,因此用激光测量距离时,精度是波长级别的,这也是为什么通常选用波长较短的激光进行测距。将同一光束分成两束,其中一束状态不变,另一束经物体反射后与第一束合并,以光电探测器进行探测。物体每移动半个波长,探测器探测到的信号就会出现一个极值,通过数极值的数量就可以知道物体移动了多少。…

    2022年5月22日

发表回复

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

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