我正在 C# 中实现一个 64 位定点有符号 31.32 数字类型,基于long
。到目前为止,加法和减法都很顺利。然而,乘法有一个我正在尝试解决的恼人的情况。
我当前的算法包括将每个操作数分为最高和最低有效 32 位,执行 4 次乘法分为 4 个长整型,然后将这些长整型的相关位相加。这是代码:
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
needs成为一个ulong
为了得到正确的结果,但我认为你得到的是一个带符号的值。解释为已签署,lowlow
最终是 -8714559645954320941 (太低了 2^64),loResult
最终是 -2029016532 (太低了 2^32),finalResult
最终成为4768835763
(也太低了 2^32),结果值为 1.11033110017888247966766357421875 ,比您预期的值小 1。
一般来说,您的值应被视为具有带符号的“上半部分”和无符号的“下半部分”。highhigh
已签名 * 已签名 = 已签名;lowhigh
and highlow
已签名 * 未签名 = 已签名;但lowlow
无符号 * 无符号 = 无符号。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)