Die Ausführung der Golang-Mathematik ist langsam, wenn Code verwendet wird

王林
Freigeben: 2024-02-05 21:39:03
nach vorne
895 Leute haben es durchsucht

使用代码时 Golang 数学执行缓慢

问题内容

问题:使用 math 包中的代码比使用 math 包慢得多。

下面的代码是从数学模块复制的,但是 math.Sqrt 的执行速度比 sqrt 快得多。我的问题是:为什么,可以做什么?

示例:(注意,感兴趣的函数不是 math.Sqrt。我想编写函数组合的自定义版本。)

package main

import (
    "fmt"
    "math"
    "unsafe"
)

const (
    uvnan    = 0x7FF8000000000001
    uvinf    = 0x7FF0000000000000
    uvneginf = 0xFFF0000000000000
    uvone    = 0x3FF0000000000000
    mask     = 0x7FF
    shift    = 64 - 11 - 1
    bias     = 1023
    signMask = 1 << 63
    fracMask = 1<<shift - 1
)

func Float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) }
func Float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) }
func sqrt(x float64) float64 {
    // special cases
    ix := Float64bits(x)
    // normalize x
    exp := int((ix >> shift) & mask)
    if exp == 0 { // subnormal x
        for ix&(1<<shift) == 0 {
            ix <<= 1
            exp--
        }
        exp++
    }
    exp -= bias // unbias exponent
    ix &^= mask << shift
    ix |= 1 << shift
    if exp&1 == 1 { // odd exp, double x to make it even
        ix <<= 1
    }
    exp >>= 1 // exp = exp/2, exponent of square root
    // generate sqrt(x) bit by bit
    ix <<= 1
    var q, s uint64               // q = sqrt(x)
    r := uint64(1 << (shift + 1)) // r = moving bit from MSB to LSB
    for r != 0 {
        t := s + r
        if t <= ix {
            s = t + r
            ix -= t
            q += r
        }
        ix <<= 1
        r >>= 1
    }
    // final rounding
    if ix != 0 { // remainder, result not exact
        q += q & 1 // round according to extra bit
    }
    ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
    return Float64frombits(ix)
}

func main() {
    n_iter := 100000000
    var x float64
    var y float64
    for i := 0; i < n_iter; i++ {
        y = math.Sqrt(2426.1)
    }
    fmt.Printf("Done\n") // Much, much faster

    for i := 0; i < n_iter; i++ {
        x = sqrt(2426.1)
    }
    fmt.Printf("Done\n")
    fmt.Printf("%f/%f\n", x, y)
}
Nach dem Login kopieren


正确答案


检查 math.Sqrt 的生成代码。使用 -S 标志构建此 main.go

package main

import (
    "fmt"
    "math"
    "math/rand"
)

func main() {
    x := rand.Float64()
    y := math.Sqrt(x)
    fmt.Println(y)
}
Nach dem Login kopieren

生成程序集:go build -gcflags='-S' main.go

...
        0x000e 00014 (./main.go:10)     PCDATA  $1, $0
        0x000e 00014 (./main.go:10)     CALL    math/rand.Float64(SB)
        0x0013 00019 (/home/user/go/pkg/mod/golang.org/<a href="https://www.php.cn/link/89fee0513b6668e555959f5dc23238e9" class="__cf_email__" data-cfemail="8afee5e5e6e9e2ebe3e4cafcbaa4baa4bba7ede5bba4b8bba4bfa4e6e3e4fff2a7ebe7eebcbe">[email&#160;protected]</a>/src/math/sqrt.go:94)    SQRTSD  X0, X0
        0x0017 00023 (./main.go:12)     MOVQ    X0, AX
        0x001c 00028 (./main.go:11)     XCHGL   AX, AX
...
Nach dem Login kopieren

可以看到,实际调用的是SQRTSD机器指令。

它受 cmd/compile/internal/ssagen/ssa.go 配置:在平台 sys.I386、sys.AMD64、sys.ARM、sys.ARM64、sys.Loong64、sys.MIPS、sys. MIPS64、sys.PPC64、sys.RISCV64、sys.S390X、sys.Wasm 编译器插入 SQRT 操作码。

您还可以检查许多其他被汇编替换的函数。

顺便说一句。在示例中,我在随机参数上调用 math.Sqrt ,因为对于文字值,编译器会计算平方根本身并编译为实际值。

这里是math.Sqrt(2.0)的汇编代码

0x0014 00020 (./main.go:11)     MOVQ    $4609047870845172685, AX
0x001e 00030 (./main.go:11)     PCDATA  $1, $1
0x001e 00030 (./main.go:11)     NOP
0x0020 00032 (./main.go:11)     CALL    runtime.convT64(SB)
0x0025 00037 (./main.go:11)     LEAQ    type:float64(SB), CX
Nach dem Login kopieren

4609047870845172685 是 64 位表示形式的实际 sqrt(2)

Das obige ist der detaillierte Inhalt vonDie Ausführung der Golang-Mathematik ist langsam, wenn Code verwendet wird. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:stackoverflow.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage