什么是固定点的最佳乘法算法,其中需要精度

时间:2016-07-08 04:07:44

标签: c++ algorithm multiplication fixed-point

我知道,我知道,人们可能会说“只是切换到浮点”,但由于我正在研究的项目的性质,目前这不是一个选项。我正在帮助用C ++编写一种编程语言,我目前很难尝试获得一个非常精确的乘法算法,我有一个VM,主要是mod / smod,div / sdiv的操作(即签名数字不是这里的关注点),mul,一个完全分数的减半数和一个推动的移位数,我乘以并除以得到我的移位。为简单起见,假设我正在使用32字节的空间。我的算法适用于几乎涉及整数的任何事情,只是当我的小数部分超过16个字节时,我遇到精度问题,如果我要绕它,数字会相当准确,但我想要它尽可能准确,甚至愿意牺牲一点性能,只要它保持固定点并且不进入浮点土地。我关心的算法将以某种伪代码映射出来。我喜欢任何有关如何使这更好的见解,或任何推理,为什么通过计算科学的法则,我要求的是一个徒劳无功的努力。

对于完全小数(所有字节都是小数):

 A = num1 / halfShift //truncates the number down to 16 so that when multiplied, we get a full 32 byte num
 B = num2 / halfShift
 finalNum = A * B

对于大于16字节的其余数字,我使用此算法:

 this algorithm can essentially be broken down into the int.frac form
 essentially A.B * C.D taking the mathematic form of
 D*B/shift + C*A*shift + D*A + C*B
 if the fractional numbers are larger than the integer, I halve them, then multiply them together in my D*B/shift
 just like in the fully fractional example above

我应该注意某种“神奇”的舍入方法吗?请告诉我。

2 个答案:

答案 0 :(得分:2)

产品的小数位数等于操作数中小数位数的总和。您必须执行乘法到该精度,然后根据所需的目标精度进行舍入或截断。

答案 1 :(得分:2)

如果先进行乘法运算,然后按比例缩放,则可获得最准确的结果。当然这意味着,您需要将乘法结果存储在64位int类型中。 如果这不是一个选项,那么提前转换的方法是有道理的。但你肯定会失去精确度。

无论哪种方式,如果你进行圆形而不是截断,你可以稍微提高一点。

我支持阿空加瓜的建议,以舍入到最近的。 为此,您需要在应用除法之前添加将被截断的最高位。

在你的情况下看起来像这样:

A = (num1 + 1<<(halfshift-1)) >> halfshift 
B = (num2 + 1<<(halfshift-1)) >> halfshift
finalNum = A * B

修改

如何根据因子的值动态缩放因子和结果的示例(这可以提高分辨率,从而提高结果的准确性):

需要设置shiftA和shiftB,使A和B各为16字节小数,因此32字节结果不会溢出。如果事先不知道shiftA和shiftB,可以通过计算num1和num2的前导零来确定。

A = (num1 + 1<<(shiftA-1)) >> shiftA
B = (num2 + 1<<(shiftB-1)) >> shiftB
finalNum = (A * B) >> (fullshift - (shiftA + shiftB))