5

我们知道编译器在优化我们的代码并使其运行得更快方面越来越好,但我的问题是有编译器可以优化浮点运算以确保更高的准确性。

例如,一个基本规则是在加法之前执行乘法,这是因为使用浮点数的乘法和除法不会像加法和减法那样引入误差,但会增加加法和减法引入的误差幅度,所以它应该很多情况下要先做。

所以像这样的浮点运算

y = x*(a + b); // faster but less accurate

应改为

y = x*a + x*b; // slower but more accurate

有没有编译器会像我上面展示的那样以牺牲速度为代价来优化浮点精度?还是编译器速度的主要关注点是不考虑浮点运算的准确性?

谢谢

更新:所选答案显示了一个非常好的示例,其中这种优化不起作用,因此编译器不可能事先知道评估 y 的更准确方法是什么。感谢您的反例。

4

3 回答 3

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
于 2010-01-14T00:08:47.700 回答
2

编译器通常“优化”精度而不是速度,精度定义为 IEEE 754 标准的精确实现。虽然整数运算可以以任何不会导致溢出的方式重新排序,但 FP 运算需要完全按照程序员指定的方式执行。这可能会牺牲数值准确性(普通的 C 编译器没有为此进行优化),但忠实地实现了程序员的要求。

确定自己没有手动优化准确性的程序员可能会启用 GCC 等编译器功能-funsafe-math-optimizations,并-ffinite-math-only可能获得额外的速度。但通常没有太大的收获。

于 2010-01-14T06:00:58.720 回答
0

不,没有。Stephen Canon 给出了一些很好的理由说明这将是一个愚蠢的想法,而且他是正确的;所以你不会找到执行此操作的编译器。

如果您作为程序员对您正在操作的数字范围有一些了解,您可以使用括号、临时变量和类似的结构来强烈提示编译器您希望如何完成工作。

于 2010-01-14T00:21:29.270 回答