目录

 高精度加法:

 高精度减法:

 高精度乘法:高精度最简单的运算了吧。

 高精度除法:高精度算法中最难理解的算法。

 高精度取余:高精度中代码最短的算法。

 高精度算法例题:

HDU 1002 A - A + B Problem II

HDU1047 Integer Inquiry

         HDU 1250 Hat's Fibonacci 

         HDU - 1865 1sting  


高精度算法,说白了其实就是用程序手动模拟我们在草稿本上的运算。

高精度加法:

1.概念

高精度使用数组来存储整数,模拟手算进行四则运算

2.高精度运算涉及到的问题

(1) 数据的输入:因为数字很大,不能用整数来输入,所以只能用字符数组输入,然后转化。

scanf("%s %s",str,str1);

(2) 数据的存储:因为后面的运算是从前向后进行,所以我们在转化的时候需要反向来转化;

int l1=strlen(str),l2=strlen(str1);
        for(int i=0;i<l1;i++)
            a[l1-i]=str[i]-'0';
        for(int i=0;i<l2;i++)
            b[l2-i]=str1[i]-'0';

(3)数据的运算:进位和借位,这里就是代码的核心了,就是手动模拟人算的。

int l=1,x=0;//x是处理进位 
            while(l<=l1||l<=l2)
            {
                c[l]=a[l]+b[l]+x;
                x=c[l]/10;//超过10要进位 
                c[l]%=10;//进位后留下来的数 
                l++;
            }
            c[l]=x;//最后一位可能会进位。

 (4)结果的输出:小数点的位置和处于多余的0:最后一步很简单,看代码就能懂

while(c[l]==0&&l>=0)//处理前置0 
                l--;
            if(l==-1)//结果为0 
                printf("0");
            else
                for(;l>0;l--)
                    printf("%d",c[l]);
            printf("\n");

 整体代码:

#include<stdio.h>
#include<cstring>
#include<algorithm>
const int maxn=1e5+10;
const int mod=1e9+7;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
using namespace std;
int main()
{
    char str[maxn],str1[maxn];
    int a[maxn],b[maxn],c[maxn];
    me(a,0),me(b,0),me(c,0);
    scanf("%s%s",str,str1);
    int l1=strlen(str),l2=strlen(str1);
    for(int i=0; i<l1; i++)
        a[l1-i]=str[i]-'0';
    for(int i=0; i<l2; i++)
        b[l2-i]=str1[i]-'0';
    int l=1,x=0;//x是处理进位
    while(l<=l1||l<=l2)
    {
        c[l]=a[l]+b[l]+x;
        x=c[l]/10;//超过10要进位
        c[l]%=10;//进位后留下来的数
        l++;
    }
    c[l]=x;//最后一位可能会进位。
    while(c[l]==0&&l>=0)//处理前置0
        l--;
    if(l==-1)//结果为0
        printf("0");
    else
        for(; l>0; l--)
            printf("%d",c[l]);
    printf("\n");
    return 0;
}

Java代码:

import java.math.BigInteger;
import java.util.Scanner;
 
public class mian {
 
    private static Scanner cin;
    public static void main(String[] args) {
        cin=new Scanner(System.in);
        while(cin.hasNext()) {
        BigInteger a,b,sum;
        a=cin.nextBigInteger();
        b=cin.nextBigInteger();
        sum=a.add(b);
        System.out.println(sum);
        }
         
    }
}

 

高精度减法:

和高精度加法相比,减法在差为负数时处理的细节更多一点:当被减数小于减数时,差为负数,差的绝对值是减数减去被减数;在程序实现上用一个变量来存储符号位,用另一个数组存差的绝对值。

  算法流程:

(1)读入被减数S1,S2(字符串):和高精度加法一样,可以参考上面的那个

(2)置符号位:判断被减数是否大于减数:大则将符号位置为空;小则将符号位置为“-”,交换减数与被减数;

int l1=strlen(str1),l2=strlen(str2);
        if(l1==l2&&strcmp(str1,str2)<0)//减数比被减数大
            jianfa(str2,str1,1);
        else if(l1<l2)//减数比被减数大
            jianfa(str2,str1,1);
        else
            jianfa(str1,str2,0);

(3)被减数与减数处理成数值,放在数组中; 

int len1=strlen(str1),len2=strlen(str2);
    for(int i=0,j=len1-1; i<len1; i++,j--)
        a[i]=str1[j]-'0';
    for(int i=0,j=len2-1; i<len2; i++,j--)
        b[i]=str2[j]-'0';

 

(4)运算:

    A、取数;

    B、判断是否需要借位;

   C、减,将运算结果放到差数组相应位中;

   D、判断是否运算完成:是,转5;不是,转A;

while(l<=len1)
    {
        c[l]=a[l]-b[l];
        if(c[l]<0)
        {
            c[l]+=10;
            a[l+1]--;
        }
        l++;
    }

(5)打印结果:符号位,第1位,循环处理第2到最后一位;

while(c[l]==0&&l>=0)//除去前置0
        l--;
    if(l==-1)
        printf("0");
    else
    {
        if(flog)///减数比被减数大,答案为负数
            printf("-");
        for(int i=l; i>=0; i--)
            printf("%d",c[i]);
    }
    printf("\n");

 整体代码:

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=1e5+10;
const int mod=1e9+7;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;

void jianfa(char *str1,char *str2,int flog)
{
    int a[maxn],b[maxn],c[maxn];
    me(a,0),me(b,0),me(c,0);
    int len1=strlen(str1),len2=strlen(str2);
    for(int i=0,j=len1-1; i<len1; i++,j--)
        a[i]=str1[j]-'0';
    for(int i=0,j=len2-1; i<len2; i++,j--)
        b[i]=str2[j]-'0';
    int l=0;
    while(l<=len1)
    {
        c[l]=a[l]-b[l];
        if(c[l]<0)
        {
            c[l]+=10;
            a[l+1]--;
        }
        l++;
    }
    while(c[l]==0&&l>=0)//除去前置0
        l--;
    if(l==-1)
        printf("0");
    else
    {
        if(flog)///减数比被减数大,答案为负数
            printf("-");
        for(int i=l; i>=0; i--)
            printf("%d",c[i]);
    }
    printf("\n");
}
int main()
{
    char str1[maxn],str2[maxn];
    while(scanf("%s%s",str1,str2)!=EOF)
    {
        int l1=strlen(str1),l2=strlen(str2);
        if(l1==l2&&strcmp(str1,str2)<0)//减数比被减数大
            jianfa(str2,str1,1);
        else if(l1<l2)//减数比被减数大
            jianfa(str2,str1,1);
        else
            jianfa(str1,str2,0);
    }
    return 0;
}

Java代码:

import java.math.BigInteger;
import java.util.Scanner;
 
public class mian {
 
    private static Scanner cin;
    public static void main(String[] args) {
        cin=new Scanner(System.in);
        while(cin.hasNext()) {
        BigInteger a,b,sum;
        a=cin.nextBigInteger();
        b=cin.nextBigInteger();
        sum=a.subtract(b);
        System.out.println(sum);
        }
    }
}

 

 高精度乘法:高精度最简单的运算了吧。

既然是一个很大的整数,我们便不能够再用简单的数据类型直接储存这些整数。我们可以自然得想到要通过数组或字符串来储存数字。字符串的特点方便我们对于高位整数的输入,而整形数组的简便性更有利于每个位数的计算,因而我们结合两者的优点,不难得出高精度乘法的大致流程:
a、通过两个字符串输入两个整数; 

char str1[maxn], str2[maxn];
    scanf("%s%s", str1, str2);

b、引人两个数组,将两个整数通过一定的运算,分别将每一位的数字储存进数组中;

int n = strlen(str1), m = strlen(str2);
    int a[maxn], b[maxn],c[maxn];
    for (int i = 0, j = n - 1; i < n; i++, j--)
        a[i] = str1[j] - '0';
    for (int i = 0, j = m - 1; i < m; i++, j--)
        b[i] = str2[j] - '0';

c、进行每一位的运算;

我们再声明一个数组c来储存答案。大家通过一个简单的乘法运算进行模拟就可以看出,以同样的储存规则,a[0] * b[0] = c[0]; a[0] * b[1] + a[1] * b[0] = c[1];逐渐我们可以发现规律: "c[i + j] += a[i] * b[j]"同过一个循环去实现,就可以把c[i + j]计算出来,需要指出的是,这里的计算我们还没有进行进位处理。

          1   2   3

  *       5   6   7

  *--------------------------

          7   14  21

      6   12  18

 5   10   15   

*--------------------------

 5   16   34  32  21

for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            c[i + j] += a[i] * b[j];

d、处理进位;

for (int i = 0; i < n + m; i++)
        if (c[i] >= 10)
        {
            c[i + 1] += c[i] / 10;
            c[i] %= 10;
        }

e、输出结果;

int l=maxn-1;
    while(!c[l])
        l--;
    for (int i = l; i >= 0; i--)
        printf("%d", c[i]);
    printf("\n");

 整体代码:

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=1e4+10;
const int mod=1e9+7;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;
int main()
{
    char str1[maxn], str2[maxn];
    scanf("%s%s", str1, str2);
    int n = strlen(str1), m = strlen(str2);
    int a[maxn], b[maxn],c[maxn];
    for (int i = 0, j = n - 1; i < n; i++, j--)
        a[i] = str1[j] - '0';
    for (int i = 0, j = m - 1; i < m; i++, j--)
        b[i] = str2[j] - '0';
    memset(c,0,sizeof(c));
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            c[i + j] += a[i] * b[j];
    for (int i = 0; i < n + m; i++)
        if (c[i] >= 10)
        {
            c[i + 1] += c[i] / 10;
            c[i] %= 10;
        }
    int l=maxn-1;
    while(!c[l])
        l--;
    for (int i = l; i >= 0; i--)
        printf("%d", c[i]);
    printf("\n");
    return 0;
}

Java代码:

import java.math.BigInteger;
import java.util.Scanner;
 
public class mian {
 
    private static Scanner cin;
    public static void main(String[] args) {
        cin=new Scanner(System.in);
        while(cin.hasNext()) {
        BigInteger a,b,sum;
        a=cin.nextBigInteger();
        b=cin.nextBigInteger();
        sum=a.multiply(b);
        System.out.println(sum);
        }
    }
}

 高精度除法:高精度算法中最难理解的算法。

大数除法,应该算是四则运算里面最难的一种了。不同于一般的模拟,除法操作步数模仿手工除法,而是利用减法操作实现的。

其基本思想是反复做除法,看从被除数里面最多能减去多少个除数,商就是多少。

逐个减显然太慢,要判断一次最多能减少多少个整的10的n次方。

以7546除23为例。

先减去23的100倍,就是2300,可以减3次,余下646。   此时商就是300;

然后646减去23的10倍,就是230,可以减2次,余下186。此时商就是320;

然后186减去23,可以减8次,此时商就是328.

a、通过两个字符串输入两个整数;

scanf("%s %s", str1, str2);
    int l1 = strlen(str1), l2 = strlen(str2);///获得大数的位数

b、进行每一位的运算;

void SubStract(int len) {
    int i = 0;
    while (str1[i] == '0')///查找现在减到哪一位了
        i++;
    int j = i;
    for (; i < len; i++)
        str1[i] = str1[i] - str2[i] + '0';///分别将每一位的数字储存进数组中
    for (i = len - 1; i > j; i--) {
        if (str1[i] < '0')///若该位<0,则需要借位
            str1[i] += 10, str1[i - 1]--;
    }
}

f、输出结果;

int l=maxn-1;
        while(!num_c[l])
            l--;
        for(int i=l; i>=0; i-- )
            printf("%d", num_c[i]);
        printf("\n");

 整体代码:

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

using namespace std;
const int maxn = 1e3 + 5;
char str1[maxn], str2[maxn];
int a[maxn];

void SubStract(int len) {
    int i = 0;
    while (str1[i] == '0')///查找现在减到哪一位了
        i++;
    int j = i;
    for (; i < len; i++)
        str1[i] = str1[i] - str2[i] + '0';///分别将每一位的数字储存进数组中
    for (i = len - 1; i > j; i--) {
        if (str1[i] < '0')///若该位<0,则需要借位
            str1[i] += 10, str1[i - 1]--;
    }
}

int main() {
    while (scanf("%s %s", str1, str2) != EOF) {
        int l1 = strlen(str1), l2 = strlen(str2);///获得大数的位数
        if (l1 < l2 || (l1 == l2 && strcmp(str1, str2) < 0)) {///如果被除数小于除数,结果为0
            printf("0\n");
            continue;
        }
        int k = 0;
        while (true) {
            a[k] = 0;
            while (strcmp(str1, str2) >= 0) {
                SubStract(l2), a[k]++;///每成功减一次,将商的相应位加1
            }
            k++;
            if (l1 == l2)///减完了 直接跳出
                break;
            for (int i = l2 - 1; i >= 0; i--)
                str2[i + 1] = str2[i];
            str2[0] = '0', l2++, str2[l2] = '\0';
        }
        int i = 0;
        while (a[i] == 0)
            i++;
        for (; i < k; i++)
            printf("%d", a[i]);
        printf("\n");
    }
    return 0;
}

Java代码:

import java.math.BigInteger;
import java.util.Scanner;
 
public class mian {
 
    private static Scanner cin;
    public static void main(String[] args) {
        cin=new Scanner(System.in);
        while(cin.hasNext()) {
        BigInteger a,b,sum;
        a=cin.nextBigInteger();
        b=cin.nextBigInteger();
        sum=a.divide(b);
        System.out.println(sum);
        }
    }
}

 

 高精度取余:高精度中代码最短的算法。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e4;
int main()
{
    char str[maxn];
    int mod;
    scanf("%s%d",str,&mod);
    int ans=0;
    for(int i=0;i<strlen(str);i++)
        ans=(ans*10+str[i]-'0')%mod;
    printf("%d\n",ans);
    return 0;
}

Java代码:

import java.math.BigInteger;
import java.util.Scanner;
 
public class mian {
 
    private static Scanner cin;
    public static void main(String[] args) {
        cin=new Scanner(System.in);
        while(cin.hasNext()) {
        BigInteger a,b,sum;
        a=cin.nextBigInteger();
        b=cin.nextBigInteger();
        sum=a.remainder(b);
        System.out.println(sum);
        }
    }
}

 

高精度算法例题:

HDU 1002 A - A + B Problem II

题解:模板高精度加法。

#include<stdio.h>
#include<cstring>

int main() {
    char str1[10000], str2[10000];
    int a[10000], b[10000], c[10000];
    int  t, k = 0;
    scanf("%d", &t);
    for (int s = 1; s <= t; s++) {
        scanf("%s %s", str1, str2);
        if (k++)
            printf("\n");
        memset(a, 0, sizeof(a));
        memset(b, 0, sizeof(b));
        memset(c, 0, sizeof(c));
        int l1 = strlen(str1), l2 = strlen(str2);
        for (int i = 0; i < l1; i++)
            a[l1 - i] = str1[i] - '0';
        for (int i = 0; i < l2; i++)
            b[l2 - i] = str2[i] - '0';
        int l = 1, x = 0;
        while (l <= l1 || l <= l2) {
            c[l] = a[l] + b[l] + x;
            x = c[l] / 10;
            c[l] %= 10;
            l++;
        }
        c[l] = x;
        printf("Case %d:\n", s);
        printf("%s + %s = ", str1, str2);
        while (c[l] == 0 && l > 0)
            l--;
        if (l == 0)
            printf("0");
        else
            for (; l > 0; l--)
                printf("%d", c[l]);
        printf("\n");
    }
    return 0;
}

 

HDU1047 Integer Inquiry

题意:让你加n个大数,直到输入0为止,主要运用高精度加法。

#include<iostream>
#include<cstring>

using namespace std;
char str[100][1000];
int a[100][1000], b[1000];

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        int n = 0;
        memset(a, 0, sizeof(a));
        memset(b, 0, sizeof(b));
        while (scanf("%s", str[++n]) && str[n][0] != '0');
        int len, max = 0;
        for (int i = 1; i <= n; i++) {
            len = strlen(str[i]);
            for (int j = 0; j < len; j++)
                a[i][len - j] = str[i][j] - '0';
            if (len > max)
                max = len;
        }
        int l = 1;
        while (l <= max) {
            for (int i = 0; i < n; i++)
                b[l] += a[i][l];
            b[l + 1] += b[l] / 10;
            b[l] %= 10;
            l++;
        }
        while (b[l] == 0 && l > 0)
            l--;
        if (l == 0)
            printf("0");
        else
            for (; l > 0; l--)
                printf("%d", b[l]);
        printf("\n");
        if (t)
            printf("\n");
    }
    return 0;
}

 

HDU 1250 Hat's Fibonacci 

题解:大数加法,但是数组每个位存一个数可能会超时间或超内存,所以使用较大的进制。

#include<stdio.h>

int a[8000][300] = {0};

int main() {
    for (int i = 1; i < 5; i++)
        a[i][1] = 1;
    for (int i = 5; i < 8000; i++) {
        for (int j = 1; j < 255; j++) {
            a[i][j] += a[i - 1][j] + a[i - 2][j] + a[i - 3][j] + a[i - 4][j];
            a[i][j + 1] += a[i][j] / 100000000;
            a[i][j] %= 100000000;
        }
    }
    int n;
    while (scanf("%d", &n) != EOF) {
        int l = 255;
        while (a[n][l] == 0)
            l--;
        printf("%d", a[n][l]);//最前面的数不够8位直接输出
        for (--l; l > 0; l--)
            printf("%08d", a[n][l]); //这里的%08d估计大家都不陌生了吧?就是不够8位的时候左侧使用0补够 。
        printf("\n");
    }
}

 

HDU - 1865 1sting  

题解:本题总共分两种情况:

    (1)当第n个不与n-1个相加,就以1结尾,有f(n-1)种情况。

    (2):第n个1加上第n-1个1,就有发(n-2)种情况以2结尾。

#include<stdio.h>
#include<cstring>

int a[205][255] = {0};

int main() {
    a[1][1] = 1, a[2][1] = 2;
    for (int i = 3; i < 205; i++) {
        for (int j = 1; j < 255; j++) {
            a[i][j] += a[i - 1][j] + a[i - 2][j];
            a[i][j + 1] += a[i][j] / 100000000;
            a[i][j] %= 100000000;
        }
    }
    int n;
    scanf("%d", &n);
    while (n--) {
        char str[300];
        scanf("%s", str);
        int s = strlen(str);
        int l = 251;
        while (a[s][l] == 0)
            l--;
        printf("%d", a[s][l]);
        for (--l; l > 0; l--)
            printf("%08d", a[s][l]);
        printf("\n");
    }
}