免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3447 | 回复: 8
打印 上一主题 下一主题

[C] 无符号大数的四则运算 [复制链接]

论坛徽章:
1
IT运维版块每日发帖之星
日期:2016-03-08 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-05-21 10:03 |只看该作者 |倒序浏览
没事编着玩儿,有兴趣的共同交流。

/***************************************
          程序名L无符号大数的四则去处程序
---------------------------------------------------
程序设计:飘来飘去的云
编制语言:标准C
编制时间:2013-5-18
****************************************/

#include <stdio.h>
#include <string.h>

#define MAX_DIGITAL        1024

/********************************************
        大数加前零
*********************************************/
char *add0BigNum(unsigned char *a,int n)       
{
        int i,len;

        len=strlen(a);
        a[len+n]=0;
       
        for (i=len; i>0; i--)
        {
                a[i-1+n]=a[i-1];
        }
        for (i=0; i<n; i++) a[i]='0';

        return a;
}

/********************************************
        大数去前零
*********************************************/
char *trimBigNum(unsigned char *a)       
{
        int i,j,k;

        k=0;
        for (i=0; i<strlen(a); i++)
        {
                if (a[i]=='0')
                {
                        k++;
                }
                else
                {
                        for (j=i; j<=strlen(a); j++)
                        {
                                a[j-k]=a[j];
                        }
                        return a;
                }
        }
        a[0]='0';a[1]=0;        //全部为'0'的串
        return a;
}

/********************************************
        大数比较,a,b
        返回,a>b        >0
                  a=b        =0
                  a<b  <0
*********************************************/
int BigNum_Comp(unsigned char *a,unsigned char *b)       
{
        trimBigNum(a);
        trimBigNum(b);
        if (strlen(a)>strlen(b)) return 11;
        if (strlen(a)<strlen(b)) return -11;
        return strcmp(a,b);

}


/*********************************************************************
        两个无符号大数相乘法
        参数说明:a,b 两个乘数 结果存放于c中
                        a,b,c均为ASCII字符串(数字),结果可以回存于到乘数数组中
**********************************************************************/
char *Bignum_Mul(unsigned char *a,unsigned char *b,unsigned char *r)
{
        unsigned char r1[MAX_DIGITAL*2];
        int i,j,la,lb,t1,t2;

        la=strlen(a);lb=strlen(b);
        for (i=0; i<la+lb; i++)        r1[i]=0;        //结果数组初始化

        for (i=lb-1; i>=0; i--)
        {

                for (j=la-1; j>=0; j--)
                {
                        t1=r1[i+j+1]+(a[j]-'0')*(b[i]-'0');
                        r1[i+j+1]=(t1 % 10);
                        r1[i+j] += t1 / 10;
                }

       
        }
       
        j=0;
        for (i=0; i<la+lb; i++)
        {
                r1[i]=r1[i]+'0';
        }
        r1[i+j]=0;
        trimBigNum(r1);

        strcpy(r,r1);
        return r;

}

/*********************************************************************
        两个无符号大数相除法
        参数说明:a,b 被除数,除数 结果存放于c中,余数存放于r中
                        a,b,c均为ASCII字符串(数字),结果可以回存于到乘数数组中
**********************************************************************/
char *Bignum_Div(unsigned char *a,unsigned char *b,unsigned char *c,unsigned char *r)
{
        unsigned char result[MAX_DIGITAL],remain[MAX_DIGITAL];
        int i,j,l,la,lb,n;

        i=BigNum_Comp(a,b);
        if ( i == 0)        //两数相等,结果为1,余数为0
        {
                c[0]='1';c[1]=0;
                r[0]='0';r[1]=0;
                return c;
        }
        if ( i < 0)        //如果被除数小,余数就直接等于被除数
        {
                strcpy(r,a);
                c[0]='0';c[1]=0;
                return c;
        }

        for (i=0; i<MAX_DIGITAL; i++)        //结果初始化
        {
                result[i]=remain[i]=0;
        }

        la=strlen(a);lb=strlen(b);                //la >= lb
        strncpy(remain,a,lb);
        i=0;                                                        //结果位指针
        j=lb;                                                        //运算指针,指示当前算到被除数的哪一位了


        while(1)
        {
                n=0;
                while(BigNum_Comp(remain,b)>0)
                {
                        Bignum_Min(remain,b,remain);
                        n++;
                }
                result[i]=n+'0';
                i++;
                if (a[j] == 0)
                {
                        break;
                }
                l=strlen(remain);remain[l]=a[j];remain[l+1]=0;        //右移一位
                j++;
        }
        result[i]=0;

        strcpy(c,result);
        trimBigNum(remain);
        strcpy(r,remain);
        return r;

}


/*********************************************************************
        两个无符号大数加法
        参数说明:a,b 两个加数 结果存放于c中
                        a,b,c均为ASCII字符串(数字),结果可以回存于到加数数组中
**********************************************************************/
char *Bignum_Add(unsigned char *a,unsigned char *b,unsigned char *r)
{
        unsigned char r1[MAX_DIGITAL],*ch;
        int i,j,la,lb,lr,t1;

        la=strlen(a);lb=strlen(b);
        if (la < lb)
        {
                ch=a;a=b;b=ch;        //保证a位长不小于b
        }
        la=strlen(a);lb=strlen(b);
        lr=la+1;

        for (i=0; i<lr; i++) r1[i]=0;        //结果数组初始化

        t1=0;
        for (i=la-1; i>=0; i--)                        //i为长数的下标
        {
                j=i-(la-lb);                                //j为短数的下标
                if (j >=0)
                {
                        t1=(a[i]-'0')+(b[j]-'0')+t1;
                }
                else
                        t1=a[i]-'0'+t1;

                r1[i+1]=t1 %10 +'0';
                t1/=10;
        }

        if (t1)                r1[0]='1';        else r1[0]='0';

        r1[lr+1]=0;
        trimBigNum(r1);
        strcpy(r,r1);
        return r;

}

/*********************************************************************
        两个无符号大数减法
        参数说明:a,b 被减数,减数 结果存放于c中
                        a,b,c均为ASCII字符串(数字),结果可以回存于到加数数组中
                        返回int,a>b:1; a=b:0  a<b:-1
**********************************************************************/
int Bignum_Min(unsigned char *a,unsigned char *b,unsigned char *r)
{
        unsigned char r1[MAX_DIGITAL],*ch;
        int i,j,la,lb,lr,t1,k,flag;

        flag=BigNum_Comp(a,b);
        if (!flag )                        //两数相等,直接返回结果0
        {
                r[0]='0';r[1]=0;
                return 0;
        }

       
        if ( flag<0 )
        {
                ch=a;a=b;b=ch;        //保证a不小于b,运算结果为正数
        }
        la=strlen(a);lb=strlen(b);
        lr=la;

        for (i=0; i<lr+1; i++) r1[i]=0;        //结果数组初始化

        k=0;                                                        //借位标志
        for (i=la-1; i>=0; i--)                        //i为长数的下标
        {
                j=i-(la-lb);                                //j为短数的下标
                if (j >=0)
                {
                        if (a[i] < (b[j]+k))                //不够减,需要借位
                        {
                                t1=10+(a[i]-'0')-(b[j]-'0')-k;
                                k=1;       
                        }
                        else
                        {
                                t1=(a[i]-'0')-(b[j]-'0')-k;
                                k=0;
                        }
                }
                else
                        if (a[i] < k)                //不够减,需要借位
                        {
                                t1=10+(a[i]-'0')-k;
                                k=1;       
                        }
                        else
                        {
                                t1=(a[i]-'0')-k;
                                k=0;
                        }

                r1[i]=t1+'0';
                }

        trimBigNum(r1);
        strcpy(r,r1);
        return flag;

}

int main(int argc, char *argv[])
{

        unsigned char *a="9835636787334143566568710547243798",*b="100050000000",c[MAX_DIGITAL*2],d[MAX_DIGITAL];

        Bignum_Div(a,b,c,d);
        printf("%s\t%s\n%s\t\t\t%s\n",a,b,c,d);
        return 0;
}

论坛徽章:
14
巨蟹座
日期:2013-11-19 14:09:4615-16赛季CBA联赛之青岛
日期:2016-07-05 12:36:0515-16赛季CBA联赛之广东
日期:2016-06-29 11:45:542015亚冠之全北现代
日期:2015-07-22 08:09:472015年辞旧岁徽章
日期:2015-03-03 16:54:15巨蟹座
日期:2014-12-29 08:22:29射手座
日期:2014-12-05 08:20:39狮子座
日期:2014-11-05 12:33:52寅虎
日期:2014-08-13 09:01:31巳蛇
日期:2014-06-16 16:29:52技术图书徽章
日期:2014-04-15 08:44:01天蝎座
日期:2014-03-11 13:06:45
2 [报告]
发表于 2013-05-21 10:20 |只看该作者
一个字:好长

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
3 [报告]
发表于 2013-05-21 10:30 |只看该作者
建议看看GMP的代码,纯C写的大数运算代码,不管程序员水平有多高,基本上可以归类为垃圾代码

论坛徽章:
1
IT运维版块每日发帖之星
日期:2016-03-08 06:20:00
4 [报告]
发表于 2013-05-21 10:39 |只看该作者
回复 3# safedead

编编代码有时是可以用来练练手的,纯属个人爱好。搜个代码什么的实用一下可以,对开发思路没什么太大的用处。


   

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
5 [报告]
发表于 2013-06-14 15:19 |只看该作者
f310 发表于 2013-05-21 10:03
没事编着玩儿,有兴趣的共同交流。

/***************************************

不反对你编着玩,性能低。

论坛徽章:
0
6 [报告]
发表于 2013-06-15 13:59 |只看该作者
大数算法.性能本来就是相对而言.
建议你去看看大数类, 可以直接拿来处理几乎所有大数问题.而且简单易用.

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
7 [报告]
发表于 2013-06-15 20:58 |只看该作者
546588532 发表于 2013-06-15 13:59
大数算法.性能本来就是相对而言.
建议你去看看大数类, 可以直接拿来处理几乎所有大数问题.而且简单易用.

大数算法主要用于密码相同,比如RSA,RSA一般都嫌太慢,算法慢就更慢。

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
8 [报告]
发表于 2013-06-16 11:29 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
9 [报告]
发表于 2013-06-16 20:39 |只看该作者
本帖最后由 群雄逐鹿中原 于 2013-06-16 21:31 编辑

这句应该有bug
         r1[i+j] += t1 / 10;

为什么这么说,因为这样的程序我也写过,知道bug在哪里

-----------------------------------------------------------------

抱歉,好像也没错。
我原本想有再次溢出的问题。楼主用的10进制,不会有问题。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP