大數的乘法(包括浮點數)

一.大數乘法

我們知道,要運算兩個數的乘法,c、c++語言裏有專門的運算符*。但是當兩個數超過一定的範圍時,用普通的運算符會產生溢出,並不能得到正確的結果。如何進行運算呢?

      首先,要想保存一個大數,用正常的整形或浮點類型是不夠的。所以我們可以採用字符串的形式對大數進行保存,然後編寫算法,模擬乘法運算過程即可。

1.第一個問題:兩個數字運算結果至多用多少位的字符串保存呢?

兩個4位數相乘,最大值爲9999*9999它的位數小於10000*10000的位數9位,所以兩個數字相乘的結果至多不超過兩數位數的和

2.第二個問題:運算的過程怎麼模擬?

        比如:我們可以先進行類乘和累加,把結果保存到相應的字符裏,然後進行進位

1  2  3  4

            1  2  3

--------------------

        3  6   9  12             //一次類乘

   2  4   6   8

1 2  3  4

--------------------------

1 4 10 16 17 12             //累加  

1 5   1   7   8    2            //進位


但是,這裏會出現的問題就是,如果當兩個數的位數特別大是,先進行類乘累加,由於無符號字符能保存的最大值也只有255,後進行進位處理時,有可能字符保存的值已經溢出。所以,在進行處理時要一次類乘後進行進位,然後累加。


處理完思路後,編寫代碼會變得很輕鬆。

  1. void bignum(char *num1, char *num2)  
  2. {  
  3.     int length1 = strlen(num1);  
  4.     int length2 = strlen(num2);  
  5.     int i, l;  
  6.     char *res = (char *)malloc(sizeof(char)*(length1 + length2)); //開闢相應內存  
  7.     memset(res, 0, sizeof(char)*(length1 + length2));  
  8.     for (i = length1 - 1; i >= 0; i--)  
  9.     for (l = length2 - 1; l >= 0; l--)  
  10.     {  
  11.         res[i + l + 1] += (num1[i] - '0')*(num2[l] - '0'); 類乘完累加  
  12.         res[i + l] += res[i + l + 1] / 10;    //馬上進行進位  
  13.         res[i + l + 1] %= 10;  
  14.     }  
  15.     int count = 0;  
  16.     while (res[count] == 0)  //由於保存的結果是從右向左的,所以要消除左部分的0;  
  17.     {  
  18.         count++;  
  19.     }  
  20.     char* ret = (char *)malloc(sizeof(char)*(length1 + length2 + 2));  
  21.     memset(ret, 0, sizeof(char)*(length1 + length2 + 2));  
  22.     for (l = 0, i = count; i < length1 + length2; l++, i++)  //非0部分賦給ret  
  23.     {  
  24.         ret[l] = res[i] + '0';  
  25.     }  
  26.     printf("Ret=%s\n", ret);  
  27.     free(res);  
  28.     free(ret);  
  29. }  
  1. 結果如圖:  


二:實現浮點數。

實現浮點數相乘,其實和整數差不多。只不過先得把浮點數轉化爲整數,並記錄兩個數小數點的位數和,然後再得到的整數上加上相應的小數點即可


  1. void bignum_float(char *str1, char *str2)  
  2. {  
  3.     int length1 = strlen(str1);  
  4.     int length2 = strlen(str2);  
  5.     int flnum = -1;   //大數1的小數點位數  
  6.     int flnum2 =-1;   //數2的小數點位數  
  7.     char num1[500] = { 0 };  
  8.     char num2[500] = { 0 };  
  9.     int i, l;  
  10.     for (i=0,l=0; l < length1;i++,l++)  
  11.     {  
  12.         if (str1[l] == '.'//遇到小數點後 開始加一  
  13.         {  
  14.             flnum++;  
  15.             i--;  
  16.             continue;  
  17.         }  
  18.         if (flnum!=-1) flnum++; //統計小數點後的位數,由於會多加一次,所以初始值爲-1  
  19.         num1[i] = str1[l];  //保存到新的數組裏  
  20.     }  
  21.   
  22.     for (i = 0,l = 0; l < length2; i++, l++)  
  23.     {  
  24.         if (str2[l] == '.')  
  25.         {  
  26.             flnum2++;  
  27.             i--;  
  28.             continue;  
  29.         }  
  30.         if (flnum2!=-1) flnum2++;  
  31.         num2[i] = str2[l];  
  32.     }  
  33.     if (flnum!=-1) length1 -= 1;   //如果數字存在小數點,則轉化爲整數後對應的長度-1  
  34.     if (flnum2!=-1) length2 -= 1;  
  35.     flnum = flnum + flnum2;  
  36.     char *res = (char *)malloc(sizeof(char)*(length1 + length2));  
  37.     memset(res, 0, sizeof(char)*(length1 + length2));  
  38.     for (i = length1-1; i>=0;i--)  
  39.     for (l=length2-1; l >= 0; l--)  
  40.         {  
  41.             res[i+l+1]+=(num1[i] - '0')*(num2[l] - '0');  
  42.             res[i + l] += res[i + l + 1] / 10;  
  43.             res[i + l + 1] %= 10;  
  44.         }  
  45.     int count = 0;  
  46.     while (res[count] == 0)  
  47.     {  
  48.         count++;  
  49.     }  
  50.     char* ret =(char *)malloc(sizeof(char)*(length1 + length2+2));  
  51.     memset(ret, 0, sizeof(char)*(length1 + length2 + 2));  
  52.     for (int n=0,l = 0,i=count; i < length1 + length2; l++, i++,n++)  
  53.     {         
  54.         if (n == length1 + length2 -count-flnum)   //在結果對應的位置加上小數點  
  55.         {  
  56.             ret[l] = '.';  
  57.             i--;  
  58.             continue;  
  59.         }  
  60.         ret[l] = res[i] + '0';  
  61.     }  
  62.   
  63.     printf("Ret=%s\n",ret);  
  64.     free(res);  
  65.     free(ret);  
  66. }  

結果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章