Sub*_*nil 51 c c++ variables negation absolute-value
在C/C++中,为什么要使用abs()或fabs()找到变量的绝对值而不使用以下代码?
int absoluteValue = value < 0 ? -value : value;
Run Code Online (Sandbox Code Playgroud)
是否与较低级别的较少指令有关?
Bau*_*gen 119
您建议的"条件绝对值"不等于std::abs(或fabs)浮点数,请参见例如
#include <iostream>
#include <cmath>
int main () {
double d = -0.0;
double a = d < 0 ? -d : d;
std::cout << d << ' ' << a << ' ' << std::abs(d);
}
Run Code Online (Sandbox Code Playgroud)
输出:
-0 -0 0
Run Code Online (Sandbox Code Playgroud)
给定-0.0并0.0表示相同的实数"0",这种差异可能或可能不重要,这取决于结果的使用方式.但是,IEEE754规定的abs函数要求结果的signbit为0,这将禁止结果-0.0.我个人认为用于计算某些"绝对值"的任何东西都应该符合这种行为.
对于整数,两种变体在运行时和行为上都是等价的.(实例)
但是,正如std::abs(或拟合C等价物)已知正确且易于阅读,您应该总是喜欢这些.
iBu*_*Bug 86
首先想到的是可读性.
比较这两行代码:
int x = something, y = something, z = something;
// Compare
int absall = (x > 0 ? x : -x) + (y > 0 ? y : -y) + (z > 0 ? z : -z);
int absall = abs(x) + abs(y) + abs(z);
Run Code Online (Sandbox Code Playgroud)
Mat*_*son 28
编译器最有可能在底层做同样的事情 - 至少是一个现代的合格编译器.
但是,至少对于浮点数,如果你想处理无穷大,非数字(NaN),负零等所有特殊情况,你最终会写几十行.
同样,它更容易阅读,abs它取绝对值而不是读取,如果它小于零,则取消它.
如果编译器是"愚蠢的",它可能最终会做更糟糕的代码a = (a < 0)?-a:a,因为它强制一个if(即使它被隐藏),并且这可能比该处理器上的内置浮点abs指令更糟糕(除了特殊价值的复杂性)
Clang(6.0-pre-release)和gcc(4.9.2)都为第二种情况生成WORSE代码.
我写了这个小样本:
#include <cmath>
#include <cstdlib>
extern int intval;
extern float floatval;
void func1()
{
int a = std::abs(intval);
float f = std::abs(floatval);
intval = a;
floatval = f;
}
void func2()
{
int a = intval < 0?-intval:intval;
float f = floatval < 0?-floatval:floatval;
intval = a;
floatval = f;
}
Run Code Online (Sandbox Code Playgroud)
clang为func1创建了这段代码:
_Z5func1v: # @_Z5func1v
movl intval(%rip), %eax
movl %eax, %ecx
negl %ecx
cmovll %eax, %ecx
movss floatval(%rip), %xmm0 # xmm0 = mem[0],zero,zero,zero
andps .LCPI0_0(%rip), %xmm0
movl %ecx, intval(%rip)
movss %xmm0, floatval(%rip)
retq
_Z5func2v: # @_Z5func2v
movl intval(%rip), %eax
movl %eax, %ecx
negl %ecx
cmovll %eax, %ecx
movss floatval(%rip), %xmm0
movaps .LCPI1_0(%rip), %xmm1
xorps %xmm0, %xmm1
xorps %xmm2, %xmm2
movaps %xmm0, %xmm3
cmpltss %xmm2, %xmm3
movaps %xmm3, %xmm2
andnps %xmm0, %xmm2
andps %xmm1, %xmm3
orps %xmm2, %xmm3
movl %ecx, intval(%rip)
movss %xmm3, floatval(%rip)
retq
Run Code Online (Sandbox Code Playgroud)
g ++ func1:
_Z5func1v:
movss .LC0(%rip), %xmm1
movl intval(%rip), %eax
movss floatval(%rip), %xmm0
andps %xmm1, %xmm0
sarl $31, %eax
xorl %eax, intval(%rip)
subl %eax, intval(%rip)
movss %xmm0, floatval(%rip)
ret
Run Code Online (Sandbox Code Playgroud)
g ++ func2:
_Z5func2v:
movl intval(%rip), %eax
movl intval(%rip), %edx
pxor %xmm1, %xmm1
movss floatval(%rip), %xmm0
sarl $31, %eax
xorl %eax, %edx
subl %eax, %edx
ucomiss %xmm0, %xmm1
jbe .L3
movss .LC3(%rip), %xmm1
xorps %xmm1, %xmm0
.L3:
movl %edx, intval(%rip)
movss %xmm0, floatval(%rip)
ret
Run Code Online (Sandbox Code Playgroud)
请注意,在第二种形式中,两种情况都明显更复杂,而在gcc情况下,它使用分支.Clang使用了更多指令,但没有分支.我不确定哪种处理器型号更快,但很明显更多的指令很少更好.
chu*_*ica 11
为什么使用abs()或fabs()而不是条件否定?
已经陈述了各种原因,但是abs(INT_MIN)应该考虑应该避免的条件码优势.
abs()当寻求整数的负绝对值时,有充分的理由使用条件代码来代替
// Negative absolute value
int nabs(int value) {
return -abs(value); // abs(INT_MIN) is undefined behavior.
}
int nabs(int value) {
return value < 0 ? value : -value; // well defined for all `int`
}
Run Code Online (Sandbox Code Playgroud)
当需要一个正的绝对函数并且value == INT_MIN是一个真正的可能性时abs(),尽管它的清晰度和速度都没有失败.各种替代品
unsigned absoluteValue = value < 0 ? (0u - value) : (0u + value);
Run Code Online (Sandbox Code Playgroud)
在给定的体系结构上,可能存在比条件分支更高效的低级实现.例如,CPU可能有一条abs指令或一种提取符号位而无需分支开销的方法.假设算术右移可以填写一个登记册[R与-1,如果是负数,或者0,如果积极的,abs x能成为(x+r)^r(和看到垫皮特森的回答,G ++实际上做这在x86).
其他答案已经超越了IEEE浮点的情况.
试图告诉编译器执行条件分支而不是信任库可能是过早的优化.