gpt4 book ai didi

c++ - 奇怪的 uint32_t 到 float 数组转换

转载 作者:可可西里 更新时间:2023-11-01 16:36:09 32 4
gpt4 key购买 nike

我有以下代码片段:

#include <cstdio>
#include <cstdint>

static const size_t ARR_SIZE = 129;

int main()
{
uint32_t value = 2570980487;

uint32_t arr[ARR_SIZE];
for (int x = 0; x < ARR_SIZE; ++x)
arr[x] = value;

float arr_dst[ARR_SIZE];
for (int x = 0; x < ARR_SIZE; ++x)
{
arr_dst[x] = static_cast<float>(arr[x]);
}

printf("%s\n", arr_dst[ARR_SIZE - 1] == arr_dst[ARR_SIZE - 2] ? "OK" : "WTF??!!");

printf("magic = %0.10f\n", arr_dst[ARR_SIZE - 2]);
printf("magic = %0.10f\n", arr_dst[ARR_SIZE - 1]);
return 0;
}

如果我在 MS Visual Studio 2015 下编译它,我可以看到输出是:

WTF??!!
magic = 2570980352.0000000000
magic = 2570980608.0000000000

所以最后一个 arr_dst 元素与前一个不同,但这两个值是通过转换相同的值获得的,该值填充了 arr 数组!是错误吗?

我注意到如果我按以下方式修改转换循环,我会得到“OK”结果:

for (int x = 0; x < ARR_SIZE; ++x)
{
if (x == 0)
x = 0;
arr_dst[x] = static_cast<float>(arr[x]);
}

所以这可能是矢量化优化的一些问题。

此行为不会在 gcc 4.8 上重现。有什么想法吗?

最佳答案

MSVC++ 使用的 32 位 IEEE-754 二进制 float 仅提供 6-7 位十进制数字的精度。您的起始值正好在该类型的范围 之内,但它似乎不能完全由该类型表示,对于大多数 uint32_t 类型的值来说确实如此。

同时,x86 或 x86_64 处理器的浮点单元使用比 MSVC++ 的 64 位 double 更广泛的表示。似乎在循环退出后,最后计算的数组元素以其扩展精度形式保留在 FPU 寄存器中。然后,程序可以直接从寄存器中使用该值,而不是从内存中读回它,这是它必须对先前的元素执行的操作。

如果程序通过将较窄的表示提升为较宽的表示而不是相反的方式来执行 == 比较,那么这两个值可能确实比较不相等,因为扩展精度的往返float 然后返回会失去精度。在任何情况下,当传递给 printf() 时,这两个值都将转换为 double 类型;如果它们确实比较不相等,那么这些转换的结果很可能也不同。

我没有使用 MSVC++ 编译选项,但很可能有一个可以消除这种行为。此类选项有时会以“严格数学”或“严格 fp”等名称命名。但是请注意,在 FP 繁重的程序中打开这样的选项(或关闭它的相反选项)可能会非常昂贵。

关于c++ - 奇怪的 uint32_t 到 float 数组转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40138067/

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