github.com/richardwilkes/toolbox@v1.121.0/xmath/num/uint128_test.go (about) 1 // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved. 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, version 2.0. If a copy of the MPL was not distributed with 5 // this file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 // 7 // This Source Code Form is "Incompatible With Secondary Licenses", as 8 // defined by the Mozilla Public License, version 2.0. 9 10 package num_test 11 12 import ( 13 "encoding/json" 14 "math" 15 "math/big" 16 "strconv" 17 "testing" 18 19 "github.com/richardwilkes/toolbox/check" 20 "gopkg.in/yaml.v3" 21 22 "github.com/richardwilkes/toolbox/xmath/num" 23 ) 24 25 const ( 26 maxUint64PlusOneAsStr = "18446744073709551616" 27 maxUint128AsStr = "340282366920938463463374607431768211455" 28 maxUint128PlusOneAsStr = "340282366920938463463374607431768211456" 29 ) 30 31 var uTable = []*uInfo{ 32 { 33 IsUint64: true, 34 IsUint128: true, 35 }, 36 { 37 Uint64: 1, 38 IsUint64: true, 39 IsUint128: true, 40 }, 41 { 42 ValueAsStr: "18446744073712590000", 43 IsUint128: true, 44 }, 45 { 46 Uint64: math.MaxUint64, 47 IsUint64: true, 48 IsUint128: true, 49 }, 50 { 51 ValueAsStr: maxUint64PlusOneAsStr, 52 IsUint128: true, 53 }, 54 { 55 ValueAsStr: maxUint128AsStr, 56 IsUint128: true, 57 }, 58 { 59 ValueAsStr: maxUint128PlusOneAsStr, 60 ExpectedConversionAsStr: maxUint128AsStr, 61 }, 62 } 63 64 type uInfo struct { 65 ValueAsStr string 66 ExpectedConversionAsStr string 67 Uint64 uint64 68 IsUint64 bool 69 IsUint128 bool 70 } 71 72 func init() { 73 for _, d := range uTable { 74 if d.IsUint64 { 75 d.ValueAsStr = strconv.FormatUint(d.Uint64, 10) 76 } 77 if d.ExpectedConversionAsStr == "" { 78 d.ExpectedConversionAsStr = d.ValueAsStr 79 } 80 } 81 } 82 83 func bigUintFromStr(t *testing.T, one *uInfo, index int) *big.Int { 84 t.Helper() 85 b, ok := new(big.Int).SetString(one.ValueAsStr, 10) 86 check.True(t, ok, indexFmt, index) 87 check.Equal(t, one.ValueAsStr, b.String(), indexFmt, index) 88 return b 89 } 90 91 func TestUint128FromUint64(t *testing.T) { 92 for i, one := range uTable { 93 if one.IsUint64 { 94 check.Equal(t, one.ExpectedConversionAsStr, num.Uint128From64(one.Uint64).String(), indexFmt, i) 95 } 96 } 97 } 98 99 func TestUint128FromBigInt(t *testing.T) { 100 for i, one := range uTable { 101 check.Equal(t, one.ExpectedConversionAsStr, num.Uint128FromBigInt(bigUintFromStr(t, one, i)).String(), indexFmt, i) 102 } 103 } 104 105 func TestUint128AsBigInt(t *testing.T) { 106 for i, one := range uTable { 107 if one.IsUint128 { 108 check.Equal(t, one.ValueAsStr, num.Uint128FromBigInt(bigUintFromStr(t, one, i)).AsBigInt().String(), indexFmt, i) 109 } 110 } 111 } 112 113 func TestUint128AsUint64(t *testing.T) { 114 for i, one := range uTable { 115 if one.IsUint64 { 116 check.Equal(t, one.Uint64, num.Uint128From64(one.Uint64).AsUint64(), indexFmt, i) 117 } 118 } 119 } 120 121 func TestUint128IsUint64(t *testing.T) { 122 for i, one := range uTable { 123 if one.IsUint128 { 124 check.Equal(t, one.IsUint64, num.Uint128FromBigInt(bigUintFromStr(t, one, i)).IsUint64(), indexFmt, i) 125 } 126 } 127 } 128 129 func TestUint128Inc(t *testing.T) { 130 big1 := new(big.Int).SetInt64(1) 131 for i, one := range uTable { 132 if one.IsUint128 { 133 b := bigUintFromStr(t, one, i) 134 v := num.Uint128FromBigInt(b) 135 if v == num.MaxUint128 { 136 check.Equal(t, num.Uint128{}, v.Inc(), indexFmt, i) 137 } else { 138 b.Add(b, big1) 139 check.Equal(t, b.String(), v.Inc().AsBigInt().String(), indexFmt, i) 140 } 141 } 142 } 143 } 144 145 func TestUint128Dec(t *testing.T) { 146 big1 := new(big.Int).SetInt64(1) 147 for i, one := range uTable { 148 if one.IsUint128 { 149 b := bigUintFromStr(t, one, i) 150 v := num.Uint128FromBigInt(b) 151 if v.IsZero() { 152 check.Equal(t, num.MaxUint128, v.Dec(), indexFmt, i) 153 } else { 154 b.Sub(b, big1) 155 check.Equal(t, b.String(), v.Dec().AsBigInt().String(), indexFmt, i) 156 } 157 } 158 } 159 } 160 161 func TestUint128Add(t *testing.T) { 162 check.Equal(t, num.Uint128From64(0), num.Uint128From64(0).Add(num.Uint128From64(0))) 163 check.Equal(t, num.Uint128From64(120), num.Uint128From64(22).Add(num.Uint128From64(98))) 164 check.Equal(t, num.Uint128FromComponents(1, 0), num.Uint128FromComponents(0, 0xFFFFFFFFFFFFFFFF).Add(num.Uint128From64(1))) 165 check.Equal(t, num.Uint128From64(0), num.MaxUint128.Add(num.Uint128From64(1))) 166 } 167 168 func TestUint128Sub(t *testing.T) { 169 check.Equal(t, num.Uint128From64(0), num.Uint128From64(0).Sub(num.Uint128From64(0))) 170 check.Equal(t, num.Uint128FromComponents(0, 0xFFFFFFFFFFFFFFFF), num.Uint128FromComponents(1, 0).Sub(num.Uint128From64(1))) 171 check.Equal(t, num.MaxUint128, num.Uint128From64(0).Sub(num.Uint128From64(1))) 172 } 173 174 func TestUint128Cmp(t *testing.T) { 175 check.Equal(t, 0, num.Uint128From64(0).Cmp(num.Uint128From64(0))) 176 check.Equal(t, -1, num.Uint128From64(1).Cmp(num.Uint128From64(2))) 177 check.Equal(t, -1, num.Uint128From64(22).Cmp(num.Uint128From64(98))) 178 check.Equal(t, 1, num.Uint128FromComponents(1, 0).Cmp(num.Uint128From64(1))) 179 check.Equal(t, -1, num.Uint128From64(0).Cmp(num.MaxUint128)) 180 check.Equal(t, 1, num.MaxUint128.Cmp(num.Uint128From64(0))) 181 check.Equal(t, 0, num.MaxUint128.Cmp(num.MaxUint128)) //nolint:gocritic // Yes, we meant to compare the same value 182 } 183 184 func TestUint128GreaterThan(t *testing.T) { 185 check.Equal(t, false, num.Uint128From64(0).GreaterThan(num.Uint128From64(0))) 186 check.Equal(t, false, num.Uint128From64(1).GreaterThan(num.Uint128From64(2))) 187 check.Equal(t, false, num.Uint128From64(22).GreaterThan(num.Uint128From64(98))) 188 check.Equal(t, false, num.Uint128From64(0).GreaterThan(num.MaxUint128)) 189 check.Equal(t, false, num.MaxUint128.GreaterThan(num.MaxUint128)) 190 check.Equal(t, true, num.Uint128FromComponents(1, 0).GreaterThan(num.Uint128From64(1))) 191 check.Equal(t, true, num.MaxUint128.GreaterThan(num.Uint128From64(0))) 192 } 193 194 func TestUint128GreaterOrEqualTo(t *testing.T) { 195 check.Equal(t, true, num.Uint128From64(0).GreaterThanOrEqual(num.Uint128From64(0))) 196 check.Equal(t, false, num.Uint128From64(1).GreaterThanOrEqual(num.Uint128From64(2))) 197 check.Equal(t, false, num.Uint128From64(22).GreaterThanOrEqual(num.Uint128From64(98))) 198 check.Equal(t, false, num.Uint128From64(0).GreaterThanOrEqual(num.Uint128From64(1))) 199 check.Equal(t, false, num.Uint128From64(0).GreaterThanOrEqual(num.MaxUint128)) 200 check.Equal(t, true, num.MaxUint128.GreaterThanOrEqual(num.MaxUint128)) 201 check.Equal(t, true, num.Uint128FromComponents(1, 0).GreaterThanOrEqual(num.Uint128From64(1))) 202 check.Equal(t, true, num.MaxUint128.GreaterThanOrEqual(num.Uint128From64(0))) 203 } 204 205 func TestUint128LessThan(t *testing.T) { 206 check.Equal(t, false, num.Uint128From64(0).LessThan(num.Uint128From64(0))) 207 check.Equal(t, true, num.Uint128From64(1).LessThan(num.Uint128From64(2))) 208 check.Equal(t, true, num.Uint128From64(22).LessThan(num.Uint128From64(98))) 209 check.Equal(t, true, num.Uint128From64(0).LessThan(num.Uint128From64(1))) 210 check.Equal(t, true, num.Uint128From64(0).LessThan(num.MaxUint128)) 211 check.Equal(t, false, num.MaxUint128.LessThan(num.MaxUint128)) 212 check.Equal(t, false, num.Uint128FromComponents(1, 0).LessThan(num.Uint128From64(1))) 213 check.Equal(t, false, num.MaxUint128.LessThan(num.Uint128From64(0))) 214 } 215 216 func TestUint128LessOrEqualTo(t *testing.T) { 217 check.Equal(t, true, num.Uint128From64(0).LessThanOrEqual(num.Uint128From64(0))) 218 check.Equal(t, true, num.Uint128From64(1).LessThanOrEqual(num.Uint128From64(2))) 219 check.Equal(t, true, num.Uint128From64(22).LessThanOrEqual(num.Uint128From64(98))) 220 check.Equal(t, true, num.Uint128From64(0).LessThanOrEqual(num.Uint128From64(1))) 221 check.Equal(t, true, num.Uint128From64(0).LessThanOrEqual(num.MaxUint128)) 222 check.Equal(t, true, num.MaxUint128.LessThanOrEqual(num.MaxUint128)) 223 check.Equal(t, false, num.Uint128FromComponents(1, 0).LessThanOrEqual(num.Uint128From64(1))) 224 check.Equal(t, false, num.MaxUint128.LessThanOrEqual(num.Uint128From64(0))) 225 } 226 227 func TestUint128Mul(t *testing.T) { 228 bigMax64 := new(big.Int).SetInt64(math.MaxInt64) 229 check.Equal(t, num.Uint128From64(0), num.Uint128From64(0).Mul(num.Uint128From64(0))) 230 check.Equal(t, num.Uint128From64(4), num.Uint128From64(2).Mul(num.Uint128From64(2))) 231 check.Equal(t, num.Uint128From64(0), num.Uint128From64(1).Mul(num.Uint128From64(0))) 232 check.Equal(t, num.Uint128From64(1176), num.Uint128From64(12).Mul(num.Uint128From64(98))) 233 check.Equal(t, num.Uint128FromBigInt(new(big.Int).Mul(bigMax64, bigMax64)), num.Uint128From64(math.MaxInt64).Mul(num.Uint128From64(math.MaxInt64))) 234 } 235 236 func TestUint128Div(t *testing.T) { 237 left, _ := new(big.Int).SetString("170141183460469231731687303715884105728", 10) 238 result, _ := new(big.Int).SetString("17014118346046923173168730371588410", 10) 239 check.Equal(t, num.Uint128From64(0), num.Uint128From64(1).Div(num.Uint128From64(2))) 240 check.Equal(t, num.Uint128From64(3), num.Uint128From64(11).Div(num.Uint128From64(3))) 241 check.Equal(t, num.Uint128From64(4), num.Uint128From64(12).Div(num.Uint128From64(3))) 242 check.Equal(t, num.Uint128From64(1), num.Uint128From64(10).Div(num.Uint128From64(10))) 243 check.Equal(t, num.Uint128From64(1), num.Uint128FromComponents(1, 0).Div(num.Uint128FromComponents(1, 0))) 244 check.Equal(t, num.Uint128From64(2), num.Uint128FromComponents(246, 0).Div(num.Uint128FromComponents(123, 0))) 245 check.Equal(t, num.Uint128From64(2), num.Uint128FromComponents(246, 0).Div(num.Uint128FromComponents(122, 0))) 246 check.Equal(t, num.Uint128FromBigInt(result), num.Uint128FromBigInt(left).Div(num.Uint128From64(10000))) 247 } 248 249 func TestUint128Json(t *testing.T) { 250 for i, one := range uTable { 251 if !one.IsUint128 { 252 continue 253 } 254 in := num.Uint128FromStringNoCheck(one.ValueAsStr) 255 data, err := json.Marshal(in) 256 check.NoError(t, err, indexFmt, i) 257 var out num.Uint128 258 check.NoError(t, json.Unmarshal(data, &out), indexFmt, i) 259 check.Equal(t, in, out, indexFmt, i) 260 } 261 } 262 263 func TestUint128Yaml(t *testing.T) { 264 for i, one := range uTable { 265 if !one.IsUint128 { 266 continue 267 } 268 in := num.Uint128FromStringNoCheck(one.ValueAsStr) 269 data, err := yaml.Marshal(in) 270 check.NoError(t, err, indexFmt, i) 271 var out num.Uint128 272 check.NoError(t, yaml.Unmarshal(data, &out), indexFmt, i) 273 check.Equal(t, in, out, indexFmt, i) 274 } 275 }