C++ 64位溢出数学转换

C++ 64位溢出数学转换,c++,integer-overflow,C++,Integer Overflow,我正在尝试执行一个转换: uint64_t factor = 2345345345; // Actually calculated at runtime, but roughly this magnitude uint64_t Convert(uint64_t num) { return num * 1000ULL / factor; } 对于最大的num值,乘法在除以因子之前进行包装。将顺序更改为num/factor*1000UL会降低一些不可接受的精度 我想重写Convert()

我正在尝试执行一个转换:

uint64_t factor = 2345345345; // Actually calculated at runtime, but roughly this magnitude

uint64_t Convert(uint64_t num)
{
    return num * 1000ULL / factor;
}
对于最大的
num
值,乘法在除以
因子之前进行包装。将顺序更改为
num/factor*1000UL
会降低一些不可接受的精度

我想重写
Convert()
以处理所有可能的
num
值:

uint64_t Convert(uint64_t num)
{
    if(num > MAX_UINT64/1000ULL)       // pseudo code
    {
        // Not sure what to put here
    }
    else
    {
        return num * 1000ULL / factor;
    }
}
我们考虑过使用128位数学,但如果可能的话,希望避免使用它


实现
Convert()
的最有效方法是什么,以便它能够理想地处理最大的
num
,并且仍然产生正确的结果?

将您的划分分解为:

r = 1000*(n/factor) + ((n%factor)*1000)/Factor

如果余数溢出(因子较大),您仍然可能会遇到问题,但如果因子小于
MAX\u UINT64/1000
,您就可以了。

稍微老派一点的数学,您可以使用
%
计算余数:

uint64_t Convert(uint64_t num)
{
    uint64_t m = 1000;
    uint64_t a = num / factor;
    uint64_t t = num % factor;
    uint64_t h = m * t / factor;

    return a * m + h;
}
例如:

uint64_t Convert2(uint64_t num)
{
    return num * 1000ULL / factor;
}

uint64_t Convert3(uint64_t num)
{
    return num / factor * 1000ULL;
}


int main()
{
    cout << Convert(std::numeric_limits<uint64_t>::max()) << endl;
    cout << Convert2(std::numeric_limits<uint64_t>::max()) << endl;
    cout << Convert3(std::numeric_limits<uint64_t>::max()) << endl;
}
uint64\u t转换器2(uint64\u t num)
{
返回数*1000ULL/系数;
}
uint64_t转换器3(uint64_t num)
{
返回数/系数*1000ULL;
}
int main()
{

你是说ULL吗?或者你使用32位因子是出于特定的原因吗?@kfsone为了清晰起见,我将它改为ULL。@kfsone-1000是一个
int
,它可能是也可能不是32位。不管怎样,它在使用它的各个地方都会被转换为
uint64\u t
。@PeteBecker 1000是一个有符号的int。1000UL是一个无符号的长int.E它可能会被转换,或者可能会导致转换和精度损失。1000ULL显式地是一个无符号长整型。由于他打算将其作为一个无符号长整型,因此在第一个位置正确使用说明符似乎是合理的,如果只是为了清楚地将意图传达给阅读代码的任何其他程序员或他自己如果他在周日早上4:30挂断电话时试图重读它,而客户在电话中对他大喊大叫。@kfsone-是的,不知道整数类型在算术表达式中如何交互的程序员可能会感到困惑;无知是可以纠正的。这段代码做的事情完全相同,有后缀或没有后缀。意图,有或者不带后缀,很明显:将值乘以1000。当然,如果你坚持添加后缀以保护醉酒的自己,那么每当你向类型不是
int
的值添加
1
时,你也需要一个后缀。
7865257077400  <--- // The correct one //
7865257077     <--- // Value wrapped before multiplication // 
7865257077000  <--- // Low accuracy, loses remaining //