gpt4 book ai didi

c++ - 为什么在 C++ 中不能很好地优化天真的 abs 实现?

转载 作者:行者123 更新时间:2023-12-01 12:32:56 27 4
gpt4 key购买 nike

我正在研究 abs(float) 的幼稚实现会编译并且对结果感到非常惊讶:

float abs(float x) {
return x < 0 ? -x : x;
}
使用 -O3 处的 clang 10.1,这会导致:
.LCPI0_0:
.long 2147483648 # float -0
.long 2147483648 # float -0
.long 2147483648 # float -0
.long 2147483648 # float -0
abs(float):
movaps xmm2, xmmword ptr [rip + .LCPI0_0]
xorps xmm2, xmm0
xorps xmm3, xmm3
movaps xmm1, xmm0
cmpltss xmm1, xmm3
andps xmm2, xmm1
andnps xmm1, xmm0
orps xmm1, xmm2
movaps xmm0, xmm1
ret
我觉得这很令人惊讶,因为老实说,我只是希望浮点数的符号位被清除,这应该只是一个 XOR 指令。一定有一些关于 IEEE-754 浮点语义的东西导致了这种复杂化,但我只是不明白是什么让它 复杂的。为什么您只需要比较和有条件的移动?
也许是因为与 NaN 的比较总是会失败,所以在这种情况下符号位不会被清除?但是由于 NaN 的符号位可以是 0 或 1,所以这无关紧要。
为了比较,当简单地使用 std::fabs 时输出要简单得多,这正是人们所期望的:
abs(float):
andps xmm0, xmmword ptr [rip + .LCPI0_0]
ret
启用 -ffast-math 时会产生相同的输出旗帜。
更新: -O3 处的 gcc 10.2 产生:
abs(float):
pxor xmm1, xmm1
comiss xmm1, xmm0
ja .L6
ret
.L6:
xorps xmm0, XMMWORD PTR .LC1[rip]
ret

最佳答案

IEEE 浮点空间包含许多特殊值,例如正负 0、正无穷大和负无穷大以及“非数字”(NaN) 的两个系列。所有这些值都具有明确定义的语义。 <运算符,因此编译器必须生成正确处理所有特殊情况的代码。
旗帜-ffast-math可用于通知编译器它可能假设未使用特殊值,正负 0 之间的区别无关紧要,并进行一些其他简化假设(例如加法是关联的)。使用此标志,clang 会为您的 abs 生成可能是最佳的代码。功能:

abs:
andps .LCPI0_0(%rip), %xmm0
retq
默认情况下尊重有些巴洛克式的 IEEE 语义的选择有些争议;除了 gcc 和 clang 之外的编译器倾向于做出相反的选择,默认情况下它们编译快速和紧凑的代码,如果需要完全符合 IEEE 标准,则需要一个明确的命令行标志(例如 -mp 在英特尔编译器的情况下)。

关于c++ - 为什么在 C++ 中不能很好地优化天真的 abs 实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63347301/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com