英文:
Go hashtable: casting without conversion?
问题
我正在实现一个专用的哈希表。我试图将大量数据存储在一个单独的64位整数键中,以节省空间并提高性能。
每个键应具有以下结构:
// 键的结构,从最低位开始
// 评估结果(16位)
// 移动(16位)
// 年龄(16位):此位置可能发生的游戏移动
// 深度(8位)
// 节点类型(8位):来自上述三个常量之一
这是一个简单的实现:
var keys [1000]uint64
var values [1000]uint64
func Put(b *dragontoothmg.Board, m dragontoothmg.Move, eval int16, depth uint8, ntype uint8) {
var value uint64 = uint64(eval) | (uint64(m) << 16) | (uint64(b.Fullmoveno) << 32) |
(uint64(depth) << 48) | (uint64(ntype) << 56)
hash := b.Hash()
key := hash ^ value
index := hash % uint64(len(keys))
keys[index] = key
values[index] = value
}
func Get(b *dragontoothmg.Board) (found bool, move dragontoothmg.Move,
eval int16, depth uint8, ntype uint8) {
hash := b.Hash()
index := hash % uint64(len(keys))
key := keys[index]
value := values[index]
found = (hash == (key ^ value))
if !found {
return false, 0, 0, 0, 0
}
eval = int16(value & 0xFFFF)
move = dragontoothmg.Move((value >> 16) & 0xFFFF)
depth = uint8((value >> 48) & 0xFF)
ntype = uint8((value >> 56) & 0xFF)
return
}
然而,当我尝试Get()
数据时,返回的数据损坏了。我怀疑这可能与eval
是有符号整数,并且强制转换为有符号uint64有关。我做错了什么,如何修复它?
这是失败的测试结果:
--- FAIL: TestSimpleTt (0.10s)
transtable_test.go:37: Simple ttable test failed.
Put data: (board: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 0) e2e4 -30 6 2
Fetched data: true h8h8 -30 255 255
FAIL
h8h8
是该字段的最大值,如果有用的话。
英文:
I am implementing a specialized hashtable. I'm trying store a lot of data in a single 64-bit int key, for space usage and performance reasons.
Each key should have this structure:
// Key structure, from LSB
// eval result (16 bits)
// move (16 bits)
// age (16 bits): the move of the game on which this position would have occurred
// depth (8 bits)
// node type (8 bits): from the three constants above
Here is a simple implementation:
var keys [1000]uint64
var values [1000]uint64
func Put(b *dragontoothmg.Board, m dragontoothmg.Move, eval int16, depth uint8, ntype uint8) {
var value uint64 = uint64(eval) | (uint64(m) << 16) | (uint64(b.Fullmoveno) << 32) |
(uint64(depth) << 48) | (uint64(ntype) << 56)
hash := b.Hash()
key := hash ^ value
index := hash % uint64(len(keys))
keys[index] = key
values[index] = value
}
func Get(b *dragontoothmg.Board) (found bool, move dragontoothmg.Move,
eval int16, depth uint8, ntype uint8) {
hash := b.Hash()
index := hash % uint64(len(keys))
key := keys[index]
value := values[index]
found = (hash == (key ^ value))
if !found {
return false, 0, 0, 0, 0
}
eval = int16(value & 0xFFFF)
move = dragontoothmg.Move((value >> 16) & 0xFFFF)
depth = uint8((value >> 48) & 0xFF)
ntype = uint8((value >> 56) & 0xFF)
return
}
However, when I try to Get()
the data, it comes back corrupted. I suspect this might be related to the fact that eval
is a signed int, and the cast converts it to a signed uint64. What have I done wrong, and how can I fix it?
This is failing test result:
--- FAIL: TestSimpleTt (0.10s)
transtable_test.go:37: Simple ttable test failed.
Put data: (board: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 0) e2e4 -30 6 2
Fetched data: true h8h8 -30 255 255
FAIL
h8h8
is the maximum value of the field, for what it's worth.
答案1
得分: 0
我无法在简化的代码中重现你的结果https://play.golang.org/p/shPN-1waZa:
func Pack(m, eval int16, depth, ntype uint8) (value uint64) {
value = (uint64(eval) |
(uint64(m) << 16) |
// (uint64(b.Fullmoveno) << 32) | <-- 我怀疑问题出在这里!
(uint64(depth) << 48) |
(uint64(ntype) << 56))
return
}
func Unpack(value uint64) (move int16, eval int16, depth uint8, ntype uint8) {
eval = int16(value & 0xFFFF)
move = int16((value >> 16) & 0xFFFF)
depth = uint8((value >> 48) & 0xFF)
ntype = uint8((value >> 56) & 0xFF)
return
}
func main() {
m, e, d, n := int16(8), int16(8), uint8(8), uint8(8)
packedValue := Pack(m, e, d, n)
fmt.Printf("%v\n", packedValue)
move, eval, depth, ntype := Unpack(packedValue)
fmt.Printf("%v %v %v %v", move, eval, depth, ntype)
}
但我有些怀疑:
a) dragonthooth.Move - 它真的是 int16
吗?我猜你有一组具有该类型值的常量。
b) 你正在打包5个值并提取4个。也许这不是错误,但请检查 b.Fullmoveno
的类型是否为 int16
。
c) 我无法判断你其他代码的正确性。我只是希望你在哈希、索引、键和值方面没有出错。
我无法完全理解你剩下的代码。
-
我猜你指的是
value 结构
而不是key 结构
(因为在你的代码中它是被打包的值)。 -
为什么你要在单独的数组中定义2个键和值?为什么不使用 []{uint64,uint64}?甚至是 map[uint64]uint64?
英文:
I can't reproduce your resultat in simplified code https://play.golang.org/p/shPN-1waZa:
func Pack(m, eval int16, depth, ntype uint8) (value uint64) {
value = (uint64(eval) |
(uint64(m) << 16) |
// (uint64(b.Fullmoveno) << 32) | <-- My suspicion is here !
(uint64(depth) << 48) |
(uint64(ntype) << 56))
return
}
func Unpack(value uint64) (move int16, eval int16, depth uint8, ntype uint8) {
eval = int16(value & 0xFFFF)
move = int16((value >> 16) & 0xFFFF)
depth = uint8((value >> 48) & 0xFF)
ntype = uint8((value >> 56) & 0xFF)
return
}
func main() {
m, e, d, n := int16(8), int16(8), uint8(8), uint8(8)
packedValue := Pack(m, e, d, n)
fmt.Printf("%v\n", packedValue)
move, eval, depth, ntype := Unpack(packedValue)
fmt.Printf("%v %v %v %v", move, eval, depth, ntype)
}
But I have suspicions:
a) dragonthooth.Move - is it really int16
? I suppose you have set of consts with values for this type
b) You're packing 5 values and extract 4. Maybe it's not error, but check type of b.Fullmoveno
is it int16
?
c) I can not judge about correctness of your other code. I just hope that you did not make errors in hash, index, keys, values.
I can't quite understand your remaining code.
-
I suppose you mean
value structure
and notkey structure
(because in your code it's value packed) -
Why did you define 2 keys and values in separate arrays?
Why not []{uint64,uint64}? Or even map[uint64]uint64?
答案2
得分: 0
感谢所有回复的人。这是解决我的问题的方法:
对于负值,uint64(eval)
会将符号位移动到64位整数的最高有效位,从而干扰了应该存储在该位的数据。我通过先转换为uint16
来解决这个问题:
uint64(uint16(eval))
英文:
Thanks to everyone who responded. This was the solution to my issue:
uint64(eval)
for negative values was moving the sign bit to the most significant bit of the 64-bit int, which then interfered with the data that was supposed to be stored at that bit. I solved it by first converting to uint16
:
uint64(uint16(eval))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论