许多算法需要计算(-1)^n
(其中n为整数),通常作为序列中的因子。也就是说,这个因子对于奇数n为-1
,对于偶数n为1
。在C++环境中,常常可以看到以下代码:
#include<iostream>
#include<cmath>
int main(){
int n = 13;
std::cout << std::pow(-1, n) << std::endl;
}
什么更好或更常见?(或其他什么),
std::pow(-1, n)
std::pow(-1, n%2)
(n%2?-1:1)
(1-2*(n%2)) // (gives incorrect value for negative n)
编辑:
此外,用户@SeverinPappadeux提出了另一种基于(全局?)数组查找的替代方案。 我的版本如下:
const int res[] {-1, 1, -1}; // three elements are needed for negative modulo results
const int* const m1pow = res + 1;
...
m1pow[n%2]
这可能无法解决问题,但通过使用生成的代码,我们可以排除一些选项。
首先,在没有优化的情况下,最终的竞争者是:
1 - ((n & 1) << 1);
(7个操作,无内存访问)
mov eax, DWORD PTR [rbp-20]
add eax, eax
and eax, 2
mov edx, 1
sub edx, eax
mov eax, edx
mov DWORD PTR [rbp-16], eax
and retvals[n&1];
(5个操作、内存 --寄存器?-- 访问)
mov eax, DWORD PTR [rbp-20]
and eax, 1
cdqe
mov eax, DWORD PTR main::retvals[0+rax*4]
mov DWORD PTR [rbp-8], eax
现在使用优化(-O3)
1 - ((n & 1) << 1);
(四则运算,无内存访问)
add edx, edx
mov ebp, 1
and edx, 2
sub ebp, edx
.
retvals[n&1];
(4个操作,内存--寄存器?--访问)
mov eax, edx
and eax, 1
movsx rcx, eax
mov r12d, DWORD PTR main::retvals[0+rcx*4]
.
n%2?-1:1;
(4个操作,无内存访问)
cmp eax, 1
sbb ebx, ebx
and ebx, 2
sub ebx, 1
测试在这里。我必须进行某些特技才能获得有意义的代码,而不会完全省略操作。
结论(暂时)
因此,最终取决于优化和表达能力的水平:
1 - ((n & 1) << 1);
总是不错的选择,但表达能力不够。retvals[n&1];
付出了内存访问的代价。n%2?-1:1;
具有表达力且效果良好,但仅在优化时才如此。
pow
是一个浮点数函数,所以我会避免使用它。n%2 ? -1 : 1
似乎是最简单明了的选择。 - M.M(n&1) ? -1 : 1
。一些人觉得这种写法不太容易理解,但是在它旁边加上注释可以澄清其含义,并且位掩码运算速度较快。 - pjs(n&1)? -1: 1
应该更快--虽然在一般情况下它不等价,因此可能不会自动优化。 - Ben Voigtn%2
在此处立即转换为bool
,我预期代码生成是相同的。 - T.C.1 - 2*(n&1)
是正确的,而问题中的(1 - 2*(n%2))
可能会得出 -1、1 或者 3。 - Ben Voigt