0-a 与 -a 的性能区别

本文最后更新于:2022年5月1日 晚上

〇、前言

今天逛 V2EX 发现了一个很有意思的问题:用 0-a 替换 -a 能提升性能,原帖链接。楼主和评论区大神都做了实验,并讲解了原理(一个是减法 一个直接取反),现在记录下这个奇技淫巧。

一、测试代码

1
2
3
4
5
6
7
void func1(double a) {
volatile auto a1 = -a;
}

void func2(double a) {
volatile auto a2 = 0-a;
}

二、汇编

汇编代码产生于 https://godbolt.org

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
func1(double):
push rbp
mov rbp, rsp
movsd QWORD PTR [rbp-24], xmm0

movsd xmm0, QWORD PTR [rbp-24]
movq xmm1, QWORD PTR .LC0[rip]
xorpd xmm0, xmm1
movsd QWORD PTR [rbp-8], xmm0

nop
pop rbp
ret
func2(double):
push rbp
mov rbp, rsp
movsd QWORD PTR [rbp-24], xmm0

pxor xmm0, xmm0
subsd xmm0, QWORD PTR [rbp-24]
movsd QWORD PTR [rbp-8], xmm0

nop
pop rbp
ret
.LC0:
.long 0
.long -2147483648
.long 0
.long 0

三、原理

对于浮点数来讲:由于存在 rounding error(化整误差),GDB 对一些操作不会优化。a 取反是和 -0.0 取异或;而 0 - a 调用的是 sub,汇编指令比 -a 要少一条

对于整数而言:0-a、-a 最终都会被优化成一样的汇编代码

四、参考链接

  1. -a 和 0-a 有什么区别?

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!