高精度計算(一):大整數加法


      C/C++中的int 類型能表示的范圍是-231~231 – 1。unsigned 類型能表示的范圍是 0 ~232

– 1,即 0~4294967295。所以,int 和unsigned 類型變量,都不能保存超過10 位的整數。
有時我們需要參與運算的數,可能會遠遠不止10 位,例如要求100!的精確值。即便使用能表示的很大數值范圍的double 變量,但是由於double變量只有64 位,double 變量的精度也不足以表示一個超過100 位的整數。一般我們稱這種基本數據類型無法表示的整數為大整數。如何表示和存放大整數呢?最簡單的思想就是:用數組存放和表示大整數。一個數組元素,存放大整數中的一位。

【例1】大整數加法。

      輸入兩個不超過200位的非負大整數a和b,求a+b的值。

      (1)編程思路。

      首先要解決的就是存儲 200 位整數的問題。顯然,任何C/C++固有類型的變量都無法保
存它。最直觀的想法是可以用一個字符串來保存它。

      由於字符串本質上是一個字符數組,因此為了編程更方便,可以用數組unsigned a[200]來保存一個200 位的整數,讓a[0]存放個位數,a[1]存放十位數,a[2]存放百位數……。
     實現兩個大整數相加的方法很簡單,就是模擬小學生列豎式做加法,從個位
開始逐位相加,超過或達到10 則進位。

      (2)源程序。

#include <stdio.h>
#include <string.h>
#define MAX_LEN 201
void bigNumAdd(char a[],char b[],char c[])
{
     int i,j,n1,n2,n;
     int num1[MAX_LEN]={0},num2[MAX_LEN]={0};
     // 將a和b中存儲的字符串形式的整數轉換到num1和num2中去,
     // num1[0]對應於個位、num1[1]對應於十位、……
     n1 = strlen(a);
     j = 0;
    for (i = n1 - 1;i >= 0 ; i --)
         num1[j++] = a[i] - '0';
    n2 = strlen(b);
    j = 0;
    for (i = n2 - 1;i >= 0 ; i --)
         num2[j++] = b[i] - '0';
    n=n1>n2?n1:n2;
    for (i = 0;i < n ; i ++ )
    {
         num1[i] += num2[i]; // 逐位相加
         if (num1[i] >= 10 ) // 處理進位
        {
             num1[i] -= 10;
             num1[i+1] ++;
        }
     }
     j=0;
     if (num1[n]!=0) c[j++]=num1[n]+'0';
     for(i=n-1; i>=0; i--)
           c[j++]=num1[i]+'0';
     c[j]='\0';
}
int main()
{
     char a[MAX_LEN],b[MAX_LEN],c[MAX_LEN+1];
     scanf("%s",a);
     scanf("%s",b);
     bigNumAdd(a,b,c);
     printf("%s\n",c);
     return 0;
}

【例2】Integer Inquiry (POJ 1503)

Description

One of the first users of BIT's new supercomputer was Chip Diller. He extended his exploration of powers of 3 to go from 0 to 333 and he explored taking various sums of those numbers.
``This supercomputer is great,'' remarked Chip. ``I only wish Timothy were here to see these results.'' (Chip moved to a new apartment, once one became available on the third floor of the Lemon Sky apartments on Third Street.)
Input

The input will consist of at most 100 lines of text, each of which contains a single VeryLongInteger. Each VeryLongInteger will be 100 or fewer characters in length, and will only contain digits (no VeryLongInteger will be negative).

The final input line will contain a single zero on a line by itself.
Output

Your program should output the sum of the VeryLongIntegers given in the input.
Sample Input

123456789012345678901234567890
123456789012345678901234567890
123456789012345678901234567890
0
Sample Output

370370367037037036703703703670

      (1)編程思路1。

      直接調用例1中設計的函數void bigNumAdd(char a[],char b[],char c[])完成。

      (2)源程序1。 

#include <stdio.h>
#include <string.h>
#define MAX_LEN 201
void bigNumAdd(char a[],char b[],char c[])
{
      int i,j,n1,n2,n;
      int num1[MAX_LEN]={0},num2[MAX_LEN]={0};
      // 將a和b中存儲的字符串形式的整數轉換到num1和num2中去,
      // num1[0]對應於個位、num1[1]對應於十位、……
      n1 = strlen(a);
      j = 0;
      for (i = n1 - 1;i >= 0 ; i --)
           num1[j++] = a[i] - '0';
      n2 = strlen(b);
      j = 0;
      for (i = n2 - 1;i >= 0 ; i --)
          num2[j++] = b[i] - '0';
      n=n1>n2?n1:n2;
      for (i = 0;i < n ; i ++ )
      {
           num1[i] += num2[i]; // 逐位相加
           if (num1[i] >= 10 ) // 處理進位
           {
                 num1[i] -= 10;
                 num1[i+1] ++;
           }
      }
      j=0;
      if (num1[n]!=0) c[j++]=num1[n]+'0';
      for(i=n-1; i>=0; i--)
           c[j++]=num1[i]+'0';
      c[j]='\0';
}
int main()
{
      char a[MAX_LEN],c[MAX_LEN]={'0'};
      scanf("%s",a);
      while (1)
     {
           if(strlen(a)==1 && a[0]=='0')
                break;
           bigNumAdd(c,a,c);
           scanf("%s",a);
      }
      printf("%s\n",c);
      return 0;
}

(3)編程思路2。

      在上面的程序中,每次調用函數都需要將被加數和加數字符串轉換成數值,還需要將計算出的和轉換成字符串。下面的程序不調用函數,直接通過循環完成多個數的累加。

(4)源程序2。

#include <stdio.h>
#include <string.h>
#define MAX_LEN 201
int main()
{
      char a[MAX_LEN];
      int sum[MAX_LEN]={0},tmp[MAX_LEN]={0};
      int i,j,n=0,n1;
      scanf("%s",a);
      while (1)
      {
          if(strlen(a)==1 && a[0]=='0')
              break;
          n1 = strlen(a);
          j = 0;
         for (i = n1 - 1;i >= 0 ; i --)
             tmp[j++] = a[i] - '0';
         if (n<n1) n=n1+1;
         for (i = 0;i < n ; i ++ )
        {
             sum[i] += tmp[i]; // 逐位相加
             if (sum[i] >= 10 ) // 處理進位
             {
                  sum[i] -= 10;
                  sum[i+1] ++;
             }
         }
         scanf("%s",a);
      }
      bool isBeginZero = false;
      for( i = n; i >= 0; i -- )
         if(isBeginZero)
             printf("%d", sum[i]);
         else if (sum[i])
        {
             printf("%d", sum[i]);
             isBeginZero = true;
         }
      if(! isBeginZero)
            printf("0");
      printf("\n");
      return 0;
}

【例3】序列(POJ 3982)

Description

數列A滿足An = An-1 + An-2 + An-3, n >= 3

編寫程序,給定A0, A1 和 A2, 計算A99
Input

輸入包含多行數據

每行數據包含3個整數A0, A1, A2 (0 <= A0, A1, A2 <= 32767)
數據以EOF結束
Output

對於輸入的每一行輸出A99的值
Sample Input

1 1 1
Sample Output

69087442470169316923566147

      (1)編程思路。

      直接調用例1中設計的函數void bigNumAdd(char a[],char b[],char c[])完成大整數的相加。

      (2)源程序。

#include <stdio.h>

#include <string.h>

#define MAX_LEN 201
void bigNumAdd(char a[],char b[],char c[])
{
      int i,j,n1,n2,n;
      int num1[MAX_LEN]={0},num2[MAX_LEN]={0};
      // 將a和b中存儲的字符串形式的整數轉換到num1和num2中去,
      // num1[0]對應於個位、num1[1]對應於十位、……
      n1 = strlen(a);
      j = 0;
      for (i = n1 - 1;i >= 0 ; i --)
            num1[j++] = a[i] - '0';
      n2 = strlen(b);
      j = 0;
      for (i = n2 - 1;i >= 0 ; i --)
      num2[j++] = b[i] - '0';
      n=n1>n2?n1:n2;
      for (i = 0;i < n ; i ++ )
      {
           num1[i] += num2[i]; // 逐位相加
           if (num1[i] >= 10 ) // 處理進位
           {
                num1[i] -= 10;
                num1[i+1] ++;
           }
      }
      j=0;
      if (num1[n]!=0) c[j++]=num1[n]+'0';
      for(i=n-1; i>=0; i--)
           c[j++]=num1[i]+'0';
      c[j]='\0';
}
int main()
{
       char a[MAX_LEN],b[MAX_LEN],c[MAX_LEN],sum[MAX_LEN];
       while (scanf("%s%s%s",a,b,c)!=EOF)
       {
            for (int i=3;i<=99;i++)
            {
                  bigNumAdd(a,b,a);
                  bigNumAdd(a,c,sum);
                  strcpy(a,b);
                  strcpy(b,c);
                  strcpy(c,sum);
            }
            printf("%s\n",sum);
       }
       return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM