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  }