码迷,mamicode.com
首页 > 其他好文 > 详细

一个大数的好东西

时间:2018-07-18 23:25:46      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:strlen   ios   strcpy   view   同余定理   printf   最小   for   方法   

技术分享图片
#include<stdio.h>//不能连续复合运算,要保存结果
#include<stdlib.h>//所以一个技巧就是用strcpy来代替等号
#include<string.h>//c=a+b改写为strcpy(c,BigAdd(a,b))
#include <iostream>
using namespace std;
#define BASE 10    //确定进制
#define N 90001    //确定 最大位数+1

int l = 0;                //每次记录缓存区用了多长,还原时节省时间
char res[N] = { \0 };  //保存结果

void ini(char * x , int l);   //初始化x数组
int BigCmp(char * a, char * b);  //  大数a < 大数b 返回1 ,相等返回0 ,a>b返回-1
void Clean(char * x, int l);//清除尾部的‘0’
void rev(char * x);//倒置字符串 ,与Clean联用,清除前导0

char * BigAdd(char * a, char * b);
char * BigSub(char * a,char * b);
char * BigMul(char * a,char * b);
char * BigDivNum(char * num,int  n);//大数除以一个int
char * BigDivBig(char * a,char * b);//大数除以一个大数

char * BigPow(char *num ,int n);
char * BigMod(char * num , int mod);
char * BigFuc(int num);

int main()
{
    char a[N] = {\0},b[N]={\0};
    int n;

    while(~scanf("%s%s%d",a,b,&n))
    {
        cout<<"a+b="<<" ";
        puts(BigAdd(a,b));

        cout<<"a-b="<<" ";
        puts(BigSub(a,b));

        cout<<"a*b="<<" ";
        puts(BigMul(a,b));

        cout<<"a/b="<<" ";
        puts(BigDivBig(a,b));

        cout<<"a/n="<<" ";
        puts(BigDivNum(a,n));

        cout<<"a^n="<<" ";
        puts(BigPow(a,n));

        cout<<"a%n="<<" ";
        puts(BigMod(a,n));

        cout<<"n!="<<" ";
        puts(BigFuc(n));

        puts("");
    }
    return 0;
}

char *  BigAdd( char * a, char * b)
{
    int i,j,k;
    int sum,la,lb,carry,flag,cmp;
    char *ans,*temp;

    ini(res,l);
    carry = 0;
    flag = 0;
    ans = &res[1];

    if(a[0] == - && b[0] != -)         //判断正负
        return BigSub(b,a+1);
    else if(a[0] != - && b[0] == -)
        return BigSub(a,b+1);
    else if(a[0] == - && b[0] == -)
    {
        flag = 1;
        a++;
        b++;
    }

    la=strlen(a);
    lb=strlen(b);

    if(b[0] == 0 && lb == 1)     //判断0
    {
        strcpy(ans,a);
        l = strlen(ans);
        return ans;
    }
    else if(a[0] == 0 && la ==1)
    {
        strcpy(ans,b);
        l = strlen(ans);
        return ans;
    }

    rev(a);
    rev(b);

    if(BigCmp(a,b) == 1)     //保持大数a>大数b
    {
        temp = a;
        a = b;
        b =temp;

        k = la;
        la = lb;
        lb = k;
    }

    for(i = lb ; i < la ; i++)  //空位补0
        b[i] = 0;

    for(i = 0 ; i < la ; i++)
    {
        sum = (a[i]-48) + (b[i]-48) + carry;

        if( sum < BASE )
        {
            ans[i] = sum + 48;
            carry = 0;
        }
        else
        {
            ans[i] = sum  - BASE  + 48;
            carry = 1;
        }
    }

    if(carry)   //补充最高位
    {
        ans[i] = carry + 48;
        i++;
    }

    Clean(ans,i);

    for(i = lb ; i < la ; i++)//删除后补上的0
        b[i] = \0;

    rev(ans);
    rev(a);
    rev(b);

    if(flag)
    {
        res[0] = -;
        ans = res;
    }

    l = strlen(ans);
    return ans;
}

char * BigSub(char * a,char * b)
{
    char *ans,*temp;
    int i,j,k;
    int borrow,flag,la,lb,sub,cmp;

    ini(res,l);
    ans = &res[1];

    flag = 0;  //结果没有负号
    borrow = 0;

    if(a[0]==- && b[0]!=-)  //被减数为负,减数为正,结果为负
    {
        BigAdd(b,a+1);
        res[0] = -;
        return  res;
    }
    else if(a[0]!=- && b[0]==-) //被减数为正,减数为负,结果为正
        return BigAdd(a,b+1);
    else if(a[0]==- && b[0]==-)   //如果a,b为同时负,交换他们并都改为正,保证为“a-b”的形式
    {
        temp=a;
        a=b;
        b=temp;

        a++;
        b++;
    }

    la = strlen(a);
    lb = strlen(b);

    if(b[0] == 0 && lb == 1)     //判断0
    {
        l = strlen(strcpy(ans,a));
        return ans;
    }
    else if(a[0] == 0 && la == 1)
    {
            if(b[0] == -)
            {
                l = strlen(strcpy(ans,b+1));
                return ans;
            }
            else
            {
                res[0] = -;
                l = strlen(strcpy(ans,b));
                return res;
            }
    }

    cmp = BigCmp(a,b);

    if(cmp == 0)
    {
        l = 1;
        res[0] = 0;
        res[1] = \0;
        return res;
    }
    else if(cmp == 1)  //保持大数a>=大数b
    {
        temp=a;
        a=b;
        b=temp;
        flag=1;  //结果有负号

        k = la;
        la = lb;
        lb = k;
    }

    rev(a);
    rev(b);

    for(i=0; i<lb ; i++)
    {
        sub = a[i] - borrow - b[i];

        if( sub >= 0)
        {
            ans[i] = sub + 48;
            borrow = 0 ;
        }
        else    // 溢出时的计算方法
        {
            ans[i]   = sub + BASE + 48;
            borrow = 1;
        }
    }

    while(i < la)   // 计算剩余位
    {
        sub = a[i] - borrow ;

        if(a[i] >= borrow)
        {
            ans[i]   = sub ;
            borrow = 0;
        }
        else        // 溢出时的计算方法
        {
            ans[i]  = sub +BASE ;
            borrow = 1;
        }
         i++;
    }

    Clean(ans,i);

    rev(ans);
    rev(a);
    rev(b);

    if(flag)
    {
        res[0] = -;
        ans = res;
    }

    l = strlen(ans);
    return ans;
}

char * BigMul(char * a,char * b)
{
    char *temp,*ans;
    char mul[N] = {\0},cal[N] = {\0},num[N] = {\0};
    int i,j,k;
    int carry,flag,la,lb,product,lmul;
    int sign,sign_a,sign_b;

    ini(res,l);
    ans = &res[1];

    carry = 0;
    flag = 0;
    sign = sign_a = sign_b = 0;

    if(a == b)   //重复拷贝
        b = strcpy(num,a);

    if(a[0] == - )
    {
        flag = 1;
        sign_a = 1;
        a++;
    }
    if(b[0] == - )
    {
        flag = 1;
        sign_b = 1;
        b++;
    }
    if(sign_a && sign_b)
        flag = 0;

    la = strlen(a);
    lb = strlen(b);

    if((a[0] == 0 && la == 1) || (b[0] == 0 && lb == 1))  //任何一个大数为0,结果为0
    {
        l = 1;
        res[0] = 0;
        res[1] = \0;
        return res;
    }

    if(BigCmp(a,b) == 1)   //保证大数a >= 大数b
    {
        temp = a;
        a = b ;
        b = temp;

        k = la;
        la = lb;
        lb =k;
    }

    rev(a);
    rev(b);

    Clean(a,la);//清除自带的前导0
    Clean(b,lb);
    la = strlen(a);//重新计算长度
    lb = strlen(b);

    lmul = 0;

    for(i = 0 ; i < lb ; i++)
    {
        ini(mul,lmul);

        for( j = 0 ; j < la ; j++)
        {
            product = (a[j] - 48) * (b[i] - 48) + carry ;
            mul[j] = product % BASE + 48 ;
            carry = product / BASE ;
        }

        if(carry)
        {
            mul[j] = carry + 48;
            j++;

            carry = 0;
        }

        lmul = j;  //计算缓冲区长度

        if(i == 0)
        {
            strcpy(cal,mul);
            rev(cal);
        }
        else
        {
            //清除前导0
            Clean(mul,lmul);
            //翻转字符串
            rev(mul);
            //以0补位,每次相当于乘10
            for(k = 0 ; k < i ;k++)
                mul[lmul++] = 0;
            //保存
            ans = BigAdd(cal,mul);
            ini(cal,strlen(cal));
            strcpy(cal,ans);
        }
    }
    strcpy(ans,cal);

    rev(a);
    rev(b);

    if(flag)
    {
        res[0] = -;
        ans = res;
    }
    l = strlen(ans);
    return ans;
}

char * BigDivBig(char * a,char * b)
{
    char *ans, *temp;
    int i,j,k,la,lb,cmp,times,tran_min;
    int sign,sign_a,sign_b,flag;

    ini(res,l);
    ans = &res[1];
    sign_a = sign_b = flag = 0;

    if(a[0] == -)
    {
        sign_a = flag = 1;
        a++;
    }
    if(b[0] == -)
    {
        sign_b = flag = 1;
        b++;
    }
    if(sign_a && sign_b)
        flag = 0;
    la = strlen(a);
    lb = strlen(b);

    rev(a);
    rev(b);
    Clean(a,la);
    Clean(b,lb);
    rev(a);
    rev(b);

    la = strlen(a);
    lb = strlen(b);

    if(la == 1 && a[0] == 0)
    {
        l = 1;
        res[0] = 0;
        res[1] = \0;
        return res;
    }
    if(lb == 1 && b[0] == 0)
    {
        puts("除数不能为0!");
        exit(1);
    }
    if(lb == 1 && b[0] == 1)
    {
        l = strlen(strcpy(res,a));
        return res;
    }

    cmp = BigCmp(a,b);
    if(cmp == 1)
    {
        l = 2;
        ans[0] = 0;
        ans[1] = \0;
        return ans;
    }
    else if(cmp == 0)
    {
        l = 2;
        ans[0] = 1;
        ans[1] = \0;
        if(flag)
        {
            res[0]=-;
            ans = res;
        }
        return ans;
    }
    ///对齐最高位试除
    char pre[N] = {\0},num[N] = {\0},now[N] = {\0},tran[N] = {\0};
    char mul[N] = {\0},sub[N] = {\0},div[N]={\0};
    char carry[N] = {0};///注意是 0
    memset(carry,0,sizeof(carry));
    now[0] = 0; //大数now初始化为0
    carry[0] = 1;//大数carry初始化为1000000000……
    times = la - lb;//确定最高倍数
    strcpy(num,a);  //复制a的值
    strcpy(div,b);//复制b的值
    for(i = 0 ; i < times ; i++) //对齐最高位
            div[lb+i] = 0;

    for(i = times ; i >= 0 ;i--)
    {   //最小的倍数为:a最高位/(b最高位+1),试一下就知道了
        tran_min = (num[0] - 0)/(div[0]-0+1);   ///?????
        for(j = 9 ; j >= tran_min ; j--)
        {
            sprintf(tran,"%d",j); //把试乘值转换成字符串
            strcpy(pre,BigMul(div,tran));
            strcpy(sub,BigSub(num,pre)); //sub = a - b*j;
            //从大到小找第一个可以被减的数
            if(sub[0] != -)
            {
                carry[i+1] = \0; //截断carry得到倍数
                strcpy(mul,BigMul(carry,tran));//乘上这次的值
                strcpy(now,BigAdd(now,mul));//将商保存在now中
                strcpy(num,sub);   //更新a的值
                break;
            }
        }
        div[lb+i-1] = \0; //每次循环降低一位直至复原
        memset(res,\0,sizeof(res));
    }
    strcpy(ans,now);
    if(flag)
    {
        res[0] = -;
        ans = res;
    }
    l = strlen(ans);
    return ans;
}

char * BigDivNum(char * num , int n)
{
    char * ans;
    int i,j,digit,divis,lnum,flag;
    int sign_num,sign_n;

    ini(res,l);

    ans = &res[1];

    digit = divis = flag = 0;
    sign_num = sign_n = 0;

    if(n == 0)
    {
        puts("除数不能等于0");
        exit(1);
    }

    if(n < 0)
    {
        n = -n;
        flag = 1;
        sign_n = 1;
    }
    if(num[0] == -)
    {
        num++;
        flag = 1;
        sign_num = 1;
    }
    if(sign_n && sign_num)
        flag = 0;

    lnum = strlen(num);

    if(lnum == 1 && num[0] == 0)
    {
        l = 1;
        res[0] = 0;
        res[1] = \0;
        return res;        //被除数为0,结果为0
    }

    for(i = 0 ; i < lnum ; i++)
    {
        divis = divis * 10 + (num[i]-48) ;

        if(divis >= n)
        {
            ans[digit++] = divis / n + 48;
            divis %= n;
        }
    }

    if(!digit)
        ans[digit++] = 0;

    ans[digit] = \0;

    if(flag)
    {
        res[0] = -;
        ans = res;
    }
    l = strlen(ans);
    return ans;
}

char * BigPow(char * num, int n)
{
    char  * ans;
    char cal[N] = {\0},pow[N] = {\0};
    int  flag;

    if(n == 0)
    {
        l = 1;
        res[0] = 1;
        res[1] = \0;
        return res;
    }

    if(strlen(num) == 1 && num[0] == 0)
    {
        l = 1;
        res[0] = 0;
        res[1] = \0;
        return res;
    }

    ini(res,l);
    ans = &res[1];

    flag = 0;

    strcpy(pow,num); //备份
    cal[0] = 1;

    if(pow[0] == - && n&1)
        flag = 1;

    while(n)
    {
        if(n&1)
        {
            ans = BigMul(cal,num);

            ini(cal,strlen(cal));
            strcpy(cal,ans);
        }

        ans = BigMul(num,num);

        ini(num,strlen(num));
        strcpy(num,ans);

        n >>= 1;
    }
    strcpy(num,pow); //还原

    strcpy(ans,cal);
    if(flag)
    {
        res[0] = -;
        ans = res;
    }
    l = strlen(ans);
    return ans;
}

char * BigMod(char * num , int mod)
{
    char * ans;
    int i,lnum,cal;

    if(mod == 0)
    {
        puts("除数不能等于0");
        exit(1);
    }

    ini(res,l);

    ans = &res[1];
    cal = 0;

    lnum = strlen(num);

    for(i = 0 ; i < lnum ; i++)     //循环利用同余定理
        cal = ( ((cal*BASE)%mod) + ((num[i]-48)%mod) ) % mod ;

    sprintf(ans,"%d",cal);  //转换为字符串
    l = strlen(ans);
    return ans;
}

char * BigFuc(int num)
{
    int i,j,k;
    int digit,carry,temp;
    char * ans;

    ini(res,l);
    ans = &res[1];

    if(num == 0)
    {
        l = 1;
        res[0] = 1;
        res[1] = \0;
        return res;
    }

    ans[0] = 1;
    digit = 1;

    for(i = 2 ; i <= num ; i++)
    {
        carry = 0;  //初始化为0

        for(j = 0 ; j < digit ; j++)
        {
            temp = (ans[j]-48)* i + carry; //中间值

            ans[j] = temp % BASE +48 ;
            carry = temp / BASE;
        }

        while(carry)  //处理剩余位数
        {
            ans[digit++] = carry % BASE + 48;
            carry /= BASE ;
        }
    }

    rev(ans);

    l = strlen(ans);
    return ans;
}

int BigCmp(char * a, char * b)  //  大数a < 大数b 返回1 ,相等返回0 ,a>b返回-1
{
    int i,j,k;
    int la = strlen(a),lb = strlen(b);
    char * temp;

    if(a[0] == - && b[0] != -)
        return 1;
    else if(a[0] != - && b[0] == -)
        return -1;
    else if(a[0] == - && b[0] == -)
    {
        a++;
        b++;

        temp = a;
        a = b;
        b = temp;

        la--;
        lb--;

        k = la;
        la =lb;
        lb = k;
    }

    if(la < lb)
        return 1;
    if(la > lb)
        return -1;

    if(la == lb)
    {
        for(i = 0 ; i < la ; i++)
        {
            if(a[i] < b[i])
                return 1;
            else if(a[i] > b[i])
                return -1;
        }
    }

    return 0;
}

void ini(char * x ,int l)
{
    int i;

    if(l < N)
        l++;

    for(i = 0 ; i < l ;i++)
        x[i] = \0;
}

void Clean(char * x,int l)
{
    for(l--; x[l] == 0;l--)
        x[l] = \0;
}

void rev(char * x)
{
    int right = strlen(x)-1;
    int left = 0;
    char temp;

    while(left < right)
    {
        temp = x[left];
        x[left++] = x[right];
        x[right--] = temp;
    }
}
View Code

 

一个大数的好东西

标签:strlen   ios   strcpy   view   同余定理   printf   最小   for   方法   

原文地址:https://www.cnblogs.com/buerdepepeqi/p/9332825.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!