C++ 精度使用 long long 和 double

C++ Precision using long long with double

我正在试验 C++。我写了一个简单的函数,它使用非常大的数字来计算三角形的面积。

我将两个大数传递给函数,并从一个单独的函数 getValue() return 一个来自不同方程的单独值。我很好奇为什么当我把 1 放在括号外的线上时,像这样:

return (long long)(a - b / 2.0) + b + 1;

我得到值 9007200509008001

当我将 1 放在括号内时,就像这样:

return (long long)(a - b / 2.0 + 1) + b;

我得到 9007200509008000

第二个值比第一个小一个,即使计算结果应该相同。

#include <iostream>

double triangleArea(int b, int h)
{
    long long bh = (long long)b * h;
    return 0.5 * bh;
}

long long getValue()
{
    int deltaY = 18014400;
    int deltaX = 1000000000;

    long b = deltaY + deltaX + 1600;
    double a = triangleArea(deltaX, deltaY);
    return (long long)(a - b / 2.0) + b + 1;
}

int main(int argc, char **argv) 
{
    std::cout << getValue() << std::endl;
}

我确信答案对某些人来说可能是显而易见的,但我无法理解。有人可以解释一下吗?

当您除以 2.0 时,您将隐式转换为 double。双精度限制为大约 15 位十进制数字。所以第 16 会发生什么是完美定义的,但可能不是你所期望的。

如果你需要准确性,请尝试使用long longunsigned long long并小心控制你没有溢出。如果还不够,你将不得不使用多精度算法(例如GMP)。因为一旦你使用双浮点数,你就被限制在 53 个二进制数字的精度,或者大约 15-16 个十进制数字。

long long 通常比 double 具有更高的精度。例如,如果两者都是 64 位,则 long long 的精度为 64 位,但 double 的精度仅为 53 位(隐含 msb=1 的 52 位尾数)。

在您的情况下,这意味着 a - b / 2.0 + 1a - b / 2.0 相同 double 常数,但 (long long)(a - b / 2.0) + b + 1long long 不同常数为 (long long)(a - b / 2.0) + b.

问题是在您的除法和变量 a.

处隐式转换为 double

查看以下示例以进行清关:

#include <iostream>

double triangleArea(int b, int h)
{
    long long bh = (long long)b * h;
    return 0.5 * bh;
}

long long getValue()
{
    int deltaY = 18014400;
    int deltaX = 1000000000;

    long b = deltaY + deltaX + 1600;
    double a = triangleArea(deltaX, deltaY);

    long long c = b / 2.0;

    long long d1 = a - c;
    long long d2 = ((long long)a) - c + 1;

    long long e1 = d1 + b + 1;
    long long e2 = d2 + b;

    return e1;
}

int main(int argc, char **argv)
{
    std::cout << getValue() << std::endl;
}

long long 的显式转换正在解决您的特殊问题。

注意变量的准确性并在它们之间进行转换。