c++ - 当 64 位 int 在 C/C++ 中转换为 64 位 float 并且没有完全匹配时,它是否总是落在非小数上?

标签 c++ c floating-point precision

当 int64_t 被强制转换为 double 并且没有完全匹配时,据我所知,我得到了一种等效于 double 的尽力而为最近的值。例如, int64_t 中的 9223372036854775000 似乎在 double 中以 9223372036854774784.0 结尾:

#include <stdio.h>

int main(int argc, const char **argv) {
    printf("Corresponding double: %f\n", (double)9223372036854775000LL);
    // Outputs: 9223372036854774784.000000
    return 0;
}
在我看来,似乎 int64_t 转换为 double 总是以干净的非小数结束,即使在 double 精度非常低的较高数字范围内也是如此。但是,我只是从随机尝试中观察到这一点。对于 int64_t 转换为 double 的任何值,是否保证会发生这种情况?
如果我将这个非小数 double 转换回 int64_t,我是否总是能得到精确对应的 64 位 int 并且 .0 被切掉? (假设它在转换回来期间没有溢出。)像这里:
#include <inttypes.h>
#include <stdio.h>

int main(int argc, const char **argv) {
    printf("Corresponding double: %f\n", (double)9223372036854775000LL);
    // Outputs: 9223372036854774784.000000
    printf("Corresponding int to corresponding double: %" PRId64 "\n",
           (int64_t)((double)9223372036854775000LL));
    // Outputs: 9223372036854774784
    return 0;
}
或者它可能不精确并在某些极端情况下让我得到“错误”的 int ?
凭直觉和我的测试,这两点的答案似乎都是"is",但是如果对浮点标准及其背后的数学有很好的正式理解的人可以确认这一点,那对我来说真的很有帮助。我也很好奇是否有任何已知的更激进的优化,例如 gcc 的 -Ofast已知会破坏其中任何一个。

最佳答案

在一般情况下,是的,两者都应该是真的。浮点基数需要 - 如果不是 2,则至少是整数,并且鉴于此,转换为最接近的浮点值的整数永远不会产生非零分数 - 精度足够或最低阶 整数 中的数字底座 float 类型的将被归零。例如,在您的情况下,您的系统使用 ISO/IEC/IEEE 60559 二进制浮点数。在基数 2 中检查时,可以看到该值的尾随数字确实为零:

>>> bin(9223372036854775000)
'0b111111111111111111111111111111111111111111111111111110011011000'
>>> bin(9223372036854774784)
'0b111111111111111111111111111111111111111111111111111110000000000'
考虑到 double 的值落在整数类型的范围内,将不带分数的 double 转换为整数类型应该是精确的...
尽管您仍然可能会遇到实现质量问题或彻底的错误 - 例如 MSVC currently has a compiler bug其中设置了 MSB 的无符号 32 位值的往返转换(或仅将 2³¹ 和 2³²-1 之间的双值转换为 unsigned int )将在转换中“溢出”并始终导致恰好 2³¹ .

关于c++ - 当 64 位 int 在 C/C++ 中转换为 64 位 float 并且没有完全匹配时,它是否总是落在非小数上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65749055/

相关文章:

c - kbhit() 作为转义触发器

c - 我们如何生成数字 x.y,其中 x 和 y 是两个参数或函数?

c++ - 在此实例中,三元运算符与 C 风格的指针向上转换相结合是否会调用未定义的行为?

c++ - OpenGL 3.2 为什么我会收到 glTexStorage3D 的 INVALID_ENUM 错误?

c++ - 将 fstat 与 Qt QDialog 一起使用

c# - 使用 ODP.NET (C#) 将对象传递给 oracle 包中的过程时必须使用哪种数据库类型?

c++ - 在 C++ 中正确转换 float

CUDA 浮点加法给出错误答案(与 CPU 浮点运算相比)

c++ - 如何在mfc中打开类中的文件?

c++ - 由于密码丢失,QuickFix 登录失败