Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/161.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何将整数乘以分数_C++_Algorithm_Templates_Optimization - Fatal编程技术网

C++ 如何将整数乘以分数

C++ 如何将整数乘以分数,c++,algorithm,templates,optimization,C++,Algorithm,Templates,Optimization,我的目标是得到一个签名如下的函数: template<typename int_t, int_t numerator, int_t denominator> int_t Multiply(int_t x); 最简单的方法是先将“x”乘以分子,然后除以 看一个具体的例子,让我们假设,int\u t=uint8\u t,“x”是30,分子和分母分别是119和255 由于(30*119)mod 256=242除以255,然后floored为0,所以采用这种简单的路由失败。真正的答案应该是

我的目标是得到一个签名如下的函数:

template<typename int_t, int_t numerator, int_t denominator>
int_t Multiply(int_t x);
最简单的方法是先将“x”乘以分子,然后除以

看一个具体的例子,让我们假设,
int\u t
=
uint8\u t
,“x”是30,分子和分母分别是119和255

由于(30*119)mod 256=242除以255,然后floored为0,所以采用这种简单的路由失败。真正的答案应该是14

下一步就是对中间值使用更大的整数大小。因此,我们将在mod 65536中进行30*119计算,而不是在mod 256中进行30*119计算。这在一定程度上确实有效,但当我们尝试在
乘法
函数中使用最大整数大小时,它失败了

下一步就是使用一些
BigInt
类型来保存值,这样它就不会溢出。这也会起作用,但使用模板参数的全部原因是这样可以非常快地完成,使用
BigInt
可能无法达到这一目的

问题是:


是否有一种只涉及移位、乘法、除法、加法、减法和余数运算符的算法,可以执行此数学函数,而不会导致溢出问题?

对于Windows平台,我建议您阅读这篇文章,它目前支持最多128位整数值。您可以根据
int\t
的位专门化模板,作为这些操作系统功能的代理

为乘法实现“移位和加法”可能提供了一个足够好的选择,但除法肯定会抵消您所希望的任何性能提升

还有一些“捷径”,比如尝试查看
分子
分母
是否可以通过分数缩减来简化,例如,乘以35/49与乘以5/7相同

我想到的另一种选择是“逐渐”乘以“分数”。不过,这一点需要一些解释:

假设您正在乘以
1234567/89012
。为了可读性,我将使用十进制表示法,但这同样适用于二进制数学

我们得到的是一个值,需要乘以这个分数。由于我们处理的是整数算术,所以让我们稍微重新打包该分数:

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...
事实上,在这一点上,你的主要问题是“我希望在计算中有多精确?”。根据对这个问题的回答,你将得到这个长序列中适当数量的成员


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

要回答这里提出的问题:是的,有一种算法只涉及移位、乘法、除法、加法、减法和余数运算符,这可以预执行此数学函数,而不会导致溢出问题。噢,至于它是什么,请注意,例如,一个32位的数字可以表示为a*65536+b,其中
a
b
都是16位的数字;因此,对32位数字的此类运算可以表示为对16位数字的等效运算,并将结果进行数学组合。你只需要自己计算出这些运算是什么。@sam但是它比使用更大的int更快吗?我不认为有一种算法可以避免对任意操作数计算完全精度的乘积。(如果输入和分母恰好gcd>1,您可以以此作为初始步骤进行缩减。)这意味着计算全积,然后使用窄类型的多个实例进行除法。这将是丑陋的,并且总是比单个硬件在更大的宽度上进行乘法和除法要慢。建议您重新规范模板,以包含中间产品的类型。由于486DX,每个Intel CPU都配有内置的数学协处理器。除非您没有列出一些其他要求(例如,可接受的精度损失)或为极其关键的部分编写代码,否则我怀疑这是否真的需要按照您描述的方式进行优化假设输入是8位值,数学是在16位中完成的,那么,为什么255的最大整数值是一个问题?255*255=65025,适用于65536。
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...