我们知道编译器在优化代码方面越来越好,并使其运行得更快,但我的问题是编译器可以优化浮点运算以确保更高的准确性。
例如,基本规则是在加法之前执行乘法,这是因为使用浮点数的乘法和除法不会引入与加法和减法一样大的不准确性,但会增加加法和减法引入的不准确性的大小,所以在很多情况下应该先做。
所以像
这样的浮点运算y = x*(a + b); // faster but less accurate
应改为
y = x*a + x*b; // slower but more accurate
是否有任何编译器能够以牺牲速度为代价优化浮点精度,如上所示?或者编译器主要关心的是如何快速查看浮点运算的准确性?
由于
更新:所选答案显示了一个很好的例子,这种类型的优化不起作用,所以编译器不可能事先知道评估y的更准确的方法。谢谢你的反例。
答案 0 :(得分:10)
你的前提是错误的。 x*(a + b)
,(一般情况下)准确度不低于x*a + x*b
。事实上,它通常会更准确,因为它只执行两个浮点运算(因此只产生两个舍入误差),而后者执行三个运算。
如果您对x
,a
和b
的先验值的预期分配有所了解,那么您可以做出明智的决定,但编制者几乎无法访问那种信息。
除此之外,如果编写程序的人实际上意味着 x*(a+b)
并且特别是想要由特定操作序列引起的精确舍入怎么办?在高质量的数值算法中,这种事情实际上很常见。
最好是做程序员写的,不是你认为他可能想要的。
编辑 - 举例说明您建议的转换会导致灾难性的精确度损失:假设
x = 3.1415926535897931
a = 1.0e15
b = -(1.0e15 - 1.0)
然后,我们在double
进行评估:
x*(a + b) = 3.1415926535897931
但
x*a + x*b = 3.0
答案 1 :(得分:2)
编译器通常“优化”速度的准确性,精确度定义为IEEE 754标准的精确实现。尽管整数运算可以以任何不会导致溢出的方式重新排序,但FP运算需要完全按照程序员的指定执行。这可能会牺牲数值精度(普通的C编译器无法优化),但忠实地实现了程序员的要求。
确保他没有手动优化准确性的程序员可以使GCC -funsafe-math-optimizations
和-ffinite-math-only
等编译器功能可以提取额外的速度。但通常没有多少收获。
答案 2 :(得分:0)
不,没有。斯蒂芬·佳能给出了一些很好的理由,说明为什么这是一个愚蠢的想法,而且他是正确的;所以你找不到这样做的编译器。
如果你作为程序员对你正在操作的数字范围有一些了解,你可以使用括号,临时变量和类似的结构来强烈暗示编译器你想要完成的事情。