github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/encoding/float_test.go (about) 1 // Copyright 2014 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package encoding 12 13 import ( 14 "bytes" 15 "fmt" 16 "math" 17 "testing" 18 19 "github.com/cockroachdb/cockroach/pkg/util/randutil" 20 ) 21 22 func TestEncodeFloatOrdered(t *testing.T) { 23 testCases := []struct { 24 Value float64 25 Encoding []byte 26 }{ 27 {math.NaN(), []byte{0x02}}, 28 {math.Inf(-1), []byte{0x03, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, 29 {-math.MaxFloat64, []byte{0x03, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, 30 {-1e308, []byte{0x03, 0x00, 0x1e, 0x33, 0x0c, 0x7a, 0x14, 0x37, 0x5f}}, 31 {-10000.0, []byte{0x03, 0x3f, 0x3c, 0x77, 0xff, 0xff, 0xff, 0xff, 0xff}}, 32 {-9999.0, []byte{0x03, 0x3f, 0x3c, 0x78, 0x7f, 0xff, 0xff, 0xff, 0xff}}, 33 {-100.0, []byte{0x03, 0x3f, 0xa6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, 34 {-99.0, []byte{0x03, 0x3f, 0xa7, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff}}, 35 {-1.0, []byte{0x03, 0x40, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, 36 {-0.00123, []byte{0x03, 0x40, 0xab, 0xd9, 0x01, 0x8e, 0x75, 0x79, 0x28}}, 37 {-1e-307, []byte{0x03, 0x7f, 0xce, 0x05, 0xe7, 0xd3, 0xbf, 0x39, 0xf2}}, 38 {-math.SmallestNonzeroFloat64, []byte{0x03, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}}, 39 {math.Copysign(0, -1), []byte{0x04}}, 40 {0, []byte{0x04}}, 41 {math.SmallestNonzeroFloat64, []byte{0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, 42 {1e-307, []byte{0x05, 0x00, 0x31, 0xfa, 0x18, 0x2c, 0x40, 0xc6, 0x0d}}, 43 {0.00123, []byte{0x05, 0x3f, 0x54, 0x26, 0xfe, 0x71, 0x8a, 0x86, 0xd7}}, 44 {0.0123, []byte{0x05, 0x3f, 0x89, 0x30, 0xbe, 0x0d, 0xed, 0x28, 0x8d}}, 45 {0.123, []byte{0x05, 0x3f, 0xbf, 0x7c, 0xed, 0x91, 0x68, 0x72, 0xb0}}, 46 {1.0, []byte{0x05, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, 47 {10.0, []byte{0x05, 0x40, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, 48 {12.345, []byte{0x05, 0x40, 0x28, 0xb0, 0xa3, 0xd7, 0x0a, 0x3d, 0x71}}, 49 {99.0, []byte{0x05, 0x40, 0x58, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00}}, 50 {99.0001, []byte{0x05, 0x40, 0x58, 0xc0, 0x01, 0xa3, 0x6e, 0x2e, 0xb2}}, 51 {99.01, []byte{0x05, 0x40, 0x58, 0xc0, 0xa3, 0xd7, 0x0a, 0x3d, 0x71}}, 52 {100.0, []byte{0x05, 0x40, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, 53 {100.01, []byte{0x05, 0x40, 0x59, 0x00, 0xa3, 0xd7, 0x0a, 0x3d, 0x71}}, 54 {100.1, []byte{0x05, 0x40, 0x59, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66}}, 55 {1234, []byte{0x05, 0x40, 0x93, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00}}, 56 {1234.5, []byte{0x05, 0x40, 0x93, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00}}, 57 {9999, []byte{0x05, 0x40, 0xc3, 0x87, 0x80, 0x00, 0x00, 0x00, 0x00}}, 58 {9999.000001, []byte{0x05, 0x40, 0xc3, 0x87, 0x80, 0x00, 0x08, 0x63, 0x7c}}, 59 {9999.000009, []byte{0x05, 0x40, 0xc3, 0x87, 0x80, 0x00, 0x4b, 0x7f, 0x5a}}, 60 {9999.00001, []byte{0x05, 0x40, 0xc3, 0x87, 0x80, 0x00, 0x53, 0xe2, 0xd6}}, 61 {9999.00009, []byte{0x05, 0x40, 0xc3, 0x87, 0x80, 0x02, 0xf2, 0xf9, 0x87}}, 62 {9999.000099, []byte{0x05, 0x40, 0xc3, 0x87, 0x80, 0x03, 0x3e, 0x78, 0xe2}}, 63 {9999.0001, []byte{0x05, 0x40, 0xc3, 0x87, 0x80, 0x03, 0x46, 0xdc, 0x5d}}, 64 {9999.001, []byte{0x05, 0x40, 0xc3, 0x87, 0x80, 0x20, 0xc4, 0x9b, 0xa6}}, 65 {9999.01, []byte{0x05, 0x40, 0xc3, 0x87, 0x81, 0x47, 0xae, 0x14, 0x7b}}, 66 {9999.1, []byte{0x05, 0x40, 0xc3, 0x87, 0x8c, 0xcc, 0xcc, 0xcc, 0xcd}}, 67 {10000, []byte{0x05, 0x40, 0xc3, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00}}, 68 {10001, []byte{0x05, 0x40, 0xc3, 0x88, 0x80, 0x00, 0x00, 0x00, 0x00}}, 69 {12345, []byte{0x05, 0x40, 0xc8, 0x1c, 0x80, 0x00, 0x00, 0x00, 0x00}}, 70 {123450, []byte{0x05, 0x40, 0xfe, 0x23, 0xa0, 0x00, 0x00, 0x00, 0x00}}, 71 {1e308, []byte{0x05, 0x7f, 0xe1, 0xcc, 0xf3, 0x85, 0xeb, 0xc8, 0xa0}}, 72 {math.MaxFloat64, []byte{0x05, 0x7f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, 73 {math.Inf(1), []byte{0x05, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, 74 } 75 76 var lastEncoded []byte 77 for _, dir := range []Direction{Ascending, Descending} { 78 for i, c := range testCases { 79 var enc []byte 80 var err error 81 var dec float64 82 if dir == Ascending { 83 enc = EncodeFloatAscending(nil, c.Value) 84 _, dec, err = DecodeFloatAscending(enc) 85 } else { 86 enc = EncodeFloatDescending(nil, c.Value) 87 _, dec, err = DecodeFloatDescending(enc) 88 } 89 if dir == Ascending && !bytes.Equal(enc, c.Encoding) { 90 t.Errorf("unexpected mismatch for %v. expected [% x], got [% x]", 91 c.Value, c.Encoding, enc) 92 } 93 if i > 0 { 94 if (bytes.Compare(lastEncoded, enc) > 0 && dir == Ascending) || 95 (bytes.Compare(lastEncoded, enc) < 0 && dir == Descending) { 96 t.Errorf("%v: expected [% x] to be less than or equal to [% x]", 97 c.Value, testCases[i-1].Encoding, enc) 98 } 99 } 100 if err != nil { 101 t.Error(err) 102 continue 103 } 104 if math.IsNaN(c.Value) { 105 if !math.IsNaN(dec) { 106 t.Errorf("unexpected mismatch for %v. got %v", c.Value, dec) 107 } 108 } else if dec != c.Value { 109 t.Errorf("unexpected mismatch for %v. got %v", c.Value, dec) 110 } 111 testPeekLength(t, enc) 112 lastEncoded = enc 113 } 114 115 // Test that appending the float to an existing buffer works. 116 var enc []byte 117 var dec float64 118 if dir == Ascending { 119 enc = EncodeFloatAscending([]byte("hello"), 1.23) 120 _, dec, _ = DecodeFloatAscending(enc[5:]) 121 } else { 122 enc = EncodeFloatDescending([]byte("hello"), 1.23) 123 _, dec, _ = DecodeFloatDescending(enc[5:]) 124 } 125 if dec != 1.23 { 126 t.Errorf("unexpected mismatch for %v. got %v", 1.23, dec) 127 } 128 } 129 } 130 131 // TestEncodeFloatValue tests that EncodeFloatValue is bit-for-bit equal 132 // after decoding. Important for the 0/-0 case because 0 == -0, but we need 133 // to verify that -0 came out of the decoder. 134 func TestEncodeFloatValue(t *testing.T) { 135 testCases := []float64{ 136 math.NaN(), 137 math.Inf(-1), 138 -1, 139 math.Copysign(0, -1), 140 0, 141 1, 142 math.Inf(1), 143 } 144 145 for _, f := range testCases { 146 t.Run(fmt.Sprint(f), func(t *testing.T) { 147 enc := EncodeFloatValue(nil, NoColumnID, f) 148 _, dec, err := DecodeFloatValue(enc) 149 if err != nil { 150 t.Fatal(err) 151 } 152 testBits := math.Float64bits(f) 153 encBits := math.Float64bits(dec) 154 if testBits != encBits { 155 t.Fatalf("unexpected decoded float64 value. expected %f, got %f", f, dec) 156 } 157 }) 158 } 159 } 160 161 func BenchmarkEncodeFloat(b *testing.B) { 162 rng, _ := randutil.NewPseudoRand() 163 164 vals := make([]float64, 10000) 165 for i := range vals { 166 vals[i] = rng.Float64() 167 } 168 169 buf := make([]byte, 0, 100) 170 171 b.ResetTimer() 172 for i := 0; i < b.N; i++ { 173 _ = EncodeFloatAscending(buf, vals[i%len(vals)]) 174 } 175 } 176 177 func BenchmarkDecodeFloat(b *testing.B) { 178 rng, _ := randutil.NewPseudoRand() 179 180 vals := make([][]byte, 10000) 181 for i := range vals { 182 vals[i] = EncodeFloatAscending(nil, rng.Float64()) 183 } 184 185 b.ResetTimer() 186 for i := 0; i < b.N; i++ { 187 _, _, _ = DecodeFloatAscending(vals[i%len(vals)]) 188 } 189 }