src/runtime: improve float/complex hashing
This allows positive and negative zero to hash to the same value, as required by Go. This is not perfect, but the best I could do without revamping all the hash funtions to take a seed. Fixes #2356
Этот коммит содержится в:
родитель
9734f349a3
коммит
1903cf23c9
3 изменённых файлов: 77 добавлений и 3 удалений
|
@ -356,6 +356,24 @@ func hashmapStringDelete(m *hashmap, key string) {
|
|||
//go:linkname valueInterfaceUnsafe reflect.valueInterfaceUnsafe
|
||||
func valueInterfaceUnsafe(v reflect.Value) interface{}
|
||||
|
||||
func hashmapFloat32Hash(ptr unsafe.Pointer) uint32 {
|
||||
f := *(*uint32)(ptr)
|
||||
if f == 0x80000000 {
|
||||
// convert -0 to 0 for hashing
|
||||
f = 0
|
||||
}
|
||||
return hashmapHash(unsafe.Pointer(&f), 4)
|
||||
}
|
||||
|
||||
func hashmapFloat64Hash(ptr unsafe.Pointer) uint32 {
|
||||
f := *(*uint64)(ptr)
|
||||
if f == 0x8000000000000000 {
|
||||
// convert -0 to 0 for hashing
|
||||
f = 0
|
||||
}
|
||||
return hashmapHash(unsafe.Pointer(&f), 8)
|
||||
}
|
||||
|
||||
func hashmapInterfaceHash(itf interface{}) uint32 {
|
||||
x := reflect.ValueOf(itf)
|
||||
if x.RawType() == 0 {
|
||||
|
@ -374,13 +392,21 @@ func hashmapInterfaceHash(itf interface{}) uint32 {
|
|||
return hashmapHash(ptr, x.RawType().Size())
|
||||
case reflect.Bool, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return hashmapHash(ptr, x.RawType().Size())
|
||||
case reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
|
||||
case reflect.Float32:
|
||||
// It should be possible to just has the contents. However, NaN != NaN
|
||||
// so if you're using lots of NaNs as map keys (you shouldn't) then hash
|
||||
// time may become exponential. To fix that, it would be better to
|
||||
// return a random number instead:
|
||||
// https://research.swtch.com/randhash
|
||||
return hashmapHash(ptr, x.RawType().Size())
|
||||
return hashmapFloat32Hash(ptr)
|
||||
case reflect.Float64:
|
||||
return hashmapFloat64Hash(ptr)
|
||||
case reflect.Complex64:
|
||||
rptr, iptr := ptr, unsafe.Pointer(uintptr(ptr)+4)
|
||||
return hashmapFloat32Hash(rptr) ^ hashmapFloat32Hash(iptr)
|
||||
case reflect.Complex128:
|
||||
rptr, iptr := ptr, unsafe.Pointer(uintptr(ptr)+8)
|
||||
return hashmapFloat64Hash(rptr) ^ hashmapFloat64Hash(iptr)
|
||||
case reflect.String:
|
||||
return hashmapStringHash(x.String())
|
||||
case reflect.Chan, reflect.Ptr, reflect.UnsafePointer:
|
||||
|
|
46
testdata/map.go
предоставленный
46
testdata/map.go
предоставленный
|
@ -1,6 +1,8 @@
|
|||
package main
|
||||
|
||||
import "sort"
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
var testmap1 = map[string]int{"data": 3}
|
||||
var testmap2 = map[string]int{
|
||||
|
@ -109,6 +111,48 @@ func main() {
|
|||
squares = make(map[int]int, 20)
|
||||
testBigMap(squares, 40)
|
||||
println("tested growing of a map")
|
||||
|
||||
floatcmplx()
|
||||
}
|
||||
|
||||
func floatcmplx() {
|
||||
|
||||
var zero float64
|
||||
var negz float64 = -zero
|
||||
|
||||
// test that zero and negative zero hash to the same thing
|
||||
m := make(map[float64]int)
|
||||
m[zero]++
|
||||
m[negz]++
|
||||
println(m[negz])
|
||||
|
||||
cmap := make(map[complex128]int)
|
||||
|
||||
var c complex128
|
||||
c = complex(zero, zero)
|
||||
cmap[c]++
|
||||
|
||||
c = complex(negz, negz)
|
||||
cmap[c]++
|
||||
|
||||
c = complex(0, 0)
|
||||
println(cmap[c])
|
||||
|
||||
c = complex(1, negz)
|
||||
cmap[c]++
|
||||
|
||||
c = complex(1, zero)
|
||||
cmap[c]++
|
||||
|
||||
println(cmap[c])
|
||||
|
||||
c = complex(negz, 2)
|
||||
cmap[c]++
|
||||
|
||||
c = complex(zero, 2)
|
||||
cmap[c]++
|
||||
|
||||
println(cmap[c])
|
||||
}
|
||||
|
||||
func readMap(m map[string]int, key string) {
|
||||
|
|
4
testdata/map.txt
предоставленный
4
testdata/map.txt
предоставленный
|
@ -72,3 +72,7 @@ structMap[{"tau", 3.14}]: 0
|
|||
structMap[{"tau", 6.28}]: 0
|
||||
tested preallocated map
|
||||
tested growing of a map
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче