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

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

#include <stdio.h>

int main(int argc, const char **argv) {
    printf("Corresponding double: %fn", (double)9223372036854775000LL);
    // Outputs: 9223372036854774784.000000
    return 0;
}

在我看来,似乎 int64_t 转换为 double 总是以干净的非小数结束,即使在 double 精度非常低的较高数字范围内也是如此。但是,我只是从随机尝试中观察到这一点。对于 int64_t 转换为 double 的任何值,是否保证会发生这种情况?

如果我将这个非小数双精度转换回 int64_t,我是否总是能得到精确对应的 64 位 int 并且 .0 被切掉?(假设它在转换回来期间没有溢出。)像这里:

#include <inttypes.h>
#include <stdio.h>

int main(int argc, const char **argv) {
    printf("Corresponding double: %fn", (double)9223372036854775000LL);
    // Outputs: 9223372036854774784.000000
    printf("Corresponding int to corresponding double: %" PRId64 "n",
           (int64_t)((double)9223372036854775000LL));
    // Outputs: 9223372036854774784
    return 0;
}

或者它可能不精确并在某些极端情况下让我得到“错误”的 int ?

凭直觉和我的测试,这两点的答案似乎都是“是”,但是如果对浮点标准及其背后的数学有很好的正式理解的人可以确认这一点,那对我来说真的很有帮助。我也很好奇是否已知任何已知的更激进的优化(例如 gcc 的优化)-Ofast会破坏其中的任何一个。

回答

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

>>> bin(9223372036854775000)
'0b111111111111111111111111111111111111111111111111111110011011000'
>>> bin(9223372036854774784)
'0b111111111111111111111111111111111111111111111111111110000000000'

考虑到 double 的值落在整数类型的范围内,将没有分数的 double 转换为整数类型应该是精确的...

尽管您仍然可能会遇到实现质量问题或彻底的错误——例如MSVC目前有一个编译器错误,其中无符号 32 位值与 MSB 集(或只是 2³¹ 和 2³² 之间的双值)的往返转换-1 转换为unsigned int ) 将在转换中“溢出”并始终导致恰好 2³¹。


以上是当64位int在C/C++中转换为64位浮点数并且没有完全匹配时,它是否总是落在非小数上?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>