高精度计算-大整数加减法

问题描述

求两个不超过 200 位的非负整数的和。

输入数据

有两行,每行是一个不超过 200 位的非负整数,没有多余的前导 0。

输出要求

一行,即相加后的结果。结果里不能有多余的前导 0,即如果结果是 342,那么就不能

输出为 0342。

输入样例

22222222222222222222

33333333333333333333

输出样例

Output Sample:

55555555555555555555

解题思路

C/C++中的 int 类型能表示的范围是[?231,?231–1]。

unsigned 类型能表示的范围是 [0,232?1]。所以,int 和 unsigned 类型变量,都不能保存超过 10 位的整数。( 10x<=232?1,x<=9.63)。参与运算的数如果大于10位数,基本数据类型已经无法表示。基本思想是:用数组模拟大整数,一个数组元素,放一位整数。不过一个数组元素存一位,空间上有点浪费,那么节省空间,可以一个数组存多位,比如说4位,注意的是进位的时候,这个时候的进位不再是10,而是10000。

代码实现

基本方法

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAX_LEN 200
int x[MAX_LEN + 20], y[MAX_LEN + 20], z[MAX_LEN + 20];
char a[MAX_LEN + 20], b[MAX_LEN + 20];

void char_to_int(const char s[ ], int x[ ])
{
    int i = 0;
    int len = strlen(s);

    memset(x,0,MAX_LEN + 20);
    int j  = 0;
    for(i = len - 1; i >= 0; i--)
    {
        x[j++] = s[i] - ‘0‘;
    }
}

void big_int_add(const int x[], const int y[], int z[])
{
    int i = 0;
    memset(z,0,MAX_LEN + 20);  

    for(i = 0; i < MAX_LEN; i++)
    {
        z[i] += x[i] + y[i];
        if(z[i] >=10)
        {
            z[i] = z[i] - 10;
            z[i+1] ++;
        }
    }
}

void big_int_print(const int z[])
{
    bool flag = 0;
    int i = 0;

    for(i = MAX_LEN; i >=0; i--)
    {
        if(flag)
            printf("%d",z[i]);
        else if(z[i])
        {
            printf("%d",z[i]);
            flag = 1;
        }
    }

    if(!flag)
        printf("0");
    printf("\n");
}

int main( )
{
    scanf("%s",a);
    scanf("%s",b);

    char_to_int(a,x);
    char_to_int(b,y);

    big_int_add(x,y,z);

    big_int_print(z);

    return 0;

}

方法二

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define Radix_Len  4
#define  Carry_num  10000
#define MAX_LEN  (200 / Radix_Len + 1)
int x[MAX_LEN], y[MAX_LEN], z[MAX_LEN + 1];
char a[MAX_LEN ], b[MAX_LEN ];

void char_to_int(const char s[ ], int x[])
{
    int i = 0;
    int len = strlen(s);

    memset(x,0,MAX_LEN);
    int j  = 0;
    for(i = len; i > 0; i -= Radix_Len)
    {
        int tmp , k ;
        tmp = 0;
        const int low = i - Radix_Len > 0 ? i - Radix_Len : 0;
        for(k = low; k < i; k++)
            tmp = tmp * 10 + ( s[k] - ‘0‘);
        x[j++] = tmp;
    }
}

void big_int_add(const int x[], const int y[], int z[])
{
    int i = 0;
    memset(z,0,MAX_LEN);  

    for(i = 0; i < MAX_LEN; i++)
    {
        z[i] += x[i] + y[i];
        if(z[i] >=Carry_num)
        {
            z[i] = z[i] - Carry_num;
            z[i+1] ++;
        }
    }
}

void big_int_print(const int z[])
{
    bool flag = 0;
    int i = 0;

    for(i = MAX_LEN; i >=0; i--)
    {
        if(flag)
            printf("%d",z[i]);
        else if(z[i])
        {
            printf("%d",z[i]);
            flag = 1;
        }
    }

    if(!flag)
        printf("0");
    printf("\n");
}

int main( )
{
    scanf("%s",a);
    scanf("%s",b);

    char_to_int(a,x);
    char_to_int(b,y);

    big_int_add(x,y,z);

    big_int_print(z);

    return 0;

}

题目来自 OpenJudge 百练 http://bailian.openjudge.cn/practice/2981/

大整数减法

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAX_LEN 200
int x[MAX_LEN + 20], y[MAX_LEN + 20], z[MAX_LEN + 20];
char a[MAX_LEN + 20], b[MAX_LEN + 20];

void char_to_int(const char s[ ], int x[ ])
{
    int i = 0;
    int len = strlen(s);

    memset(x,0,MAX_LEN + 20);
    int j  = 0;
    for(i = len - 1; i >= 0; i--)
    {
        x[j++] = s[i] - ‘0‘;
    }
}

void big_int_add(const int x[], const int y[], int z[], int max_len)
{
    int i = 0;
    memset(z,0,MAX_LEN + 20);  

    int exchange = 0;

    printf("%d %d\n",x[max_len - 1],y[max_len - 1]);

    if(x[max_len - 1 ] < y[max_len - 1])
    {
        exchange = 1;
        printf("-");
    }
    for(i = 0; i < MAX_LEN; i++)
    {
        if(exchange)
        {
            z[i] += y[i] - x[i];
        }
        else
        {
            z[i] += x[i] - y[i];
        }

        if(z[i] < 0)
        {
            z[i] = z[i] + 10;
            z[i+1] --;
        }
    }
}

void big_int_print(const int z[])
{
    bool flag = 0;
    int i = 0;

    for(i = MAX_LEN; i >=0; i--)
    {
        if(flag)
            printf("%d",z[i]);
        else if(z[i])
        {
            printf("%d",z[i]);
            flag = 1;
        }
    }

    if(!flag)
        printf("0");
    printf("\n");
}

int main( )
{
    scanf("%s",a);
    scanf("%s",b);

    int max_len = 0;
    int len1  = strlen(a);
    int len2  = strlen(b);

              max_len = len1 > len2 ? len1: len2;

    char_to_int(a,x);
    char_to_int(b,y);

    big_int_add(x,y,z,max_len);

    big_int_print(z);

    return 0;

}
时间: 2024-10-03 22:25:05

高精度计算-大整数加减法的相关文章

高精度计算-大整数除法

问题描述 求两个大的正整数相除的商 输入数据 第 1 行是测试数据的组数 n,每组测试数据占 2 行,第 1 行是被除数,第 2 行是除数. 每组测试数据之间有一个空行,每行数据不超过 100 个字符 输出要求 n 行,每组测试数据有一行输出是相应的整数商 解题思路 基本的思想是反复做减法,看看从被除数里最多能减去多少个除数,商就是多少.一个一个减显然太慢,如何减得更快一些呢?以 7546 除以 23 为例来看一下:开始商为 0.先减去 23 的 100 倍,就是 2300,发现够减 3 次,余

高精度计算-大整数乘法

大整数乘法 问题描述 求两个不超过 200 位的非负整数的积. 输入数据 有两行,每行是一个不超过 200 位的非负整数,没有多余的前导 0. 输出要求 一行,即相乘后的结果.结果里不能有多余的前导 0,即如果结果是 342,那么就不能 输出为 0342. 输入样例 12345678900 98765432100 输出样例 1219326311126352690000 解题思路 乘法规律,一个数的第i位和另一个数的第j位相乘,一定会累加到结果的第i+j位,结果的数组一个数组元素存2位数,最后对结

高精度计算(一):大整数加法

C/C++中的int 类型能表示的范围是-231~231 – 1.unsigned 类型能表示的范围是 0 ~232 – 1,即 0~4294967295.所以,int 和unsigned 类型变量,都不能保存超过10 位的整数.有时我们需要参与运算的数,可能会远远不止10 位,例如要求100!的精确值.即便使用能表示的很大数值范围的double 变量,但是由于double变量只有64 位,double 变量的精度也不足以表示一个超过100 位的整数.一般我们称这种基本数据类型无法表示的整数为大

高精度计算(四):大整数乘法(采用“万进制”)

[例1]大整数乘法. 编写一个程序,求两个不超过200 位的非负整数的积. (1)编程思路. 大整数乘大整数,实质就是在小学竖式乘法的基础上枚举各个乘数位与被乘数相乘,累加到结果当中.其中乘数中的第j位与被乘数中的第i位相乘时,结果应该保存到结果的第i+j-1位中. (2)源程序. #include <iostream>using namespace std;const int base=10000;const int maxlen=50+2;void charTobignum(char *c

自己动手写Java大整数《3》除法和十进制转换

之前已经完成了大整数的表示.绝对值的比较大小.取负值.加减法运算以及乘法运算.具体见前两篇博客(自己动手写Java * ). 这里添加除法运算. 另外看到作者Pauls Gedanken在blog(http://paul-ebermann.tumblr.com/post/6312290327/big-numbers-selfmade-part-2-14-conversion-from)中的转换十进制数到大整数的方法,这里一并列出. 除法 除法使用经典的除法法则,但是有几个需要注意的问题,下面列出

整数平方根:整数开方及大整数开方解决方法

求整数N的开方,精度在0.001 二分法 若N大于1,则从[1, N]开始,low = 1, high = N, mid = low + (high - low) >> 1开始进行数值逼近 若N小于1,则从[N, 1]开始,low = 0, high = N, mid = low + (high - low) >> 1开始进行数值逼近 #include <stdio.h> #include <stdlib.h> #include <math.h>

关于大整数的加减乘除求余运算 java

自己用java 实现了大字符串整数的加减乘除和求余运算, 加减法的算法是模拟手工笔算的计算过程, 除法就是从最高位不停的减操作, 乘法的算法 :遍历一个数的各个位数以及他所在位置,另一个数根据这个数的位置末位添n个0,然后累加次数为这个位置数的数值 原创代码如下: public class Demo6 { public static void main(String[]args){ System.out.println(add("-989","989")); Sys

大整数算法[08] 有符号加法和减法

★ 引子 前面几篇文章介绍了比较操作,绝对值加法和绝对值减法,现在就可以利用这几个算法构建有符号数的加减算法. ★ 有符号数加法            有符号数的加法分成两种情况:同号和异号. 1.  如果两个数同号,则执行绝对值加法,如果两个数为非负数,则结果为非负数:如果两个数都是负数,则结果也为负数. 2.  如果两个数异号,则要执行绝对值减法,用绝对值较大的数去减绝对值较小的数.最终结果 z 的符号由 x 和 y 的绝对值大小决定:如果 x 的绝对值大于或等于 y,则 z 的符号与 x

自己动手写Java大整数《4》扩展欧几里得和Mod逆

/* *我把这个大整数的系列写成了Code中的项目,见https://code.csdn.net/XUE_HAIyang/bignumber */ 之前已经完成了大整数的表示.绝对值的比较大小.取负值.加减法运算.乘法运算以及除法和余数运算.具体见我的主页前三篇博客(自己动手写Java系列 ). 这篇博客添加求大整数GCD.扩展欧几里得算法和求Mod逆的算法. 扩展欧几里得算法 说道扩展的欧几里得算法,首先我们看下简单的欧几里得算法.经典的欧几里得算法就是 计算两个整数的最大公因子的算法,所基于