gpt4 book ai didi

c++ - 将 float 转换为 uint64 和 uint32 行为异常

转载 作者:太空狗 更新时间:2023-10-29 23:01:42 44 4
gpt4 key购买 nike

当我在 C++ 中将 32 位 float 转换为 64 位无符号整数时,一切都按预期工作。溢出导致设置 FE_OVERFLOW 标志 (cfenv) 并返回值 0。

std::feclearexcept(FE_ALL_EXCEPT);
float a = ...;
uint64_t b = a;
std::fexcept_t flags;
std::fegetexceptflag(&flags, FE_ALL_EXCEPT);

但是当我像这样将 32 位 float 转换为 32 位无符号整数时:

std::feclearexcept(FE_ALL_EXCEPT);
float a = ...;
uint32_t b = a;
std::fexcept_t flags;
std::fegetexceptflag(&flags, FE_ALL_EXCEPT);

除了高 32 位被截断外,我的行为与 64 位转换的方式完全相同。它等于:

std::feclearexcept(FE_ALL_EXCEPT);
float a = ...;
uint64_t b2 = a;
uint32_t b = b2 & numeric_limits<uint32_t>::max();
std::fexcept_t flags;
std::fegetexceptflag(&flags, FE_ALL_EXCEPT);

所以只有当指数大于或等于 64 并且在指数 32 和 64 之间,它返回 64 位转换的低 32 位而不设置溢出。这很奇怪,因为您会期望它在指数 32 处溢出。

这是应该的方式,还是我做错了什么?

编译器是:LLVM version 6.0 (clang-600.0.45.3) (based on LLVM 3.5svn)

最佳答案

从 float 到整数的转换中出现溢出是未定义的行为。您不能依赖它是通过单个汇编指令或溢出指令来完成的,该指令会溢出您希望为其设置溢出标志的确切值集。

可能已经生成的汇编指令cvttsd2si确实会在溢出时设置标志,但在转换为32位int类型时可能会生成该指令的64位变体。一个很好的理由是当将浮点值截断为 unsigned 32 位整数时,如您的问题所示,因为目标寄存器的所有 32 位低位都为浮点正确设置 -在执行 64 位signed 指令后导致定义转换的点值cvttsd2si 指令没有未签名的变体。

来自Intel manual :

CVTTSD2SI—Convert with Truncation Scalar Double-Precision FP Value to Signed Integer

If a converted result exceeds the range limits of signed doubleword integer (in non-64-bit modes or 64-bit mode with REX.W/VEX.W=0), the floating-point invalid exception is raised, and if this exception is masked, the indefinite integer value (80000000H) is returned.

If a converted result exceeds the range limits of signed quadword integer (in 64-bit mode and REX.W/VEX.W = 1), the floating-point invalid exception is raised, and if this exception is masked, the indefinite integer value (80000000_00000000H) is returned.

blog post , 尽管是 C 的,但扩展了这个主题。

关于c++ - 将 float 转换为 uint64 和 uint32 行为异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30665959/

44 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com