高精度のアルゴリズム(C / C ++)

高精度のアルゴリズム(C / C ++)

ドゥACMの質問は、私たちは多くの場合、加算、減算、乗算パワー、階乗を大量に遭遇し、その後、データの特定のタイプは、多くの場合、最終的な結果を表現するには十分ではありません、あなたは、高精度演算を使用する必要があります。アルゴリズムの性質は、固定長の複数のブロックに多数の精密分割であり、各ブロックは、操作に対応します。負の整数、次に読み取る;ここで(他のビットも考えられるが、それぞれ対応する動作であるノートは、データ型の値の範囲を超えないようにすることができ、例えば、多数の正の整数であり、入力され、4桁の数字を考慮することですサインインフィッティング意思決定の判定動作)。

1.高精度加算器

例に3479957928375817 + 897,259,321,544,245:

3479 9579 2837 5817
897 2593 2154 4245
= = = =
4376 12172 4991 10062
キャリー0 キャリー1 キャリー0 キャリー1
4377 2172 4992 0062

C言語のコードを次のように:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 200

//整数乘幂运算函数
int Pow(int a, int b)
{
    int i = 0, result = 1;
    for(i = 0; i < b; ++i)
    {
        result *= a;
    }
    return result;
}


//High Precision Of Addition
int main()
{
    char stra[N], strb[N];      //字符串数组,以字符形式储存两个大数;
    int i = 0, step = 4, carry = 0; //step表示块长,carry为进位位;
    int lengtha, lengthb, maxlength, resultsize;    //maxlength表示stra和strb二者长度较大的那个;
    int numa[N], numb[N],numc[N];   //依次储存被加数,加数,和;
    memset(numa, 0, sizeof(numa));
    memset(numb, 0, sizeof(numb));
    memset(numc, 0, sizeof(numc));         //初始化为零;
    scanf("%s%s", stra, strb);
    lengtha = strlen(stra);
    lengthb = strlen(strb);     //计算两个大数的长度
    //字符数字转为四位一块的整数数字
    for(i = lengtha-1; i >= 0; --i)
    {
        numa[(lengtha-1-i)/step] += (stra[i]-'0')*Pow(10,(lengtha-1-i)%step);
    }
    for(i = lengthb-1; i >= 0; --i)
    {
        numb[(lengthb-1-i)/step] += (strb[i]-'0')*Pow(10,(lengthb-1-i)%step);
    }
    maxlength = lengtha > lengthb ? lengtha : lengthb;

    //逐块相加,并进位
    for(i = 0; i <= maxlength/step; ++i)
    {
        numc[i] = (numa[i] + numb[i])%Pow(10, step) + carry;    //计算和
        carry = (numa[i] + numb[i])/Pow(10, step);  //计算进位
    }

    //计算最后和的块的总数
    resultsize = numc[maxlength/step] > 0 ? maxlength/step : maxlength/step - 1;
    printf("%d", numc[resultsize]);
    for(i = resultsize-1; i >= 0; --i)
    {
        printf("%04d", numc[i]);    //右对齐,补零输出;
    }
    printf("\n");
    return 0;
}

2.精密減算

そして、同様の加算器は、符号変化と表示桁ことに注意する点が異なります。99,999,037,289,799 --100,004,642,015,000例に:
最初にその大被減数と減算を決定し、減算は明らかに大きなここで、その出力結果が否定的です。以下の表に(減算は負の数である場合、上部ブロックボローが希望)小数で多数を差し引きます

100 0046 4201 5000
-99 -9990 -3728 -9799
1 56 473 5201
ボロー0 ボロー1 ボロー0 ボロー1
0 56 472 5201

C言語のコードを次のように:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 200

//整数乘幂运算函数
int Pow(int a, int b)
{
    int i = 0, result = 1;
    for(i = 0; i < b; ++i)
    {
        result *= a;
    }
    return result;
}

//High Precision Of Subtraction
int main()
{
    char stra[N], strb[N];     //字符串数组,以字符形式储存两个大数;
    int i = 0, step = 4, borrow = 0, mark = 0; //step表示块长,borrow为借位位, mark为结果符号位;
    int lengtha, lengthb, maxlength, resultsize;    //maxlength表示stra和strb二者长度较大的那个;
    int numa[N], numb[N],numc[N],  *maxnum, *minnum;   //依次储存被减数,减数,和;
    memset(stra, 0, sizeof(stra));
    memset(strb, 0, sizeof(strb));
    memset(numa, 0, sizeof(numa));
    memset(numb, 0, sizeof(numb));
    memset(numc, 0, sizeof(numc));         //初始化为零;
    scanf("%s%s", stra, strb);
    lengtha = strlen(stra);
    lengthb = strlen(strb);     //计算两个大数的长度
    maxlength = lengtha >= lengthb ? lengtha : lengthb;

    //字符数字转为四位一块的整数数字
    for(i = lengtha-1; i >= 0; --i)
    {
        numa[(lengtha-1-i)/step] += (stra[i]-'0')*Pow(10,(lengtha-1-i)%step);
    }
    for(i = lengthb-1; i >= 0; --i)
    {
        numb[(lengthb-1-i)/step] += (strb[i]-'0')*Pow(10,(lengthb-1-i)%step);
    }

    //找出较大的数
    maxnum = numa;
    minnum = numb;
    mark = 1;
    for(i = (maxlength-1)/step; i >= 0; --i)
    {
        if(numa[i] > numb[i])
        {
            maxnum = numa;
            minnum = numb;
            mark = 1;
            break;
        }
        else if(numa[i] < numb[i])
        {
            maxnum = numb;
            minnum = numa;
            mark = -1;
            break;
        }
    }

    //逐块相减,并借位
    for(i = 0; i <= maxlength/step; ++i)
    {
        numc[i] = (maxnum[i] - minnum[i] + Pow(10, step) + borrow)%Pow(10,step);    //计算差
        borrow = (maxnum[i] - minnum[i] + Pow(10, step) + borrow)/Pow(10, step) - 1;  //计算借位
    }

    //计算最后和的块的总数
    resultsize = maxlength/step;
    while(!numc[resultsize])    --resultsize;
    printf("%d", mark*numc[resultsize]);
    for(i = resultsize-1; i >= 0; --i)
    {
        printf("%04d", numc[i]);    //右对齐,补零输出;
    }
    printf("\n");
    return 0;
}

3.高精度乗算

乗算は、一例として4296556241 X 56241に各和を乗算する乗算器と被乗数として見ることができます。

被乗数 42 9655 6241
乗数 5 6 2 4 1
被乗数Xの乗算 42 9655 6241
1 42 9655 6241
4 168 * 10 38620 * 10 24964 * 10
2 84 * 100 19310 * 100 12482 * 100
6 * 1000 252 57930×1000 37446×1000
5 210 * 10000 48275 * 10000 31205 * 10000
累積と 2362122 543006855 351000081
キャリー(ハイからローに) 241 54304 35100
プロダクト 241 6426 1955 0081

C言語のコードを次のように:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 200

//整数乘幂运算函数
int Pow(int a, int b)
{
    int i = 0, result = 1;
    for(i = 0; i < b; ++i)
    {
        result *= a;
    }
    return result;
}


//High Precision Of Multiplication
int main()
{
    char stra[N], strb[N];      //字符串数组,以字符形式储存两个大数;
    int i = 0, j = 0, k = 0, step = 4, carry = 0; //step表示块长,carry为进位位;
    int lengtha, lengthb, resultsize, tmpsize, eachnum;  //resultsize储存块的总数,eachnum用来储存乘数的每一位
    int numa[N], numb[N], numc[N], tmp[N];   //依次储存被乘数数&积,乘数;
    memset(numa, 0, sizeof(numa));
    memset(numb, 0, sizeof(numb));
    memset(numc, 0, sizeof(numc));  //初始化为零;
    scanf("%s%s", stra, strb);
    lengtha = strlen(stra);
    lengthb = strlen(strb);     //计算两个大数的长度
    //将被乘数字符数字转为四位一块的整数数字
    for(i = lengtha-1; i >= 0; --i)
    {
        numa[(lengtha-1-i)/step] += (stra[i]-'0')*Pow(10,(lengtha-1-i)%step);
    }
    //将乘数数字字符数字转为一位一块的整数数字
    for(i = lengthb-1; i >= 0; --i)
    {
        numb[lengthb-1-i] = strb[i]-'0';
    }

    resultsize = tmpsize = (lengtha-1)/step;
    //取乘数的每一位与被乘数的逐块相乘,并进位;
    for(i = 0; i < lengthb; ++i)
    {
        memcpy(tmp, numa, sizeof(numa));    //将numa数组赋值给tmp数组;

        k = i/step;     //k储存每一块需要向高位块移动的次数;
        if(k)
        {
            for(j = tmpsize; j >= 0; --j)
            {
                tmp[j+k] = tmp[j];
                tmp[j] = 0;
            }
            tmpsize += k;
        }

        //乘以乘数每一位扩展成的块;
        eachnum = numb[i]*Pow(10, i%step);
        for(j = 0; j <= tmpsize; ++j)
        {
            tmp[j] *= eachnum;
        }

        //大数相加
        carry = 0;  //进位置零;
        for(j = 0; j <= resultsize; ++j)
        {
            numc[j] += tmp[j] + carry;
            carry = numc[j]/Pow(10,step);
            numc[j] %= Pow(10, step);
        }
        if(carry)
        {
            ++resultsize;
            numc[j] += carry;
        }
    }

    //输出
    printf("%d", numc[resultsize]);
    for(i = resultsize-1; i >= 0; --i)
    {
        printf("%04d", numc[i]);    //右对齐,补零输出;
    }
    printf("\n");
    return 0;
}

4.精密分割

二つの高精度の分割、一方は高精度、低精度、精度および他の精密で割られることによって分割さがあります。前者単に除数ができる低精度のそれぞれを分割して、周波数および減算を達成すると考えられる精度、すなわち、除数未満に減少するまで、各精密除数を減算し、減算プロバイダであり、残りそれは余りあります。

  • 高精度、低精度を分割
    9876342876 /例343に:
配当 98 7634 2876
除数 343
下部ブロックを運ぶために 98 137 190
ビジネス 0 2879 4002
余り 190

以下を達成するためにC言語コード:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 200

//整数乘幂运算函数
int Pow(int a, int b)
{
    int i = 0, result = 1;
    for(i = 0; i < b; ++i)
    {
        result *= a;
    }
    return result;
}

//High Precision Of division
//(1)高精度除以低精度
int main()
{
    char stra[N];      //字符串数组,以字符形式储存高精度被除数;
    int i = 0, step = 4, carry = 0; //step表示块长,carry为高位向低位进位位;
    int lengtha, resultsize;
    int numa[N], numb, numc[N], numd;   //依次储存被除数,除数,商, 余数;
    memset(numa, 0, sizeof(numa));
    memset(numc, 0, sizeof(numc));         //初始化为零;
    scanf("%s%d", stra, &numb);
    lengtha = strlen(stra);   //计算被除数的长度

    //字符数字转为四位一块的整数数字
    for(i = lengtha-1; i >= 0; --i)
    {
        numa[(lengtha-1-i)/step] += (stra[i]-'0')*Pow(10,(lengtha-1-i)%step);
    }

    carry = 0;  //高位向低位进位位置零
    resultsize = (lengtha-1)/step;
    //逐块相除,高位向低位进位
    for(i = resultsize; i >= 0; --i)
    {
        numc[i] = (numa[i] + carry*Pow(10,step))/numb;    //计算商
        carry = (numa[i] + carry*Pow(10,step))%numb;  //计算进位
    }
    numd = carry;   //最低位块的余数即为整个除法的余数

    //计算最后和的块的总数
    while(!numc[resultsize])    --resultsize;
    //输出商
    printf("%d", numc[resultsize]);
    for(i = resultsize-1; i >= 0; --i)
    {
        printf("%04d", numc[i]);    //右对齐,补零输出;
    }
    //输出余数
    printf("\n%d\n", numd);
    return 0;
}
  • 精密分割精度
    例として176342876/3453452に:
配当 176342876
- (51のx 除数 51 X 3453452
余り 216824
ビジネス 51

以下を達成するためにC言語コード:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 200

//整数乘幂运算函数
int Pow(int a, int b)
{
    int i = 0, result = 1;
    for(i = 0; i < b; ++i)
    {
        result *= a;
    }
    return result;
}

//High Precision Of division
//(2)高精度除以高精度
int main()
{
    char stra[N], strb[N];     //字符串数组,以字符形式储存两个大数;
    int i = 0, step = 4, borrow = 0; //step表示块长,borrow为进位位;
    int lengtha, lengthb, tmpnum, numbsize, numcsize, numdsize, maxsize, mark;    //maxlength表示stra和strb二者长度较大的那个;
    int numa[N], numb[N], numc[N], numd[N];   //依次储存被除数数,除数数,商,余数;
    memset(stra, 0, sizeof(stra));
    memset(strb, 0, sizeof(strb));
    memset(numa, 0, sizeof(numa));
    memset(numb, 0, sizeof(numb));
    memset(numc, 0, sizeof(numc));
    memset(numd, 0, sizeof(numd));      //初始化为零;
    scanf("%s%s", stra, strb);
    lengtha = strlen(stra);
    lengthb = strlen(strb);     //计算两个大数的长度

    //字符数字转为四位一块的整数数字
    for(i = lengtha-1; i >= 0; --i)
    {
        numa[(lengtha-1-i)/step] += (stra[i]-'0')*Pow(10,(lengtha-1-i)%step);
    }
    for(i = lengthb-1; i >= 0; --i)
    {
        numb[(lengthb-1-i)/step] += (strb[i]-'0')*Pow(10,(lengthb-1-i)%step);
    }
    memcpy(numd, numa, sizeof(numa));
    numbsize = (lengthb-1)/step;
    numcsize = 0;
    numdsize = (lengtha-1)/step;

    do
    {
        maxsize = numdsize > numbsize ? numdsize : numbsize;
        //计算剩余数是否小于除数
        mark = 1;
        for(i = maxsize; i >= 0; --i)
        {
            if(numd[i] > numb[i])
            {
                mark = 1;
                break;
            }
            else if(numd[i] < numb[i])
            {
                mark = -1;
                break;
            }
        }

        //判断是否余数已经小于除数
        if(!(mark+1))   break;

        borrow = 0; //借位置零;
        //逐块相减,并借位
        for(i = 0; i <= maxsize; ++i)
        {
            tmpnum = (numd[i] - numb[i] + Pow(10, step) + borrow)%Pow(10,step);    //计算差
            borrow = (numd[i] - numb[i] + Pow(10, step) + borrow)/Pow(10,step) - 1;  //计算借位
            numd[i] = tmpnum;
        }
        while(!numd[numdsize])  --numdsize;

        //每减一个除数,商加一;
        borrow = 1;
        for(i = 0; i <= numcsize; ++i)
        {
            numc[i] += borrow;
            borrow = numc[i]/Pow(10,step);
            numc[i] %= Pow(10,step);
        }
        if(borrow)
        {
            ++numcsize;
            numc[i] += borrow;
        }
    }while(1);

    printf("%d", numc[numcsize]);
    for(i = numcsize-1; i >= 0; --i)
    {
        printf("%04d", numc[i]);    //右对齐,补零输出;
    }
    printf("\n");
    printf("%d", numd[numdsize]);
    for(i = numdsize-1; i >= 0; --i)
    {
        printf("%04d", numd[i]);    //右对齐,补零输出;
    }
    printf("\n");
    return 0;
}

おすすめ

転載: www.cnblogs.com/BlueHeart0621/p/12238176.html
おすすめ