Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.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+中的分数乘以64位整数+;在最小化误差的同时?_C++_Multiplication_Integer Overflow_Integer Division - Fatal编程技术网

C++ 如何用C+中的分数乘以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

给定一个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<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;
}