大数除法,大数辗转相除(密码学第三次实验作业)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chimchim04/article/details/84667074

大数除法:把除法运算转化为减法运算

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 1000005
char a[N],b[N];
int x[N],y[N],c[N<<1];
//用长度为len1的大整数p1减去长度为len2的大整数p2
// 结果存在p1中,返回值代表结果的长度,不够减返回-1,正好减完返回0
int SubStract( int *k1, int *k2, int len1, int len2 )
{
    if( len1 < len2 )
        return -1;
    if( len1 == len2 )
    {
        //判断k1 > k2
        for(int i=len1-1; i>=0; i-- )
        {
            if( k1[i] > k2[i] )
                break;
            else if( k1[i] < k2[i] )
                return -1;
        }
    }
    for(int i=0; i<=len1-1; i++ )  //从低位开始做减法
    {
        k1[i] -= k2[i];
        if( k1[i] < 0 )          //若p1<0,则需要借位
        {
            k1[i] += 10;         //借1当10
            k1[i+1]--;           //高位减1
        }
    }
    for(int i=len1-1; i>=0; i-- )       //查找结果的最高位
        if( k1[i] )                  //最高位第一个不为0
            return (i+1);       //得到位数并返回
    return 0;                  //两数相等的时候返回0
}
int main()
{
    while(~scanf("%s%s",a,b))
    {
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
        memset(c,0,sizeof(c));
        int len1=strlen(a),len2=strlen(b),len;
        for(int i=len1-1,j=0; i>=0; j++,i--)
            x[j]=a[i]-'0';
        for(int i=len2-1,j=0; i>=0; j++,i--)
            y[j]=b[i]-'0';
        if( len1 < len2 )   //如果被除数小于除数,结果为0
        {
            printf("0\n");
            printf("%s\n",a);
            continue;
        }
        len= len1 - len2;
        for (int i=len1-1; i>=0; i-- )    //将除数扩大,使得除数和被除数位数相等
        {
            if ( i>=len )
                y[i] = y[i-len];
            else                     //低位置0
                y[i] = 0;
        }
        len2 = len1;
        int n;
        for(int j=0; j<=len; j++ )      //重复调用,同时记录减成功的次数,即为商
        {
            while((n= SubStract(x,y + j,len1,len2 - j)) >= 0)
            {
                len1 =n;      //结果长度
                c[len-j]++;//每成功减一次,将商的相应位加1
            }
        }
        //输出商
        while(1)
        {
            if(c[len])
                break;
            len--;
        }
        for(int i=len; i>=0; i--)
            printf("%d",c[i]);
        printf("\n");
        //输出余数
        while(1)
        {
            if(x[len1]||len1==0)
                break;
            len1--;
        }
        for(int i=len1; i>=0; i--)
            printf("%d",x[i]);
        printf("\n");
    }
    return 0;
}

大数辗转相除:就是根据上面的除法改一下

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 1000005
char a[N],b[N];
int x[N],y[N],c[N];
int SubStract( int *k1, int *k2, int len1, int len2 )
{
    if( len1 < len2 )
        return -1;
    if( len1 == len2 )
    {
        //判断k1 > k2
        for(int i=len1-1; i>=0; i-- )
        {
            if( k1[i] > k2[i] )
                break;
            else if( k1[i] < k2[i] )
                return -1;
        }
    }
    for(int i=0; i<=len1-1; i++ )  //从低位开始做减法
    {
        k1[i] -= k2[i];
        if( k1[i] < 0 )          //若p1<0,则需要借位
        {
            k1[i] += 10;         //借1当10
            k1[i+1]--;           //高位减1
        }
    }
    for(int i=len1-1; i>=0; i-- )       //查找结果的最高位
        if( k1[i] )                  //最高位第一个不为0
            return (i+1);       //得到位数并返回
    return 0;                  //两数相等的时候返回0
}
int main()
{
    while(~scanf("%s%s",a,b))
    {
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
        memset(c,0,sizeof(c));
        int len1=strlen(a),len2=strlen(b),len;
        if(len1<len2||(len1==len2&&strcmp(a,b)<0))  //把大的数换到前面
        {
            swap(a,b);
            swap(len1,len2);
        }
        for(int i=len1-1,j=0; i>=0; j++,i--)
            x[j]=a[i]-'0';
        for(int i=len2-1,j=0; i>=0; j++,i--)
            y[j]=b[i]-'0';
        int l;
        while(1)
        {
            l=len2;
            len= len1 - len2;
            for (int i=len1-1; i>=0; i-- )    //将除数扩大,使得除数和被除数位数相等
            {
                if ( i>=len )
                    y[i] = y[i-len];
                else                     //低位置0
                    y[i] = 0;
            }
            len2 = len1;
            int n;
            for(int j=0; j<=len; j++ )      //重复调用,同时记录减成功的次数,即为商
            {
                while((n= SubStract(x,y + j,len1,len2 - j)) >= 0)
                    len1 =n;
            }
            while(1)
            {
                if(x[len1-1]||len1==0)
                    break;
                len1--;
            }
            if(len1==0) //余数为0时,此时除数就是最大公约数
            {
                for(int i=len2-1;i>=len2-l;i--)
                    printf("%d",y[i]);
                printf("\n");
                break;
            }
            //把除数变为下一个式子被除数,把余数变为除数
            for(int i=0;i<len1;i++)
                c[i]=x[i];
            for(int i=len2-1,j=l-1;i>=len-l;i--,j--)
                x[j]=y[i];
            for(int i=0;i<len1;i++)
                y[i]=c[i];
            len2=l;
            swap(len1,len2);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/chimchim04/article/details/84667074