我遇到了一些IEEE浮点规则的问题,导致编译器优化看起来很明显。例如,
char foo(float x) {
if (x == x)
return 1;
else
return 0;
}
无法优化为仅返回1,因为NaN == NaN为false。好的,我猜。
但是,我想写一下,优化器实际上可以为我修复。所有花车都有数学身份吗?例如,我愿意写!(x - x)如果它意味着编译器可以假设它一直保持(尽管情况并非如此)。
我在网上看到了对这些身份的一些提及,例如here,但我没有找到任何有组织的信息,包括在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编译是不合适的。
答案 0 :(得分:2)
另一个可能对您有用的参考是Yossarian King在Game Programming Gems第2卷中关于浮点优化的非常好的文章。您可以阅读文章here。它详细讨论了IEEE格式,考虑了实现和架构,并提供了许多优化技巧。
答案 1 :(得分:2)
我认为你总是很难让计算机浮点数运算表现得像数学实数运算,并建议你不要出于任何原因。我建议您在尝试比较2个fp数字的相等性时出现类型错误。由于fp数字绝大多数是近似值,因此你应该接受这个并使用近似相等作为你的测试。
存在用于数值等式测试的计算机整数。
嗯,这就是我的想法,如果你愿意,你可以继续和机器(实际上是所有机器)对抗。
现在,回答你问题的某些部分:
- 对于您从实数运算中熟悉的每个数学标识,浮点数域中都有反例,无论是IEEE还是其他;
- '聪明'编程几乎总是使编译器比直接编程更难以优化代码;
- 你似乎正在做一些图形编程:最后,概念空间中点的坐标将被映射到屏幕上的像素;像素总是有整数坐标;从概念空间到屏幕空间的翻译定义了近似等式函数
此致
标记
答案 2 :(得分:2)
如果您可以假设此模块中使用的浮点数不是Inf / NaN,则可以使用-ffinite-math-only
(在GCC中)编译它。这可能会“改进”代码,例如您发布的代码。
答案 3 :(得分:1)
您可以比较按位相等。虽然你可能会因为某些相同但按位不同的值而被咬,但它会捕获所有那些你提到的真正相等的情况。而且我不确定编译器会识别你做什么并在内联时将其删除(我相信你所追求的是),但这很容易检查。
答案 4 :(得分:0)
当您以明显的方式尝试并对其进行分析时发生了什么?或检查生成的asm?
如果函数内联调用站点已知的值,则优化程序可以使用此信息。例如:foo(0, y)
。
您可能会对不必须做的工作感到惊讶,但至少在剖析或查看编译器实际对代码执行的操作时,会为您提供更多信息并帮助您弄清楚接下来要去哪里。
也就是说,如果您知道优化器无法弄清楚的某些事情,您可以编写该函数的多个版本,并指定您要调用的函数。这有点麻烦,但至少对于内联函数,它们都将在一个标题中一起指定。它比下一步更容易,它使用内联asm来完全按照你想要的那样。