4

我在 IEEE 浮点规则方面遇到了一些问题,这些规则阻止了看起来很明显的编译器优化。例如,

char foo(float x) {
    if (x == x) 
       return 1;
    else 
       return 0; 
}

不能优化为只返回 1,因为 NaN == NaN 为假。好吧,好吧,我猜。

但是,我想编写这样的代码,优化器实际上可以为我解决问题。是否存在适用于所有浮点数的数学恒等式?例如,我愿意写 !(x - x) 如果这意味着编译器可以假设它一直保持不变(尽管情况并非如此)。

我在网络上看到了一些对此类身份的引用,例如这里,但我没有找到任何有组织的信息,包括对 IEEE 754 标准的简单扫描。

如果我能让优化器假设 isnormal(x) 而不生成额外的代码(在 gcc 或 clang 中),那也很好。

显然,我实际上并不打算在我的源代码中编写 (x == x),但我有一个专为内联而设计的函数。该函数可以声明为 foo(float x, float y),但通常 x 为 0,或 y 为 0,或 x 和 y 均为 z 等。浮点数表示屏幕上的几何坐标。在这些情况下,如果我在不使用函数的情况下手动编码,我永远不会区分 0 和 (x - x),我只会手动优化愚蠢的东西。所以,我真的不关心编译器在内联我的函数后所做的 IEEE 规则,我只想让编译器忽略它们。舍入差异也不是很重要,因为我们基本上是在屏幕上绘图。

我不认为 -ffast-math 对我来说是一个选项,因为该函数出现在头文件中,并且使用该函数的 .c 文件与 -ffast-math 一起编译是不合适的。

4

5 回答 5

2

我认为你总是会努力让计算机浮点数算术表现得像数学实数算术,并建议你不要出于任何原因。我建议您在尝试比较 2 个 fp 数字的相等性时出现类型错误。由于 fp 数字绝大多数是近似值,因此您应该接受这一点并使用近似相等作为您的测试。

存在用于数值相等性测试的计算机整数。

好吧,这就是我的想法,如果你愿意,你可以继续与机器(实际上是所有机器)战斗。

现在,回答您问题的某些部分:

-- 对于你熟悉的实数算术中的每一个数学恒等式,在浮点数领域都有反例,无论是 IEEE 还是其他;

——“聪明”的编程几乎总是让编译器比简单的编程更难优化代码;

- 似乎您正在做一些图形编程:最终,您的概念空间中的点坐标将映射到屏幕上的像素;像素总是有整数坐标;您从概念空间到屏幕空间的转换定义了您的近似相等函数

问候

标记

于 2009-12-29T09:47:46.560 回答
2

另一个可能对您有用的参考资料是 Yossarian King 在 Game Programming Gems 第 2 卷中关于浮点优化的非常好的文章。你可以在这里阅读这篇文章。它非常详细地讨论了 IEEE 格式,考虑了实现和架构,并提供了许多优化技巧。

于 2009-12-29T06:22:30.600 回答
2

如果您可以假设此模块中使用的浮点数不是 Inf/NaN,则可以使用-ffinite-math-only(在 GCC 中)编译它。对于您发布的示例,这可能会“改进”代码生成。

于 2009-12-29T22:24:01.050 回答
1

您可以比较按位相等。尽管您可能会为某些等效但按位不同的值而烦恼,但它会捕获所有您提到的真正相等的情况。而且我不确定编译器是否会识别您所做的并在内联时将其删除(我相信这是您所追求的),但这很容易检查。

于 2010-01-06T23:25:07.497 回答
0

当您以明显的方式尝试并对其进行分析时发生了什么?或检查生成的汇编?

如果该函数内联了调用站点已知的值,则优化器可以使用此信息。例如:foo(0, y)

您可能会对您不必做的工作感到惊讶,但至少分析或查看编译器实际上对代码所做的工作将为您提供更多信息并帮助您确定下一步该做什么。

也就是说,如果您知道优化器自己无法弄清楚的某些事情,您可以编写该函数的多个版本,并指定您要调用的那个。这有点麻烦,但至少对于内联函数,它们都将在一个标题中一起指定。它也比下一步要容易得多,下一步是使用内联 asm 来做你想做的事。

于 2009-12-29T06:36:28.240 回答