大数算法

简介:在计算机中数字表示的范围是有限制的,比如我们熟知的 int、float、double 等数据类型所能表示的范围都是有限的,如果我们要对位数达到几十位、几百位、上千位的大整数进行计算,这些数据类型显然不能满足我们的要求,因此我们需要通过算法来实现这些功能。

大数减法:
相减算法也是从低位开始减的。先要判断被减数和减数哪一个位数长,若被减数位数长是正常的减法;若减数位数长,则用被减数减去减数,最后还要加上负号;当两数位数长度相等时,最好比较哪一个数字大,否则负号处理会很繁琐;处理每一项时要,如果前一位相减有借位,就先减去上一位的借位,无则不减,再去判断是否能够减开被减数,如果减不开,就要借位后再去减,同时置借位为1,否则置借位为0。

#include<stdio.h>
#include<string.h>
#define MAX 1000    // 大数的最大位数 
/*
  大数减法 
  参数: 
  num1为被减数,用字符数组保存
  num2为减数 
  sum数组保存相减的结果   即:num1-num2=sum
  返回值:返回数组sum的有效长度,即计算结果的位数 
 */
int Subtraction(char num1[], char num2[], int sum[])
{
    int i, j, len, blag;
    char *temp;
    int n2[MAX] = {0};
    int len1 = strlen(num1); // 计算数组num1的长度,即大数的位数 
    int len2 = strlen(num2); // 计算数组num2的长度,即大数的位数
    
    // 在进行减法之前要进行一些预处理 
    blag = 0; // 为0表示结果是正整数,为1表示结果是负整数 
    if(len1 < len2) // 如果被减数位数小于减数
    {
        blag = 1; // 标记结果为负数
        // 交换两个数,便于计算 
        temp = num1;
        num1 = num2;
        num2 = temp;
        len = len1;
        len1 = len2;
        len2 = len;
    }
    else if(len1 ==len2) // 如果被减数的位数等于减数的位数
    {  
        // 判断哪个数大 
        for(i = 0; i < len1; i++)
        {
            if(num1[i] == num2[i])
                continue;
            if(num1[i] > num2[i])
            {
                blag = 0; // 标记结果为正数 
                break;
            } 
            else
            {
                blag = 1; // 标记结果为负数 
                // 交换两个数,便于计算 
                temp = num1;
                num1 = num2;
                num2 = temp;
                break;
            } 
        } 
    }
    len = len1>len2 ? len1 : len2; // 获取较大的位数
    //将num1字符数组的数字转换为整型数且逆向保存在整型数组sum中,即低位在前,高位在后
    for (i = len1-1, j = 0; i >= 0; i--, j++) 
        sum[j] = num1[i] - '0';
    // 转换第二个数 
    for (i = len2-1, j = 0; i >= 0; i--, j++)
        n2[j] = num2[i] - '0';
    // 将两个大数相减 
    for (i = 0; i <= len; i++)
    {
        sum[i] = sum[i] - n2[i]; // 两个数从低位开始相减 
        if (sum[i] < 0)   // 判断是否有借位 
        {    // 借位 
            sum[i] += 10;
            sum[i+1]--;
        }
    }
    // 计算结果长度 
    for (i = len1-1; i>=0 && sum[i] == 0; i--);
    len = i+1;
    if(blag==1)
    {
        sum[len] = -1;  // 在高位添加一个-1表示负数 
        len++;
    }
    return len;   // 返回结果的位数 
}

int main()
{
    int i, len;
    int sum[MAX] = {0}; // 存放计算的结果,低位在前,高位在后,即sum[0]是低位 
    char num1[] = "987654321987654321"; // 第一个大数 
    char num2[] = "123456789123456789"; // 第二个大数 
    len = Subtraction(num1, num2, sum);    // 两数相减 
    // 输出结果
    printf("%s\n  -\n%s\n  =\n", num1, num2);
    if(sum[i=len-1] < 0) // 根据高位是否是-1判断是否是负数
    {
        printf("-"); // 输出负号
        i--;
    }
    for (; i >= 0; i--)
        printf("%d", sum[i]);
    printf("\n"); 
    return 0;
}

在这里插入图片描述
大数加法:
两个大数我们可以用数组来保存,然后在数组中逐位进行相加,再判断该位相加后是否需要进位,为了方便计算,我们将数字的低位放在数组的前面,高位放在后面。

#include<stdio.h>
#include<string.h>
#define MAX 1000 
int addnumber(char num1[], char num2[], int sum[]){
	int i, j, len, blag;
    char *temp;
    int n2[MAX] = {0};
    int len1 = strlen(num1); // 计算数组num1的长度,即大数的位数 
    int len2 = strlen(num2); // 计算数组num2的长度,即大数的位数
    len = len1>len2 ? len1 : len2; // 获取较大的位数
    //将num1字符数组的数字字符转换为整型数字,且逆向保存在整型数组sum中,即低位在前,高位在后
    for (i = len1-1, j = 0; i >= 0; i--, j++) 
        sum[j] = num1[i] - '0';
    // 转换第二个数 
    for (i = len2-1, j = 0; i >= 0; i--, j++)
        n2[j] = num2[i] - '0';
    // 将两个大数相加 
    for (i = 0; i <= len; i++)
    {
        sum[i] += n2[i];  // 两个数从低位开始相加 
        if (sum[i] > 9)   // 判断是否有进位 
        {   // 进位 
            sum[i] -= 10;
            sum[i+1]++;
        }
    }
    if(sum[len] != 0)  // 判断最高位是否有进位 
        len++;
    return len;   // 返回和的位数 
}
int main(){
	int i, len;
    int sum[MAX] = {0}; // 存放计算的结果,低位在前,高位在后,即sum[0]是低位 
    char num1[] = "1234567891234567891234"; // 第一个大数 
    char num2[] = "2345678912345678913345"; // 第二个大数 
    len = addnumber(num1, num2, sum);    // 两数相加 
    printf("%s\n  +\n%s\n  =\n", num1, num2);
    // 反向输出求和结果
    for (i = len-1; i >= 0; i--)
        printf("%d", sum[i]);
    printf("\n"); 
    return 0;
}

在这里插入图片描述
大数乘法

首先说一下乘法计算的算法,从低位向高位乘,在竖式计算中,我们是将乘数第一位与被乘数的每一位相乘,记录结果,之后,用第二位相乘,记录结果并且左移一位,以此类推,直到计算完最后一位,再将各项结果相加,得出最后结果。

计算的过程基本上和小学生列竖式做乘法相同。为了编程方便,并不急于处理进位,而是将进位问题留待最后统一处理。

总结一个规律: 即一个数的第i 位和另一个数的第j 位相乘所得的数,一定是要累加到结果的第i+j 位上。这里i, j 都是从右往左,从0 开始数。
ans[i+j] = a[i]*b[j];

另外注意进位时要处理,当前的值加上进位的值再看本位数字是否又有进位;前导清零。
#include<stdio.h>
#include<string.h>
#define MAX 1000    // 大数的最大位数  
/*
  大数乘法 
  参数: 
  num1为第一个因数,用字符数组保存
  num2为第二个因数
  sum数组保存相乘的结果  即:num1*num2=sum
  返回值:返回数组sum的有效长度,即计算结果的位数 
 */
int Multiplication(char num1[],char num2[], int sum[])
{
    int i, j, len, len1, len2;
    int a[MAX+10] = {0};
    int b[MAX+10] = {0};
    int c[MAX*2+10] = {0};

    len1 = strlen(num1);
    for(j = 0, i = len1-1; i >= 0; i--) //把数字字符转换为整型数 
        a[j++] = num1[i]-'0';
    len2 = strlen(num2);
    for(j = 0, i = len2-1; i >= 0; i--)
        b[j++] = num2[i]-'0';
    
    for(i = 0; i < len2; i++)//用第二个数乘以第一个数,每次一位 
    {
        for(j = 0; j < len1; j++)
        {
            c[i+j] += b[i] * a[j]; //先乘起来,后面统一进位
        }
    }
    
    for(i=0; i<MAX*2; i++) //循环统一处理进位问题
    {
        if(c[i]>=10)
        {
            c[i+1]+=c[i]/10;
            c[i]%=10;
        }
    }

    for(i = MAX*2; c[i]==0 && i>=0; i--); //跳过高位的0
    len = i+1; // 记录结果的长度 
    for(; i>=0; i--)
        sum[i]=c[i];
    return len; 
}

int main()
{
    int i, len;
    int sum[MAX*2+10] = {0}; // 存放计算的结果,低位在前,高位在后,即sum[0]是低位 
    char num1[] = "123456789123456789"; // 第一个大数 
    char num2[] = "123456789123456789"; // 第二个大数 
    len = Multiplication(num1, num2, sum);
    // 输出结果
    printf("%s\n  *\n%s\n  =\n", num1, num2);
    for(i = len-1; i>=0; i--)
        printf("%d", sum[i]); 
    printf("\n"); 
    return 0;
}

在这里插入图片描述
大数除法

大数除法是四则运算里面最难的一种。不同于一般的模拟,除法操作不是模仿手工除法,而是利用减法操作来实现的。其基本思想是反复做除法,看从被除数里面最多能减去多少个除数,商就是多少。逐个减显然太慢,要判断一次最多能减少多少个整数(除数)的10的n次方。

以7546除以23为例:

先用7546减去23的100倍,即减去2300,可以减3次,余下646,此时商就是300 (300=100*3);

然后646减去23的10倍,即减去230,可以减2次,余下186,此时商就是320 (320=300+10*2);

然后186减去23,可以减8次,余下2,此时商就是328 (328=320+1*8);

因为2除以23的结果小于1,而我们又不用计算小数点位,所以不必再继续算下去了。

在这里插入图片描述
使用Java提供的类

在Java中提供了BigInteger类和BigDecimal类,分别用来处理大整数和大浮点数,我们只要调用里面提供的方法就能很方便的进行大数的四则运算,具体实现可参考:http://www.cnblogs.com/wuqianling/p/5410218.html
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值