Go哈希表:是否可以进行无转换的类型转换?

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

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) &lt;&lt; 16) | (uint64(b.Fullmoveno) &lt;&lt; 32) |
		(uint64(depth) &lt;&lt; 48) | (uint64(ntype) &lt;&lt; 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 &amp; 0xFFFF)
	move = dragontoothmg.Move((value &gt;&gt; 16) &amp; 0xFFFF)
	depth = uint8((value &gt;&gt; 48) &amp; 0xFF)
	ntype = uint8((value &gt;&gt; 56) &amp; 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) 我无法判断你其他代码的正确性。我只是希望你在哈希、索引、键和值方面没有出错。

我无法完全理解你剩下的代码。

  1. 我猜你指的是 value 结构 而不是 key 结构(因为在你的代码中它是被打包的值)。

  2. 为什么你要在单独的数组中定义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) &lt;&lt; 16) |
		// (uint64(b.Fullmoveno) &lt;&lt; 32) |  &lt;-- My suspicion is here !
		(uint64(depth) &lt;&lt; 48) |
		(uint64(ntype) &lt;&lt; 56))
	return
}
func Unpack(value uint64) (move int16, eval int16, depth uint8, ntype uint8) {
	eval = int16(value &amp; 0xFFFF)
	move = int16((value &gt;&gt; 16) &amp; 0xFFFF)
	depth = uint8((value &gt;&gt; 48) &amp; 0xFF)
	ntype = uint8((value &gt;&gt; 56) &amp; 0xFF)
	return
}

func main() {
	m, e, d, n := int16(8), int16(8), uint8(8), uint8(8)
	packedValue := Pack(m, e, d, n)
	fmt.Printf(&quot;%v\n&quot;, packedValue)
	move, eval, depth, ntype := Unpack(packedValue)
	fmt.Printf(&quot;%v %v %v %v&quot;, 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.

  1. I suppose you mean value structure and not key structure (because in your code it's value packed)

  2. 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))

huangapple
  • 本文由 发表于 2017年5月14日 05:47:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/43958297.html
匿名

发表评论

匿名网友

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

确定