为什么从无符号long long转换为double会导致数据丢失?

Dmi*_*try 5 c c++ floating-point visual-c++

当我通过微软的VC 2008编译这段琐碎的代码时:

double maxDistance(unsigned long long* a, unsigned long long* b, int n)
{
    double maxD = 0, currentD = 0;
    for(int i = 0; i < n; ++i)
    {
        currentD = b[i] - a[i];
        if(currentD > maxD)
        {
            maxD = currentD;
        }
    }
    return maxD;
}
Run Code Online (Sandbox Code Playgroud)

编译器给了我:

警告C4244说明:从'unsigned long long'转换为'double',可能会丢失数据.在线上

currentD = b[i] - a[i]
Run Code Online (Sandbox Code Playgroud)

我知道最好以某种方式重写代码,我使用double来解释差异的可能负值,但我只是好奇,为什么在世界范围内从无符号long long转换为double会导致数据丢失,如果unsigned long long的范围从0到18,446,744,073,709,551,615,双倍是+/- 1.7E +/- 308?

nwe*_*hof 16

IEEE双精度浮点数具有53位尾数.这意味着(大多数)大于2 53的整数不能精确地存储在double中.

示例程序(这适用于GCC,%I64u用于MSVC):

#include <stdio.h>

int main() {
    unsigned long long ull;

    ull = (1ULL << 53) - 1;
    printf("%llu %f\n", ull, (double)ull);

    ull = (1ULL << 53) + 1;
    printf("%llu %f\n", ull, (double)ull);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

9007199254740991 9007199254740991.000000
9007199254740993 9007199254740992.000000
Run Code Online (Sandbox Code Playgroud)

  • @Rob你是对的,但问题是关于MSVC,据我所知,只有在符合IEEE 754标准的平台上才能使用. (6认同)

Rob*_*Rob 3

Adouble支持更大范围的可能值,但不能表示该范围内的所有值。有些无法表示的值是整数值,along或along long可以表示。

尝试将一个值分配给无法表示的浮点变量意味着结果是某种近似值 - 一个接近但不完全相等的值。这表示潜在的数据丢失(取决于分配的值)。