github.com/cockroachdb/apd/v3@v3.2.0/table_test.go (about) 1 // Copyright 2016 The Cockroach Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 // implied. See the License for the specific language governing 13 // permissions and limitations under the License. 14 15 package apd 16 17 import ( 18 "bytes" 19 "math/rand" 20 "strings" 21 "testing" 22 ) 23 24 func BenchmarkNumDigitsLookup(b *testing.B) { 25 prep := func(start string, c byte) []*Decimal { 26 var ds []*Decimal 27 buf := bytes.NewBufferString(start) 28 for i := 1; i < digitsTableSize; i++ { 29 buf.WriteByte(c) 30 d, _, _ := NewFromString(buf.String()) 31 ds = append(ds, d) 32 } 33 return ds 34 } 35 var ds []*Decimal 36 ds = append(ds, prep("", '9')...) 37 ds = append(ds, prep("1", '0')...) 38 ds = append(ds, prep("-", '9')...) 39 ds = append(ds, prep("-1", '0')...) 40 b.ResetTimer() 41 for i := 0; i < b.N; i++ { 42 for _, d := range ds { 43 d.NumDigits() 44 } 45 } 46 } 47 48 func BenchmarkNumDigitsFull(b *testing.B) { 49 prep := func(start string, c byte) []*Decimal { 50 var ds []*Decimal 51 buf := bytes.NewBufferString(start) 52 for i := 1; i < 1000; i++ { 53 buf.WriteByte(c) 54 d, _, _ := NewFromString(buf.String()) 55 ds = append(ds, d) 56 } 57 return ds 58 } 59 var ds []*Decimal 60 ds = append(ds, prep("", '9')...) 61 ds = append(ds, prep("1", '0')...) 62 ds = append(ds, prep("-", '9')...) 63 ds = append(ds, prep("-1", '0')...) 64 b.ResetTimer() 65 for i := 0; i < b.N; i++ { 66 for _, d := range ds { 67 d.NumDigits() 68 } 69 } 70 } 71 72 func TestNumDigits(t *testing.T) { 73 runTest := func(start string, c byte) { 74 buf := bytes.NewBufferString(start) 75 var offset int 76 if strings.HasPrefix(start, "-") { 77 offset-- 78 } 79 for i := 1; i < 1000; i++ { 80 buf.WriteByte(c) 81 bs := buf.String() 82 t.Run(bs, func(t *testing.T) { 83 d := newDecimal(t, testCtx, bs) 84 n := d.NumDigits() 85 e := int64(buf.Len() + offset) 86 if n != e { 87 t.Fatalf("%s ('%c'): expected %d, got %d", bs, c, e, n) 88 } 89 }) 90 } 91 } 92 runTest("", '9') 93 runTest("1", '0') 94 runTest("-", '9') 95 runTest("-1", '0') 96 } 97 98 func TestDigitsLookupTable(t *testing.T) { 99 // Make sure all elements in table make sense. 100 min := new(BigInt) 101 prevBorder := NewBigInt(0) 102 for i := 1; i <= digitsTableSize; i++ { 103 elem := &digitsLookupTable[i] 104 105 min.SetInt64(2) 106 min.Exp(min, NewBigInt(int64(i-1)), nil) 107 if minLen := int64(len(min.String())); minLen != elem.digits { 108 t.Errorf("expected 2^%d to have %d digits, found %d", i, elem.digits, minLen) 109 } 110 111 if zeros := int64(strings.Count(elem.border.String(), "0")); zeros != elem.digits { 112 t.Errorf("the %d digits for digitsLookupTable[%d] does not agree with the border %v", elem.digits, i, &elem.border) 113 } 114 115 if min.Cmp(&elem.border) >= 0 { 116 t.Errorf("expected 2^%d = %v to be less than the border, found %v", i-1, min, &elem.border) 117 } 118 119 if elem.border.Cmp(prevBorder) > 0 { 120 if min.Cmp(prevBorder) <= 0 { 121 t.Errorf("expected 2^%d = %v to be greater than or equal to the border, found %v", i-1, min, prevBorder) 122 } 123 prevBorder = &elem.border 124 } 125 } 126 127 // Throw random big.Ints at the table and make sure the 128 // digit lengths line up. 129 const randomTrials = 100 130 for i := 0; i < randomTrials; i++ { 131 a := NewBigInt(rand.Int63()) 132 b := NewBigInt(rand.Int63()) 133 a.Mul(a, b) 134 135 d := NewWithBigInt(a, 0) 136 tableDigits := d.NumDigits() 137 if actualDigits := int64(len(a.String())); actualDigits != tableDigits { 138 t.Errorf("expected %d digits for %v, found %d", tableDigits, a, actualDigits) 139 } 140 } 141 } 142 143 func TestTableExp10(t *testing.T) { 144 tests := []struct { 145 pow int64 146 str string 147 }{ 148 { 149 pow: 0, 150 str: "1", 151 }, 152 { 153 pow: 1, 154 str: "10", 155 }, 156 { 157 pow: 5, 158 str: "100000", 159 }, 160 { 161 pow: powerTenTableSize + 1, 162 str: "1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 163 }, 164 } 165 166 for i, test := range tests { 167 var tmpE BigInt 168 d := tableExp10(test.pow, &tmpE) 169 if s := d.String(); s != test.str { 170 t.Errorf("%d: expected PowerOfTenDec(%d) to give %s, got %s", i, test.pow, test.str, s) 171 } 172 } 173 }