C++ 如何用C+中的分数乘以64位整数+;在最小化误差的同时?
给定一个64位(有符号)C++ 如何用C+中的分数乘以64位整数+;在最小化误差的同时?,c++,multiplication,integer-overflow,integer-division,C++,Multiplication,Integer Overflow,Integer Division,给定一个64位(有符号)long或\uu int64,您将如何将其乘以任意分数,同时最小化错误 三个简单的草图: int64_t numerator = ...; int64_t denominator = ...; int64_t x = ...; // a, lossy double conversion for large values double fraction = static_cast<double>(numerator) / static_cast<doub
long
或\uu int64
,您将如何将其乘以任意分数,同时最小化错误
三个简单的草图:
int64_t numerator = ...;
int64_t denominator = ...;
int64_t x = ...;
// a, lossy double conversion for large values
double fraction = static_cast<double>(numerator) / static_cast<double>(denominator);
int64_t result = x * fraction;
// b, divide first, problem if denominator value near (or even larger) x
int64_t result = x / denominator;
result *= numerator;
// c, multiply first, problem if multiplication overflows
int64_t result = x * numerator;
result /= denominator;
int64_t分子=。。。;
int64_t分母=。。。;
int64_t x=。。。;
//a、大值的有损双转换
双分数=静态施法(分子)/静态施法(分母);
int64_t结果=x*分数;
//b,首先除法,如果分母值接近(甚至更大)x,则出现问题
int64_t结果=x/分母;
结果*=分子;
//c,先乘法,乘法溢出的问题
int64_t result=x*分子;
结果/=分母;
如果
x*n/d
在数学上不能产生整数,我可以将结果截断为最接近的整数。您可以使用以下方法:
const int64_t q = x / denominator;
const int64_t r = x - q * denominator;
// x = q * denominator + r;
const int64_t result = q * numerator + ((r * numerator) / denominator);
注意:您可以使用std::div
family同时获得商和余数
注:正如Sander De Dycker所指出的,当r*分子/分母
溢出对于特例
x=INT64_MIN,分母=-1
,其中x/分母
溢出。或多或少地从中复制,这对我来说似乎最有意义:
int64_t muldiv64(const int64_t x, const int64_t n, const int64_t d)
{
/* find the integer and remainder portions of x/d */
const int64_t div = x / d;
const int64_t mod = x % d;
return div * n + (mod * n) / d;
}
改进提供的答案(当
b
较大时,这会减少溢出):
不需要编写奇怪的代码来避免使用模运算:编译器可以进行替换,您可以获得更可读的代码
编辑:
任何更复杂的代码可能都不值得研究。如果需要更高的精度,最好是使用128位算术或使用任意精度整数库(请参见)使用第三种128位算术方法。您也可以使用BigInt库,然后手动管理溢出,以适应
int64\t
@jbutler483-Title是一个dup。问题主体不是这样,我想说。看这个词是muldiv
。最好还是把它变成一个内联函数int64\t muldiv64(int64\t x,int64\t分子,int64\t分母)
。你是说:更好的r=x%d
还是你的r=x-q*d
?对于负数,%
的语义标准化了吗?@Ben-C++11定义了它。@MartinBa:应该是相同的。(可能其中一个比另一个更有效)。请注意,对于a
,b
但a*d
溢出的情况,存在与上一个答案相同的问题。它只是解决了当b>=d
@Jarod42时其他答案的问题是的,我并不是说它是最好的可能性,只是比以前的解决方案有所改进。如果需要更精确的解决方案,最好使用任意精度的整数库,例如在int8\t
上测试它。为简单起见,它会在x=3,n=86,d=87上溢出。所以我相信你可以找到64位的等价性。
int64_t muldiv64(const int64_t a, const int64_t b, const int64_t d)
{
/* find the integer and remainder portions of x/d */
const int64_t diva = a / d;
const int64_t moda = a % d;
const int64_t divb = b / d;
const int64_t modb = b % d;
return diva * b + moda * divb + moda * modb / d;
}