改装 1024 真的比改装 1023 快吗?

Is modding 1024 really faster than modding 1023?

我的同事告诉我,代码修改 2 的功能将针对位操作进行优化,并且比修改其他数字更快。我已经检查了证明他的选择的组件。但是我用 Golang 写了一个基准代码,运行 它是用 Go 版本 1.17 编写的。好像没有太大区别。为什么会这样,他是对的吗?

这是 Golang 代码:

package main

import (
    "fmt"
    "time"
)

const loop = 10000000000

func Mod1024() int {
    sum := 0
    for i := 0; i < loop; i++ {
        sum += i % 1024
    }
    return sum
}

func Mod1023() int {
    sum := 0
    for i := 0; i < loop; i++ {
        sum += i % 1023
    }
    return sum
}

func main() {
    start := time.Now()
    Mod1023()
    fmt.Println(time.Since(start).Microseconds())

    start = time.Now()
    Mod1024()
    fmt.Println(time.Since(start).Microseconds())
}

我电脑上的结果是:

2810668
2694136

执行单个 modulo 操作 确实 快,仅需纳秒级。 Mod1024()Mod1023() 函数的作用远不止于此:它们递增并测试循环变量,执行加法并将结果存储在局部变量中。这些总共比简单的 modding 操作多几个数量级,无论是否针对位屏蔽进行了优化。

此外,将任何代码作为主应用程序的一部分进行基准测试从来都不是一个好主意,有许多因素会扭曲结果(通常使其完全无用)。参见 。始终使用 Go 的测试框架(具有基准测试功能)来更可靠地对代码进行基准测试。

那么让我们mod验证示例函数:

func Mod1023() {
    for i := 23; i%1023 != 0; i++ {
    }
}

func Mod1024() {
    for i := 24; i%1024 != 0; i++ {
    }
}

(上述函数中的循环将有 1000 次迭代。)

然后让我们使用 Go 的测试框架编写适当的基准测试函数:

func BenchmarkMod1023(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Mod1023()
    }
}

func BenchmarkMod1024(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Mod1024()
    }
}

运行基准使用go test -bench .,输出为:

BenchmarkMod1023-8        881263              1346 ns/op
BenchmarkMod1024-8       3710430               325.4 ns/op

所以是的,mod通过 1024 优化了位掩码,实际上速度更快:大约 快 4 倍。由于优化(1.3 ns 与 0.3 ns),为您节省了一整纳秒。尽管这仅在您必须执行数百万次并且执行过程中没有其他代码比简单的 CPU mod 操作慢时才重要。