Clang 与 1 优化的倒数
Clang reciprocal to 1 optimisations
经过与同事的讨论,我最终测试了 clang 是否会优化两个除法(倒数为 1)到一个除法。
const float x = a / b; //x not used elsewhere
const float y = 1 / x;
如果 x
仅用作临时步长值,理论上 clang 可以优化为 const float y = b / a
,不是吗?
这是一个简单测试用例的输入和输出:https://gist.github.com/Jiboo/d6e839084841d39e5ab6(在两个输出中你可以看到它执行了两个除法,而不是优化)
这个相关问题在我的理解背后,似乎只关注为什么不使用特定指令,而在我的情况下,它是未完成的优化:
谢谢,
JB.
不,clang 不能那样做。
但首先,您为什么要使用浮动? float 有六位精度,double 有 15 位。除非你有充分的理由,你可以解释,使用 double。
1 / (a / b) 在浮点运算中与 b / a 不同。编译器必须做的是第一种情况:
- a 除以 b
- 将结果舍入到最接近的浮点数
- 结果除以 1
- 将结果舍入到最接近的浮点数。
第二种情况:
- 将 b 除以 a。
- 将结果舍入到最接近的浮点数。
编译器只能在保证结果相同的情况下更改代码,如果编译器编写者无法提供结果相同的数学证明,则编译器无法更改代码。第一种情况有两次舍入操作,对不同的数进行舍入,所以不太可能保证结果相同。
编译器不像数学家那样思考。在您认为简化表达式在数学上微不足道的地方,编译器还有很多其他事情需要考虑。实际上,编译器很可能比程序员聪明得多,而且对 C 标准的了解也多得多。
优化编译器的 "mind":
可能就是这样的事情
- 啊,他们写了
a / b
但只在一个地方使用 x
,所以我们不必在堆栈上分配那个变量。我将删除它并使用 CPU 寄存器。
- 嗯,整数文字 1 除以浮点变量。好的,我们必须先在这里调用平衡,然后将该文字转换为浮点数
1.0f
.
- 程序员指望我生成的代码包含将
1.0f
除以另一个浮点变量所涉及的潜在浮点不准确!所以我不能只用 b / a
交换这个表达式,因为那样的话程序员似乎想要的浮点不准确就会丢失。
等等。有 很多 的注意事项。您最终得到的机器代码很难提前预测。只知道编译器会严格按照您的说明进行操作。
经过与同事的讨论,我最终测试了 clang 是否会优化两个除法(倒数为 1)到一个除法。
const float x = a / b; //x not used elsewhere
const float y = 1 / x;
如果 x
仅用作临时步长值,理论上 clang 可以优化为 const float y = b / a
,不是吗?
这是一个简单测试用例的输入和输出:https://gist.github.com/Jiboo/d6e839084841d39e5ab6(在两个输出中你可以看到它执行了两个除法,而不是优化)
这个相关问题在我的理解背后,似乎只关注为什么不使用特定指令,而在我的情况下,它是未完成的优化:
谢谢, JB.
不,clang 不能那样做。
但首先,您为什么要使用浮动? float 有六位精度,double 有 15 位。除非你有充分的理由,你可以解释,使用 double。
1 / (a / b) 在浮点运算中与 b / a 不同。编译器必须做的是第一种情况:
- a 除以 b
- 将结果舍入到最接近的浮点数
- 结果除以 1
- 将结果舍入到最接近的浮点数。
第二种情况:
- 将 b 除以 a。
- 将结果舍入到最接近的浮点数。
编译器只能在保证结果相同的情况下更改代码,如果编译器编写者无法提供结果相同的数学证明,则编译器无法更改代码。第一种情况有两次舍入操作,对不同的数进行舍入,所以不太可能保证结果相同。
编译器不像数学家那样思考。在您认为简化表达式在数学上微不足道的地方,编译器还有很多其他事情需要考虑。实际上,编译器很可能比程序员聪明得多,而且对 C 标准的了解也多得多。
优化编译器的 "mind":
可能就是这样的事情- 啊,他们写了
a / b
但只在一个地方使用x
,所以我们不必在堆栈上分配那个变量。我将删除它并使用 CPU 寄存器。 - 嗯,整数文字 1 除以浮点变量。好的,我们必须先在这里调用平衡,然后将该文字转换为浮点数
1.0f
. - 程序员指望我生成的代码包含将
1.0f
除以另一个浮点变量所涉及的潜在浮点不准确!所以我不能只用b / a
交换这个表达式,因为那样的话程序员似乎想要的浮点不准确就会丢失。
等等。有 很多 的注意事项。您最终得到的机器代码很难提前预测。只知道编译器会严格按照您的说明进行操作。