Go使用位运算符返回的和与JavaScript不同。

huangapple go评论80阅读模式
英文:

Go returns other sum using bitwise operator than javascript

问题

我已经为你翻译了内容,请查看以下翻译结果:

我尝试使用Go语言将一个在JS中编写的函数进行移植,但是我遇到了一个奇怪的问题。该函数的目标是对字符串中的每个字母的ASCII码进行求和。

当字符串长度小于等于6时,一切正常。但是在此之后,Go语言返回了其他结果。

JS中的原始函数

function c(e) { // e是字符串
    var t = 0;
    if (!e) // 如果e为空字符串
        return t;
    for (var n = 0; n < e.length; n++) {
        t = (t << 5) - t + e.charCodeAt(n);
        t &= t;
    }
    return t;
}

c("Google") // 返回 2138589785
c("Google1") // 返回 1871773944

Go语言中的移植版本

package main

import (
	"fmt"
)

func main() {
	fmt.Println(CountChars("Google")) // 返回 2138589785
	fmt.Println(CountChars("Google1")) // 返回 66296283384
}

func CharCodeAt(s string) int {
	return int([]rune(s)[0])
}

func CountChars(char string) int {
	var sum int = 0
	if char == "" {
		return sum
	}
	for x := 0; x < len(char); x++ {
		charToCode := string(char[x])
		sum = (sum << 5) - sum + CharCodeAt(charToCode)
		sum &= sum
	}
	return sum
}

Go playground

JS playground in playcode

英文:

I've tried to make port of function made in JS using Go but I'm facing strange problem. The goal of function is to sum ascii codes from every letter in string.

Everything is fine until string length is <= 6 After that Go returns other results.

Original from JS

function c(e) { // e is string
    var t = 0;
     if (!e) // if e == &quot;&quot;
       return t;
     for (var n = 0; n &lt; e.length; n++) {
            t = (t &lt;&lt; 5) - t + e.charCodeAt(n),
            t &amp;= t
     }
     return t
}sd
c(&quot;Google&quot;) // returns 2138589785
c(&quot;Google1&quot;) // returns 1871773944

Port in Go

package main

import (
	&quot;fmt&quot;
)

func main() {
	fmt.Println(CountChars(&quot;Google&quot;)) // returns 2138589785
	fmt.Println(CountChars(&quot;Google1&quot;)) // returns 66296283384
}

func CharCodeAt(s string) int {
	return int([]rune(s)[0])
}

func CountChars(char string) int {
	var sum int = 0
	if char == &quot;&quot; {
		return sum
	}
	for x:=0; x&lt;len(char); x++ {
		charToCode := string(char[x])
		sum = (sum &lt;&lt; 5) - sum + CharCodeAt(charToCode)
		sum &amp;= sum
	}
	return sum
}

Go playground

JS playground in playcode

答案1

得分: 5

在JavaScript中,整数是32位的,而Go语言的int类型是与架构相关的,可能是32位或64位。在Go Playground上,它是64位的。由于每次迭代都会左移5位,所以在JavaScript中使用超过6个字符肯定会"溢出"(但在Go中尚未溢出):7*5=35 > 32位

为了获得与JavaScript相同的输出,可以使用显式的32位整数(int32):

func CountChars(char string) int32 {
    var sum int32 = 0
    if char == "" {
        return sum
    }
    for x := 0; x < len(char); x++ {
        sum = (sum << 5) - sum + int32(char[x])
        sum &= sum
    }
    return sum
}

这样输出将与JavaScript中的输出相同(在Go Playground上尝试一下):

2138589785
1871773944

还要注意,Go将字符串存储为它们在内存中的UTF-8字节序列,并且索引字符串(如char[x])会索引它的字节,即UTF-8序列。在您的示例中,这是可以的,因为所有输入字符都使用单个字节进行编码,但如果输入包含多字节字符,则会得到不同的结果。

为了正确处理所有情况,请使用简单的for range循环遍历字符串:它返回连续的符文,这也是int32的别名,因此您可以获得所需的码点。

另外,检查空字符串是不必要的,如果字符串为空,循环体将不会执行。另外,sum &= sum是一个无操作,可以直接删除。

简化版本如下:

func CountChars(s string) (sum int32) {
    for _, r := range s {
        sum = (sum << 5) - sum + r
    }
    return
}

测试一下:

fmt.Println(CountChars("Google 世界"))

将输出与JavaScript中的输出相同(在Go Playground上尝试一下):

-815903459
英文:

Integers in Javascript are 32-bit, while Go's int is architecture dependent, may be 32 bit and 64 bit. It's 64-bit on the Go Playground. And since each iteration shifts left by 5, using more than 6 characters surely "overflows" in Javascript (but not yet in Go): 7*5=35 &gt; 32 bits.

Use explicit 32-bit integers (int32) to have the same output as in Javascript:

func CountChars(char string) int32 {
	var sum int32 = 0
	if char == &quot;&quot; {
		return sum
	}
	for x := 0; x &lt; len(char); x++ {
		sum = (sum &lt;&lt; 5) - sum + int32(char[x])
		sum &amp;= sum
	}
	return sum
}

This way output will be the same as that of Javascript (try it on the Go Playground):

2138589785
1871773944

Also note that Go stores strings as their UTF-8 byte sequences in memory, and indexing a string (like char[x]) indexes its bytes, the UTF-8 sequence. This is fine in your example as all the input characters are encoded using a single byte, but you'll get different result if the input contains multi-byte characters.

To properly handle all cases, use a simple for range over the string: that returns the successive runes, which is also an alias to int32, so you get the code points you need.

Also that check for empty string is unnecessary, if it's empty, the loop body will not be executed. Also sum &amp;= sum: this is a no-op, simply remove this.

The simplified version:

func CountChars(s string) (sum int32) {
	for _, r := range s {
		sum = (sum &lt;&lt; 5) - sum + r
	}
	return
}

Testing it:

fmt.Println(CountChars(&quot;Google 世界&quot;))

Will output the same as in Javascript (try this one on the Go Playground):

-815903459

答案2

得分: 4

这是一个大小调整问题。JavaScript中的整数是32位的,而Go中的整数不一定是32位的。如果您依赖于特定的整数大小,您应该通过将int替换为int32来指定它。

修改后的代码如下(playground):

package main

import (
	"fmt"
)

func main() {
	fmt.Println(CountChars("Google"))
	fmt.Println(CountChars("Google1"))
}

func CharCodeAt(s string, n int) int32 {
	return int32(s[n])
}

func CountChars(char string) int32 {
	var sum int32 = 0
	if char == "" {
		return sum
	}
	for x := 0; x < len(char); x++ {
		sum = (sum << 5) - sum + CharCodeAt(char, x)
		sum &= sum
	}
	return sum
}

希望对您有所帮助!

英文:

It's a sizing issue. JS ints are 32 bits and Go ints are not necessarily 32 bits. If you are relying on a specific int size you should specify it by replacing instances of int with int32.

What that looks like (playground):

package main

import (
	&quot;fmt&quot;
)

func main() {
	fmt.Println(CountChars(&quot;Google&quot;))
	fmt.Println(CountChars(&quot;Google1&quot;))
}

func CharCodeAt(s string, n int) int32 {
	return int32(s[n])
}

func CountChars(char string) int32 {
	var sum int32 = 0
	if char == &quot;&quot; {
		return sum
	}
	for x:=0; x&lt;len(char); x++ {
		sum = (sum &lt;&lt; 5) - sum + CharCodeAt(char, x)
		sum &amp;= sum
	}
	return sum
}

huangapple
  • 本文由 发表于 2021年8月27日 20:40:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/68953623.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定