官术网_书友最值得收藏!

2.3 定點(diǎn)數(shù)的四則運(yùn)算

考慮兩個(gè)定點(diǎn)數(shù)a,b的四則運(yùn)算,它們對(duì)應(yīng)的整數(shù)分別是f(a),f(b),暫不考慮溢出等問(wèn)題。

這意味著兩個(gè)定點(diǎn)數(shù)的和/差,就是這兩個(gè)定點(diǎn)數(shù)對(duì)應(yīng)的整數(shù)的和/差表示的定點(diǎn)數(shù)。

其中,f(a)f(b)是兩個(gè)定點(diǎn)數(shù)對(duì)應(yīng)的整數(shù)的乘積,是這個(gè)乘積再除以2n得到的整數(shù)所表示的定點(diǎn)數(shù)。

其中,是兩個(gè)定點(diǎn)數(shù)對(duì)應(yīng)的整數(shù)的商,是這個(gè)商再乘以2n得到的整數(shù)所表示的定點(diǎn)數(shù)。而乘以、除以2n的運(yùn)算可以方便地通過(guò)移位操作來(lái)實(shí)現(xiàn)。

2.3.1 加法與減法

浮點(diǎn)數(shù)的加減需要先對(duì)齊階碼(相當(dāng)對(duì)齊小數(shù)點(diǎn)),然后再相加減。而定點(diǎn)數(shù)的小數(shù)點(diǎn)是對(duì)齊的,按照我們之前講的原理,可以直接使用對(duì)應(yīng)的整數(shù)的加減法。

2.3.2 乘法

浮點(diǎn)數(shù)的乘法是通過(guò)整數(shù)部分相乘、階碼相加實(shí)現(xiàn)的。

對(duì)于32位定點(diǎn)數(shù),按照前面所講的原理可以實(shí)現(xiàn)為

    std::int32_t a;
    std::int32_t b;
    std::int32_t value = (std::int64_t(a) * b) >> 10;

這里做右移44.20(64)→32.10(32)時(shí)存在數(shù)據(jù)信息丟失和溢出的可能。在使用時(shí)要注意這一點(diǎn)。

對(duì)于64位定點(diǎn)數(shù),直接將兩個(gè)定點(diǎn)數(shù)的內(nèi)部64位整數(shù)相乘,需要一個(gè)128位的整數(shù)才能完整表示結(jié)果。

對(duì)于GCC,可以使用_int128_t 128位類(lèi)型,能直接使用128位乘法。

    _int64_t value = (_int128_t(a) * b) >> 32;

而對(duì)于VC,目前還沒(méi)有128位整數(shù)類(lèi)型,可以使用intrinsic function _mull128來(lái)計(jì)算,并用兩個(gè)std::int64_t來(lái)存儲(chǔ)結(jié)果。

    std::int64_t retHigh = 0;
    std::int64_t retLow = _mul128(a, b, &retHigh);

在函數(shù)的第三個(gè)參數(shù)中傳入高64位變量的地址,即可以得出計(jì)算結(jié)果的高64位。

可以自定義簡(jiǎn)單的128位數(shù)據(jù)來(lái)存儲(chǔ)內(nèi)部64位整數(shù)相乘的完整結(jié)果。例如:

    struct Multiply128
    {
        std::uint64_t Low;
        std::int64_t High;
    }

2.3.3 除法

按照前面所講的原理,做除法運(yùn)算需要乘以232,為避免溢出需要引入128位的運(yùn)算。對(duì)于GCC可以直接使用128位整數(shù)除法:

    _int64_t value =  (_int128_t(a) << 32) / b;

但對(duì)于VC就不行了,在intrinsic function中沒(méi)有128位整數(shù)除法。但是可以用匯編代碼來(lái)實(shí)現(xiàn)。

在C++中聲明:

    extern "C" std::int64_t _Div128_64(
        std::int64_t    a_low,
        std::int64_t    a_high,
        std::int64_t    b,
        std::int64_t*   ret );

這里把a(bǔ)_low的值傳給寄存器rcx,把a(bǔ)_high的值傳給rdx,把b的值傳給r8,把ret的指針傳給r9。

用匯編代碼實(shí)現(xiàn):

    .code
    Div128_64 proc
        mov rax, rcx     ; 將a_low的值由rcx傳給rax
        idiv r8          ; rdx - rax(128位被除數(shù)) / r8(除數(shù)) = rdx(余數(shù)), rax(商)
        mov[r9], rdx     ; 通過(guò)指針傳出余數(shù)
        ret              ; 返回商
    ret;
    Div128_64 endp
    END

需要注意的是,除出來(lái)的商不能超過(guò)64位,否則CPU會(huì)報(bào)出異常。

在審稿階段,筆者發(fā)現(xiàn)最新版本的Visual Studio 2019已經(jīng)提供了128位整數(shù)除法的intrinsic function _div128(),與匯編版本的功能一致。

主站蜘蛛池模板: 收藏| 永福县| 渝北区| 黎平县| 临西县| 安塞县| 山东省| 大埔县| 正阳县| 平罗县| 乡宁县| 星座| 吉安县| 漯河市| 简阳市| 泰安市| 同江市| 大石桥市| 太谷县| 西青区| 攀枝花市| 正定县| 且末县| 龙州县| 沽源县| 电白县| 洪洞县| 东阿县| 高雄市| 阜南县| 东安县| 天祝| 岑溪市| 呈贡县| 西乌| 沙湾县| 延津县| 义马市| 郓城县| 湖南省| 林州市|