大數的計算

這類問題的相同之處在於,數的大小超出了原生數據類型所能表示的範圍。如果用Python或者Java,就不必再看下去了。。。。。。

大數的模冪運算

給定x和y,求x的y次冪模k的餘數

unsigned int quick_power_mod(unsigned int x, unsigned int y, unsigned int k)
{
    unsigned int res = 1;
    x %= k;
    while(y != 0)
    {
        if(y & 1)
        {
            res = (res * x) % k;
        }
        y >>= 1;
        x = (x * x) % k;
    }
    return res;
}

這種做法的道理如下,指數y的二進制表示爲:

y=a020+a121+a222++an2n,ai{0,1}

那麼

xy=xa020+a121+a222++an2n=xa020xa121xa222xan2n,ai{0,1}

又因爲模運算有如下性質

(ab)modc=((amodc)(bmodc))modc

於是我們有

xymodk=((xa020modk)(xa121modk)(xa222modk)(xan2nmodk))modk,ai{0,1}

該算法即在按照上式從左到右一項一項的計算。體現爲,遍歷y的每一個二進制位,如果該位爲1,將當前的計算結果乘以當前x的值並求餘,如果該位爲0,則不乘或者說乘以1;每遍歷y的一位,將x做一次平方,對應着上式中依次乘2的x的指數。

大數的進制轉換

給定a進制的數x(字符串形式),轉換爲b進制的數y

// big-endian for input
// small-endian for output
unsigned int convert_base(std::vector<unsigned int> &from_num, std::vector<unsigned int> &to_num, unsigned int from_base, unsigned int to_base)
{
    for(int i = 0; i < from_num.size(); )
    {
        int carry = 0;
        for(int j = i; j < from_num.size(); j++)
        {
            int tmp = (from_num[j] + carry * from_base) % to_base;
            from_num[j] = (from_num[j] + carry * from_base) / to_base;
            carry = tmp;
        }
        to_num.push_back(carry);
        while(from_num[i] == 0)
        {
            i++;
        }
    }
}

此處使用的是除k取餘法,輸入的vector也被改變了,用來存儲每步計算的商。

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