[位壓] 高精度加法

這算是本BLOG的第一篇文章吧,算法這一塊荒廢了很長時間,,這份代碼剛開始寫的時候,剛輸完main時,整個人都是蒙的,不知該如何往下走。

好在成功寫完了。由於沒啥狀態,所以這個高精+功能非常簡單,只能+,不支持負數。

 

這裏說一下位壓的思想,一般的評測機都是32位的,所以一個int能儲存32位數據。

再來看一看0 ~ 9,二進制分別對應0000~1001,所以一個4位二進制正好可以存儲,所以這裏就4位存一個數字,32位正好8個。

首先來設計輸入函數:

inline bool read (int & ret, int bit) {//存到一個32位整數裏
    int c = getchar();
    if (c < '0' || c > '9') return 0;
    c = c - '0';
    c <<= (bit << 2); //bit * 4
    ret |= c;
    return 1;//該數是否讀取成功,用於while的結束
}

返回一個bool,表示當前輸入是否成功,一般返回也就代表一行輸入完了。
函數思想和快速讀入差不多,也是getchar,然後變成整數。一個int可以存8個數字,其中參數bit(新京報命名)表示存爲第幾位數字。

讀寫好了,接下來就是取,取數字的話分爲兩種:

  1. 對於一個單獨的int取數
  2. 對於一整個(高精度)數組取數

第一種比較好實現,但是會出一小點點問題:

inline void get_num (int n_arr, int bit, int & ret) {//取數字
    ret = (n_arr >> (bit << 2)) & 15;
}

 因爲我們存數字是從高位開始讀取的,高位的數字優先存儲在int中的低位
比如我輸入1234,讀取函數返回的int爲171855,二進制爲0100 0011 0010 0001,十六進制爲4321

可以看到正好反過來了,所以我們搞不清楚某一個int中到底存儲了多少個有效數字。

這種存儲方式中,1234和12340的int值是相等的,不過我們可以通過記錄每一個高精度數字的總位數來避免這種情況,理由是:

  1. 只要不是高精數的最後幾位不滿8個數的,其他高位上的int都能存儲8位整數
  2. 當某個int存儲了不到8個數時,往前(高位)的位都是全0填充

所以只要單開兩個變量存儲數字的總位數即可。

先講講第二種取數字

inline void get_arr_num(int * arr, int bit, int & ret) {//對一個高精度數字取出某一位
    -- bit;
    int a = bit / 8, b = bit - a * 8;
    get_num (arr[a], b, ret);
}

這裏數字位數是從1開始的,注意。。

參數的解釋:arr數組表示某一個高精度數,bit是取這個高精度數字的第幾位,最高位是1,依次往下。ret就是返回。。。

a代表要取的數字在第幾個數組裏,向下取整,因爲高位數字在數組中的下標更小,b表示該位數字存儲在32位int中的第幾個。

最後最後,就是main了,主函數中包含了這幾個部分:

  1. 讀入兩個高精度操作數
  2. 循環開始從這兩個數字的最低位相加,一直加到最大的那個數的最高位
  3. 保存結果,輸出

這裏直接放全部的代碼吧。。

#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;

int num_a [505];
int num_b [505];

inline bool read (int & ret, int bit) {//存到一個32位整數裏
    int c = getchar();
    if (c < '0' || c > '9') return 0;
    c = c - '0';
    c <<= (bit << 2); //bit * 4
    ret |= c;
    return 1;//該數是否讀取成功,用於while的結束
}

inline void get_num (int n_arr, int bit, int & ret) {//取數字
    ret = (n_arr >> (bit << 2)) & 15;
}

/*inline int get_num_long (int n) {//查詢一個數字中的有效數字存儲個數
    int r = 8,z = 15 << 28;
    while (!(n & z)) {
        -- r;
        z >>= 4;
    }
    return r;
}*/

inline void get_arr_num(int * arr, int bit, int & ret) {//對一個高精度數字取出某一位
    -- bit;
    int a = bit / 8, b = bit - a * 8;
    get_num (arr[a], b, ret);
}

int main () {
    int b_p = 0, l_p = 0;
    int a_l = 0, b_l = 0;
    while (read (num_a [b_p], l_p)) {//讀取數字a
        ++ l_p; a_l ++;
        if (l_p == 8) {
            l_p = 0;
            ++ b_p;
        }
    }
    b_p = 0, l_p = 0;
    while (read (num_b [b_p], l_p)) {//讀取數字b
        ++ l_p; b_l ++;
        if (l_p == 8) {
            l_p = 0;
            ++ b_p;
        }
    }

    string OP;//OutPut
    int Cin = 0;//進位
    int a, b, c;//a的某位,b的某位,c=a+b
    for (int i = a_l,j = b_l; (i > 0) | (j > 0); -- i, -- j) {//最低位開始相加
        if (i > 0) {
            get_arr_num (num_a, i, a);
        } else { //判斷是否超出最高位
            a = 0;
        }
        if (j > 0) {
            get_arr_num (num_b, j, b);
        } else {
            b = 0;
        }
        c = a + b + Cin;
        if (c >= 10) {//是否進位
            Cin = 1;
            OP = (char) (c - 10 + '0') + OP;
        } else {
            Cin = 0;
            OP = (char) (c + '0') + OP;
        }
    }
    if (Cin) cout << '1';//判斷最高位是否進位
    cout << OP;
    return 0;
}

當然,所有的思想都是自己想出來的,這份代碼也只是臨時起意,並沒有經過評測,僅供參考,如有BUG,也算正常,還請指點

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