gpt4 book ai didi

c - gcc -mno-sse2 四舍五入

转载 作者:太空狗 更新时间:2023-10-29 17:26:23 25 4
gpt4 key购买 nike

我正在做一个将 RGB 转换为亮度的项目,但我遇到了一些与 -mno-sse2 标志有关的舍入问题:

测试代码如下:

#include <stdio.h>
#include <stdint.h>

static double rec709_luma_coeff[3] = {0.2126, 0.7152, 0.0722};

int main()
{
uint16_t n = 242 * rec709_luma_coeff[0] + 242 * rec709_luma_coeff[1] + 242 * rec709_luma_coeff[2];

printf("%u\n", n);
return 0;
}

这是我得到的:

user@gentoo>gcc -mno-sse2 test.c -o test && ./test
241
user@gentoo> gcc test.c -o test && ./test
242

我想 gcc 对 double 乘法使用 sse2 优化,但我不明白为什么优化版本会是正确的。

此外,您建议我使用什么来获得更一致的结果,ceil()floor()

最佳答案

TL:DR 使用 lrint(x)(int)rint(x) 将 float 转换为 int,使用舍入到最近而不是截断。不幸的是,并非所有编译器都能有效地内联相同的数学函数。参见 round() for float in C++


gcc -mno-sse2 必须为 double 使用 x87,即使在 64 位代码中也是如此。 x87 寄存器的内部精度为 80 位,但 SSE2 使用 IEEE binary64 (aka double)在 XMM 寄存器中原生格式化,因此所有临时值在每一步都舍入为 64 位 double

这个问题没有the double rounding problem 有趣。 (80 位 -> 64 位,然后是整数)。它也不是来自 gcc -O0 (默认:没有额外的优化)在将临时对象存储到内存时舍入,因为你在一个 C 语句中完成了整个事情,所以它只对整个表达式使用 x87 寄存器.


只是 80 位精度导致结果刚好低于 242.0 并被 C 的 float->int 语义截断为 241,而 SSE2 产生的结果刚好高于 242.0,截断为 242 . 对于 x87,对于从 1 到 65535 的任何输入,向下舍入到下一个较低的整数是一致的,而不仅仅是 242。(我使用 atoi(argv[1]) 制作了你的程序的一个版本所以我可以使用 -O3 测试其他值。

请记住 int foo = 123.99999 是 123,因为 C 使用“截断”舍入模式(接近零)。对于非负数,这与 floor(向 -Infinity 舍入)相同。 https://en.wikipedia.org/wiki/Floating-point_arithmetic#Rounding_modes .


double 不能准确表示系数:我用 gdb 打印它们并得到:{0.21260000000000001, 0.71519999999999995, 0.0722}。这些十进制表示可能不是以 2 为底的浮点值的精确表示。但它们非常接近,可以看出系数加起来为 0.99999999999999996(使用任意精度计算器)。

我们得到consist rounding down是因为x87内部精度高于系数的精度,所以在n * rec709_luma_coeff[0]等中求和舍入误差,在求和结果, 是 ~2^11 小于系数之和与 1.0 之间的差值。 (64 位有效数与 53 位)。

真正的问题是 SSE2 版本如何运作!大概舍入到最近——即使在临时对象上也恰好在足够多的情况下向上,至少对于 242。它恰好在更多情况下产生原始输入,但它为 5、7、10、13 产生输入 1, 14、20...(从 1..1000 开始的前 1000 个数字中有 252 个被 SSE2 版本“篡改”了,所以它也不总是有效。)


使用 -O3 作为您的源代码,它会在编译时以更高的精度进行计算并产生准确的结果。即它的编译与 printf("%u\n", n); 相同。


顺便说一句,你应该为常量使用 static const 以便 gcc 可以更好地优化。不过,static 比普通的 global 好得多,因为编译器可以看到编译单元中没有任何内容写入值或将它们的地址传递到任何地方,因此它可以将它们视为 const

关于c - gcc -mno-sse2 四舍五入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35069186/

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