我很好奇使用像
这样的微优化是否有意义a / 2
与a >> 1
对比
a * 2
vs a << 1
a % 2
vs a & 1
我知道任何体面的C编译器都可以处理这个问题。另外请不要写关于过早优化,因为这些技术是如此明显,甚至不是优化,更像是喜欢如何编写代码。
P.S。我试图做基准测试,时间上的差异在统计上并不显着。我不知道如何检查go的字节码,所以谢谢你的指点。
答案 0 :(得分:10)
简短的回答,是的,编译器优化了这些。
但int
vs uint
(并且可能是任何有符号与无符号整数类型,例如byte
)的情况略有不同。
在这两种情况下都可以避免乘法和除法指令,但它只是无符号整数的单个指令(以及有符号整数的少量指令)。 那是因为你的成对语句只对无符号整数完全等价而不是有符号整数。
更长的回答:
采取一个简单的程序,如:
package main
func main() {}
func div2(a int) {
b := a / 2
c := a >> 1
_, _ = b, c
}
func mul2(a int) {
b := a * 2
c := a << 1
_, _ = b, c
}
func mod2(a int) {
b := a % 2
c := a & 1
_, _ = b, c
}
并且运行go build -gcflags="-S"
将为您提供汇编输出,例如:
"".mod2 t=1 size=32 value=0 args=0x8 locals=0x0
0x0000 00000 (…/opt.go:17) TEXT "".mod2+0(SB),4,$0-8
…
0x0000 00000 (…/opt.go:17) MOVQ "".a+8(FP),BX
…
0x0005 00005 (…/opt.go:18) MOVQ BX,AX
0x0008 00008 (…/opt.go:18) SARQ $63,AX
0x000c 00012 (…/opt.go:18) MOVQ BX,DX
0x000f 00015 (…/opt.go:18) SUBQ AX,DX
0x0012 00018 (…/opt.go:18) ANDQ $1,DX
0x0016 00022 (…/opt.go:18) ADDQ AX,DX
0x0019 00025 (…/opt.go:19) ANDQ $1,BX
0x001d 00029 (…/opt.go:21) RET ,
此处BX
是参数,DX
和BX
似乎是两个结果
(BX
被重用作其中一个结果)。
这里它们略有不同,但只有几条说明
(查看显示的源行号)
并且没有任何除法或乘法指令
(所以基本上一样快)。
差异是由于算法与逻辑的变化以及Go如何对负值进行模拟。
您可以通过在程序中将int
更改为uint
来确认,然后输出包含以下内容:
0x0008 00008 (…/opt.go:18) ANDQ $1,CX
0x000c 00012 (…/opt.go:19) ANDQ $1,BX
即。完全相同的指令。 对于您提供的每个示例都是如此。