【发布时间】:2012-12-24 22:05:19
【问题描述】:
我正在 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() 是一种直接从 long 值构建 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
我试图在纸上弄清楚这个逻辑,但我有点卡住了。我该如何解决这个问题?
【问题讨论】:
-
你在用进位位做什么?另外,我不太理解翻译..
2265950765的等效数值是多少? -
是的,进位位呢?
-
我不熟悉 C# 的整数提升规则 —
lowlow等值是 32 位的,还是 32x32 乘法会自动得出 64 位的结果? -
@hobbs:
xlow和ylow已经是long,所以两者的乘积也会是long。如果在 C# 中将两个 32 位整数相乘,则会得到 32 位结果并溢出。 -
@mellamokb xlow、ylow、xhigh 和 yhigh 是 64 位整数,其中前 32 位是 0(对于 -low)或 1(对于 -high),最后是低或高 32 x 和 y 的位。所以进位位只是溢出到未使用的高 32 位。从 long 转换为 (value * (1L > 32。基本上相同的规则适用于浮点类型,但有一些舍入和强制转换。
标签: c# math binary fixed-point