【发布时间】:2017-04-09 08:24:40
【问题描述】:
所以我的目标是创建一个签名如下所示的函数:
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 函数中使用最大整数大小时它会失败。
下一步就是使用一些BigInt 类型来保存值,这样它不会溢出。这也是可行的,但是使用模板参数的全部原因是这样可以非常快,并且使用 BigInt 可能会破坏该目的。
那么问题来了:
是否有一种算法只涉及移位、乘法、除法、加法、减法和余数运算符,可以执行此数学函数,而不会导致溢出问题?
【问题讨论】:
-
回答这里提出的问题:是的,有一种算法只涉及移位、乘法、除法、加法、减法和余数运算符,可以执行此数学函数,而不会导致溢出问题。哦,至于它是什么,请注意,例如,一个32位的数字可以表示为a*65536+b,其中
a和b都是16位数字;因此,对 32 位数字的此类操作可以表示为对 16 位数字的等效操作,并以数学方式组合结果。您只需要自己弄清楚这些操作是什么。 -
@sam 但它比使用更大的 int 更快吗?
-
我认为没有一种算法可以避免对任意操作数进行全精度计算。 (如果输入和分母碰巧有 gcd > 1,你可以以此作为初始步骤。)这意味着计算完整的产品,然后使用多个窄类型实例进行划分。这将是丑陋的,并且总是比单个硬件在更大宽度上的乘法和除法要慢。建议您重新指定模板以包含中间产品的类型。
-
从 486DX 开始,每个 Intel CPU 都带有一个内置的数学协处理器。除非您没有列出其他一些要求(例如,可接受的精度损失)或为极其关键的部分编写代码,否则我怀疑这是否真的需要按照您描述的方式进行优化
-
假设输入是 8 位值并且数学是在 16 位中完成的,那么为什么 max_int 值 255 是个问题? 255*255 = 65025,适合 65536。
标签: c++ algorithm templates optimization