go - 为什么 math.Pow 的性能比位移差?

标签 go compiler-optimization bit-shift

解决this exercise时在 Exercism 网站上,我使用了标准的 math.Pow 包函数来获得两个的幂。

return uint64(math.Pow(2, float64(n-1)))

在查看社区解决方案后,我找到了一个使用位移来实现相同目的的解决方案:

return uint64(1 << uint(n-1)), nil

令我惊讶的是,两者之间存在很大的性能差异: bit-shifting math-pow

我认为 Go 编译器会识别出 math.Pow 使用常量 2 作为基数,并且只使用它自己的位移位,而无需我明确地这样做。我能看到的唯一其他区别是 float64 的转换和 math.Pow 是对 float 而不是整数进行运算。

为什么编译器不优化幂运算以达到类似于位移位的性能?

最佳答案

首先,请注意 uint64(1) << (n-1)是表达式 uint64(1 << uint(n-1)) 的更好版本出现在你的问题中。表达式 1<<n是一个 int ,因此有效的移位值介于 0 和 30 或 62 之间,具体取决于 int 的大小。 uint64(1) << n允许 n介于 0 和 63 之间。

总的来说,您建议的优化是不正确的。编译器必须能够推断出 n在特定范围内。

查看此示例 (on playground)

package main

import (
    "fmt"
    "math"
)

func main() {
    n := 65
    fmt.Println(uint64(math.Pow(2, float64(n-1))))
    fmt.Println(uint64(1) << uint(n-1))
}

输出表明这两种方法是不同的:

9223372036854775808
0

关于go - 为什么 math.Pow 的性能比位移差?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68267574/

相关文章:

go - 使用嵌套结构和文本/模板包时,删除打印的{}大括号

c++ - 在不改变值(value)、性能的情况下多次访问位域?

c++ - 如何在 C++ 中获取内存位置而不等待其检索?

javascript - 逻辑移位如何在 javascript 中工作

c - AND 0xFF 有什么作用?

go - 如何访问另一个结构内的 golang 结构数组?

elasticsearch - 使用 golang 包 'elastic' 中的 BulkIndexRequest

golang 导入包内包

c++ - Visual Studio 2013 优化标志(/O2 与/Ox)

c++ - 从十六进制中获取 LSB 的值(C 代码)