簡體   English   中英

64位定點乘法錯誤

[英]64-bit fixed-point multiplication error

我正在C#中基於long實現64位定點帶符號的31.32數字類型。 到目前為止,對於加法和減法都很好。 但是,乘法有一個令人煩惱的案例,我正在嘗試解決。

我當前的算法包括將每個操作數分成最高和最低有效32位,對4個long執行4次乘法,然后將這些long的相關位相加。 它在代碼中:

public static Fix64 operator *(Fix64 x, Fix64 y) {

    var xl = x.m_rawValue; // underlying long of x
    var yl = y.m_rawValue; // underlying long of y

    var xlow = xl & 0x00000000FFFFFFFF; // take the 32 lowest bits of x
    var xhigh = xl >> 32; // take the 32 highest bits of x
    var ylow = yl & 0x00000000FFFFFFFF; // take the 32 lowest bits of y
    var yhigh = yl >> 32; // take the 32 highest bits of y

    // perform multiplications
    var lowlow = xlow * ylow;
    var lowhigh = xlow * yhigh;
    var highlow = xhigh * ylow;
    var highhigh = xhigh * yhigh;

    // take the highest bits of lowlow and the lowest of highhigh
    var loResult = lowlow >> 32;
    var midResult1 = lowhigh;
    var midResult2 = highlow;
    var hiResult = highhigh << 32;

    // add everything together and build result
    var finalResult = loResult + midResult1 + midResult2 + hiResult;
    return new Fix64(finalResult); // this constructor just copies the parameter into m_rawValue
}

在一般情況下,此方法有效,但在許多情況下均失敗。 即,對於操作數的值非常小或很大,結果通常相差1.0(十進制值)。 這是我的單元測試的一些結果(FromRaw()是一種直接從長值構建Fix64而不移位的方法):

Failed for FromRaw(-1) * FromRaw(-1): expected 0 but got -1
Failed for FromRaw(-4) * FromRaw(6791302811978701836): expected -1.4726290525868535041809082031 but got -2,4726290525868535041809082031
Failed for FromRaw(2265950765) * FromRaw(17179869183): expected 2.1103311001788824796676635742 but got 1,1103311001788824796676635742

我試圖在紙上弄清楚這一點的邏輯,但我有些困惑。 我怎樣才能解決這個問題?

該算法看起來不錯,並且可以“在紙上”解決,而且看起來很正確。 這是我針對FromRaw(2265950765) * FromRaw(17179869183) (0.52758277510292828083038330078125 * 3.99999999976716935634613037109375 = 2.11033110017888247966766357421875)制定的筆記

x1 = 2265950765
y1 = 17179869183

xlow = 2265950765
xhigh = 0
ylow = 4294967295
yhigh = 3

lowlow = 9732184427755230675
lowhigh = 6797852295
highlow = 0
highhigh = 0

loResult = 2265950764
midResult1 = 6797852295
midResult2 = 0
hiResult = 0

finalResult = 9063803059

現在,這里是我懷疑正在發生的事情: lowlow 需要ulong的結果出來的權利,但我認為,你得到是一個符號值。 解釋為簽署, lowlow最終被-8714559645954320941(過低除以2 ^ 64), loResult最終被-2029016532(過低由2 ^ 32), finalResult結束是4768835763 (也太低除以2 ^ 32),和則得出的值為1.1103311001788824796676635742121875,比您的預期小1。

通常,應將您的值視為帶符號的“上半部”和無符號的“下半部”。 highhigh是帶符號的*帶符號的=帶符號的; lowhighhighlow是帶符號的* unsigned =帶符號的; 但是lowlow是無符號的* unsigned =無符號的。

我不明白,為什么FromRaw(-1) * FromRaw(-1)應該返回0 它應該返回+1

通常關於算法:不要拆分,只需乘以long s。

假設您乘以2.3*4.5 您將得到10.35 但是,如果乘以23*45 ,將得到1035

數字是一樣的!

因此,要乘以數字,應乘以m_rawValue ,然后向右移位。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM