@@ -3,6 +3,7 @@ package gnolang
3
3
import (
4
4
"encoding/binary"
5
5
"fmt"
6
+ "math"
6
7
"math/big"
7
8
"math/rand/v2"
8
9
"reflect"
@@ -1459,21 +1460,16 @@ func (tv *TypedValue) AssertNonNegative(msg string) {
1459
1460
}
1460
1461
}
1461
1462
1462
- // uvnan is the unsigned value of NaN. It can be obtained by applying the following:
1463
- // { var nan = math.NaN(); var uvnan = *(*uint64)(unsafe.Pointer(&nan)) }
1464
- const uvnan = 0x7FF8000000000001
1465
-
1466
- // randNaN returns an uint64 representation of NaN with a random payload of 53 bits.
1467
- func randNaN () uint64 {
1468
- return rand .Uint64 ()&^uvnan | uvnan //nolint:gosec
1463
+ // randNaN64 returns an uint64 representation of NaN with a random payload.
1464
+ func randNaN64 () uint64 {
1465
+ const uvnan64 = 0x7FF8000000000001 // math.Float64bits(math.NaN())
1466
+ return rand .Uint64 ()&^uvnan64 | uvnan64 //nolint:gosec
1469
1467
}
1470
1468
1471
- // IsNaN reports wether tv is an IEEE 754 "not a number" value.
1472
- func (tv * TypedValue ) IsNaN () bool {
1473
- if tv .HasKind (Float64Kind ) {
1474
- return uvnan == tv .GetFloat64 ()& uvnan
1475
- }
1476
- return false
1469
+ // randNaN32 returns an uint32 representation of NaN with a random payload.
1470
+ func randNaN32 () uint32 {
1471
+ const uvnan32 = 0x7FC00000 // math.Float32bits(float32(math.NaN()))
1472
+ return rand .Uint32 ()&^uvnan32 | uvnan32 //nolint:gosec
1477
1473
}
1478
1474
1479
1475
func (tv * TypedValue ) ComputeMapKey (store Store , omitType bool ) MapKey {
@@ -1494,9 +1490,26 @@ func (tv *TypedValue) ComputeMapKey(store Store, omitType bool) MapKey {
1494
1490
}
1495
1491
switch bt := baseOf (tv .T ).(type ) {
1496
1492
case PrimitiveType :
1497
- if tv .IsNaN () {
1498
- // if NaN, generate a random payload to ensure key uniqueness.
1499
- tv .SetFloat64 (randNaN ())
1493
+ if tv .HasKind (Float64Kind ) {
1494
+ f := math .Float64frombits (tv .GetFloat64 ())
1495
+ if f != f {
1496
+ // If NaN, shuffle its value, thus allowing several NaN per map
1497
+ // and ensuring that a value cannot be retrieved by NaN.
1498
+ tv .SetFloat64 (randNaN64 ())
1499
+ } else if f == 0.0 {
1500
+ // If zero, clear the sign, so +0.0 and -0.0 match the same key.
1501
+ tv .SetFloat64 (math .Float64bits (+ 0.0 ))
1502
+ }
1503
+ } else if tv .HasKind (Float32Kind ) {
1504
+ f := math .Float32frombits (tv .GetFloat32 ())
1505
+ if f != f {
1506
+ // If NaN, shuffle its value, thus allowing several NaN per map
1507
+ // and ensuring that a value cannot be retrieved by NaN.
1508
+ tv .SetFloat32 (randNaN32 ())
1509
+ } else if f == 0.0 {
1510
+ // If zero, clear the sign, so +0.0 and -0.0 match the same key.
1511
+ tv .SetFloat32 (math .Float32bits (+ 0.0 ))
1512
+ }
1500
1513
}
1501
1514
pbz := tv .PrimitiveBytes ()
1502
1515
bz = append (bz , pbz ... )
0 commit comments