英文:
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
}
英文:
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 == ""
return t;
for (var n = 0; n < e.length; n++) {
t = (t << 5) - t + e.charCodeAt(n),
t &= t
}
return t
}sd
c("Google") // returns 2138589785
c("Google1") // returns 1871773944
Port in Go
package main
import (
"fmt"
)
func main() {
fmt.Println(CountChars("Google")) // returns 2138589785
fmt.Println(CountChars("Google1")) // returns 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
}
答案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 > 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 == "" {
return sum
}
for x := 0; x < len(char); x++ {
sum = (sum << 5) - sum + int32(char[x])
sum &= 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 &= sum
: this is a no-op, simply remove this.
The simplified version:
func CountChars(s string) (sum int32) {
for _, r := range s {
sum = (sum << 5) - sum + r
}
return
}
Testing it:
fmt.Println(CountChars("Google 世界"))
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 (
"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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论