Golang模拟JavaScript中的左右移位运算符实现

Golang模拟JavaScript中的左右移位运算符实现 我需要实现与JavaScript中相同的位移运算结果。该如何实现?

目前在JavaScript中:

console.log(20192019 << 10);   // -798209024
console.log(201920192019 >> 2) // 14182276

目前在Go中:

fmt.Println(20192019 << 10)    // 20676627456
fmt.Println(201920192019 >> 2) // 50480048004

我希望在Go中实现:

fmt.Println(20192019 << 10)    // -798209024
fmt.Println(201920192019 >> 2) // 14182276

谢谢!


更多关于Golang模拟JavaScript中的左右移位运算符实现的实战教程也可以访问 https://www.itying.com/category-94-b0.html

12 回复

现在我想知道为什么将其包装在函数中会改变行为?

更多关于Golang模拟JavaScript中的左右移位运算符实现的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我的输出:

20676627456
50480048004

[@enzovitaliy] 这个方案对你有用吗:https://play.golang.org/p/3caJWUs5IjG

我理解,但是是否有可能从64位数模拟出32位数?我尝试用不同的系数减去32位数,有时候能成功,但只针对特定值。

你所说的"有时候"是什么意思?

如果你需要64位精度,那就坚持使用它;如果你需要32位精度,那就不要使用64位。

// 代码示例保留原样

使用 int64 就不会出现 int32 的溢出行为,这正是我之前说"附注:强制使用 int32 可能已经足够,不过 201920192019 这个值已经会导致溢出……"时想要表达的意思。

这是因为当你使用常量并对常量进行位移操作时,编译器会将它们折叠成常量,并且知道它们超出了范围。通过将int64int32的转换放入函数中,溢出会被推迟到运行时,而在运行时溢出是不被检查的。

NobbZ:

你所说的"有时候"是什么意思?

它对特定值有效,但如果我改变这个值,就不再起作用了。 类似 1 << 32, (1 << 32) * 5 这样的情况(这些是我前面提到的系数)。

是的,你之前已经提到过,但能否请你分享产生该输出的确切代码?将你上面的代码片段放入 playground 的 main 函数中会产生所引用的编译错误。

https://play.golang.org/p/240I3ZjBMle

NobbZ:

是的,您已经提到过这一点,但能否请您分享产生该输出的确切代码?将您上面的代码片段放入 Playground 的 main 函数中会产生所引用的编译错误。

在 Playground 上,您需要显式将类型转换为 int64:

package main

import (
	"fmt"
)

func main() {
	fmt.Println(int64(20192019) << 10)
	fmt.Println(int64(201920192019) >> 2)
}

引用 enzovitaliy:

fmt.Println(20192019     << 10) // -798209024
fmt.Println(201920192019 >>  2) // 14182276

嗯,我实际看到的是:

./prog.go:8:23: constant 20676627456 overflows int
./prog.go:9:27: constant 50480048004 overflows int

那么你能否展示一下实际产生你所见结果的代码呢?

PS:强制使用 int32 可能就足够了,不过 201920192019 在这种情况下已经溢出了……

在Go中实现与JavaScript相同的位移运算结果,关键在于处理整数溢出和符号扩展的差异。JavaScript使用32位有符号整数进行位移运算,而Go会根据操作数类型自动选择位数。

以下是解决方案:

package main

import "fmt"

// 模拟JavaScript的32位左移运算
func jsLeftShift(x int32, n uint) int32 {
    return x << n
}

// 模拟JavaScript的32位右移运算
func jsRightShift(x int32, n uint) int32 {
    return x >> n
}

// 处理大整数的辅助函数
func toInt32(x int64) int32 {
    return int32(x)
}

func main() {
    // 示例1: 20192019 << 10
    result1 := jsLeftShift(toInt32(20192019), 10)
    fmt.Println(result1) // -798209024
    
    // 示例2: 201920192019 >> 2
    result2 := jsRightShift(toInt32(201920192019), 2)
    fmt.Println(result2) // 14182276
}

更简洁的写法:

package main

import "fmt"

func main() {
    // 直接转换为int32进行位移运算
    fmt.Println(int32(20192019) << 10)    // -798209024
    fmt.Println(int32(201920192019) >> 2) // 14182276
}

对于通用的JavaScript位移运算模拟:

package main

import "fmt"

// 模拟JavaScript的<<运算符
func jsLeftShift(val interface{}, shift uint) int32 {
    switch v := val.(type) {
    case int:
        return int32(v) << shift
    case int32:
        return v << shift
    case int64:
        return int32(v) << shift
    default:
        return 0
    }
}

// 模拟JavaScript的>>运算符
func jsRightShift(val interface{}, shift uint) int32 {
    switch v := val.(type) {
    case int:
        return int32(v) >> shift
    case int32:
        return v >> shift
    case int64:
        return int32(v) >> shift
    default:
        return 0
    }
}

func main() {
    fmt.Println(jsLeftShift(20192019, 10))    // -798209024
    fmt.Println(jsRightShift(201920192019, 2)) // 14182276
}

关键点:

  • JavaScript位移运算基于32位有符号整数
  • 在Go中需要明确转换为int32类型
  • 溢出时会产生与JavaScript相同的结果
  • 右移运算会保持符号位(算术右移)
回到顶部