如何将整数乘以分数

时间:2017-04-08 22:47:25

标签: c++ algorithm templates optimization

所以我的目标是拥有一个签名如下的函数:

template<typename int_t, int_t numerator, int_t denominator>
int_t Multiply(int_t x);

类型是一个整数类型,它既是一个参数的类型,也是返回类型。

另外两个模板参数是分数的分子和分母。

此函数的目标是将数字“x”乘以任意分数,该分数位于两个模板值中。一般来说答案应该是:

floor(x*n/d) mod (int_t_max+1)

这种天真的方法是首先将“x”乘以分子,然后除以。

查看具体案例,可以说int_t = uint8_t,“x”为30,分子和分母分别为119和255.

采用这种天真的路线失败是因为(30 * 119)mod 256 = 242,除以255然后被覆盖为0.真正的答案应该是14。

下一步是为中间值使用更大的整数。所以不是在mod 256中进行30 * 119计算,而是在mod 65536中进行。这在某种程度上有效,但是当我们尝试在Multiply函数中使用最大整数时,它会失败。 / p>

下一步是只使用一些BigInt类型来保存值,使无法溢出。这也可行,但是获得模板参数的全部原因是,这可能非常快,并且使用BigInt可能会失败。

所以这就是问题:

是否有一个算法只涉及移位,乘法,除法,加法,减法和余数运算符,可以预先形成这个数学函数,而不会引起溢出问题?

1 个答案:

答案 0 :(得分:0)

对于Windows平台,我建议您查看large integers上的这篇文章,该文章目前包含对最多128位整数值的支持。您可以根据int_t的位与您的模板进行专门化,以作为这些操作系统功能的代理。

为乘法实现“shift-and-add”可能提供了一个足够好的替代方案,但是一个部门肯定会否定你可能希望的任何性能提升。

然后有“快捷方式”,例如试图查看numeratordenominator是否可以通过减少分数来简化,例如乘以35/49与乘以5/7相同。

另一个想到的选择是“逐渐”乘以“分数”。这个需要一些解释:

假设您乘以1234567/89012。我将使用十进制表示法来表示可读性,但同样适用于(自然地)二进制数学。

所以我们所拥有的是一个值x,需要乘以该分数。因为我们正在处理整数运算,所以让我们重新包装那个分数:

1234567/89012 = A + B/10 + C/100 + D/1000...
 = 1157156/89012 + ((71210*10)/89012)/10 + ((5341*100)/89012)/100 + ((801*1000)/89012)/1000...
 = 13 + 8/10 + 6/100 + 9/1000...

事实上,在这一点上,你的主要问题是“我在计算中有多精确?”。根据该问题的答案,您将拥有该长序列的适当数量的成员。

这将为您提供所需的精度,并为计算产品提供通用的“无溢出”方法,但计算成本是多少?