c++ - 64 位溢出数学转换

标签 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 值,乘法在除以 factor 之前换行。将顺序更改为 num/factor * 1000UL 会失去一些 Not Acceptable 准确性。

我想重写 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 可能并仍然产生正确的结果?

最佳答案

有点老派的数学,你可以使用%来计算剩余:

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;
}

输出:

7865257077400  <--- // The correct one //
7865257077     <--- // Value wrapped before multiplication // 
7865257077000  <--- // Low accuracy, loses remaining //

关于c++ - 64 位溢出数学转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18537030/

相关文章:

c++ - 无法解释以下 C++ 片段的输出

c++ - VIM 中突出显示的随机括号

integer - 缩放(长)整数时防止溢出并保持精度

C++ 嵌套条件运算符的求值顺序

c++ - 使用 std::string 定义运算符 =

c - 在 C 中实现/强制执行环绕算术

c# - 将 C 移植到 C# 时棘手的整数溢出

c++ - 可以容纳两个 size_t 的乘积的类型

gcc - "int64var = int32var * int32var"中的计算没有像预期的那样溢出。为什么?

回调中生产者和消费者之间的 C++ 循环模板依赖