将最大整数转换为浮点数而不损失精度

问题描述 投票:0回答:1

我有一个以下片段,我用它来尝试测试如果将最大整数转换为

double

是否会发生精度损失
    #include <cstdint>
    #include <limits>
    #include <iostream>
    #include <iomanip>

    int main () noexcept
    {
        uint64_t ui64{std::numeric_limits<uint64_t>::max()};
        constexpr auto max_precision{std::numeric_limits<long double>::digits10 + 1}; 
        std::cout << "ui64 " << std::setprecision(max_precision) << std::boolalpha << ui64 << "\n\n";

        double f64 = static_cast<double>(ui64);
        uint64_t ui64_cast_back = static_cast<uint64_t>(f64);
        std::cout << "sizeof(f64): " << sizeof(double) << std::endl;
        std::cout << "f64 = " << f64 << std::endl;
        std::cout << "ui64_cast_back matches original value? " << (ui64_cast_back == ui64) << std::endl;
        std::cout << "ui64_cast_back = " << ui64_cast_back << std::endl;
    }

当我为项目的自定义平台构建它时(在编译器资源管理器上不可用),我得到以下输出:

ui64 18446744073709551615

sizeof(f64): 8
f64 = 18446744073709551616
ui64_cast_back matches original value? true
ui64_cast_back = 18446744073709551615
打印

double

 值时出现一个错误似乎表明存在精度损失。然而,当回传时,会检索到原始值。 off 1 是否有可能是打印时 IO 流实现造成的,或者打印可以被认为是精度损失的证明?

c++ floating-point precision
1个回答
1
投票
您平台上的

double

 看起来是 
binary64

该格式中没有

18446744073709551615

。最接近的两个值是:

18446744073709549568 // The double below 18446744073709551615 // Your integer (not exactly representable) 18446744073709551616 // The double above
因此 

double f64 = static_cast<double>(ui64);

 将值四舍五入到最接近的双精度(上面的那个)。没有办法防止“精度损失”,因为它在物理上无法表示。 (考虑有 2^64 个 
int64_t
 值,最多 2^64 个 double 值)。

您应该注意到,对于

std::numeric_limits<uint64_t>::max()-1

std::numeric_limits<uint64_t>::max()-2
 等,您会得到相同的结果,因为它们也舍入为相同的值。

当您执行强制转换时,您会出现未定义的行为,因为 double 现在太大而无法放入 int64_t 中。如果双精度太大,您的机器似乎只是返回最大的 int64_t 。

© www.soinside.com 2019 - 2024. All rights reserved.