为了账号安全,请及时绑定邮箱和手机立即绑定

为什么是数学。战俘性能比位移差?

为什么是数学。战俘性能比位移差?

Go
慕侠2389804 2022-09-12 16:57:33
在 Exercism 网站上解决此练习时,我使用了标准数学。Pow包函数获得两个的提升幂。return uint64(math.Pow(2, float64(n-1)))在检查了社区解决方案之后,我发现了一个使用位移来实现相同目标的解决方案:return uint64(1 << uint(n-1)), nil令我惊讶的是,两者之间有很大的性能差异:位移数学pow我以为Go编译器会识别出这种数学。Pow使用常量2作为基础,并且只是自己使用位移位,而我没有明确地这样做。我能看到的唯一其他区别是 float64 的转换和数学运算。Pow 在浮点数上运行,而不是在整数上运行。为什么编译器不优化电源操作以实现类似于位移位的性能?
查看完整描述

3 回答

?
MYYA

TA贡献1868条经验 获得超4个赞

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


通常,您建议的优化不正确。编译器必须能够推断出该值是否在特定范围内。n


请参阅此示例(在操场上)


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


查看完整回答
反对 回复 2022-09-12
?
桃花长相依

TA贡献1860条经验 获得超8个赞

数学。Pow() 用于对数字进行操作。位移位以计算 2 的幂只能应用于整数,并且只能应用于结果适合(或 )的微小子集。float64int64uint64

如果您有这样的特殊情况,我们非常欢迎您使用位移位。

结果大于或基数不是(或 的幂)的任何其他情况都需要浮点运算。math.MaxInt6422

另请注意,即使将实现对上述可能的微小子集的检测,结果也是2的补码格式,该格式也必须转换为IEEE 754格式,因为返回值为is(尽管这些数字可以被缓存),您很可能会再次将其转换回。math.Pow()float64int64

同样:如果需要性能,请使用显式位移位。


查看完整回答
反对 回复 2022-09-12
?
千万里不及你

TA贡献1784条经验 获得超9个赞

因为这种优化从未实施过。

go编译器旨在实现快速的编译时间。因此,一些优化被认为是不值得的。这节省了编译时间,但代价是需要一些运行时。


查看完整回答
反对 回复 2022-09-12
  • 3 回答
  • 0 关注
  • 80 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信