github.com/remobjects/goldbaselibrary@v0.0.0-20230924164425-d458680a936b/Source/Gold/math/big/arith_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package big 6 7 import ( 8 "fmt" 9 "internal/testenv" 10 "math/rand" 11 "strings" 12 "testing" 13 ) 14 15 var isRaceBuilder = strings.HasSuffix(testenv.Builder(), "-race") 16 17 type funVV func(z, x, y []Word) (c Word) 18 type argVV struct { 19 z, x, y nat 20 c Word 21 } 22 23 var sumVV = []argVV{ 24 {}, 25 {nat{0}, nat{0}, nat{0}, 0}, 26 {nat{1}, nat{1}, nat{0}, 0}, 27 {nat{0}, nat{_M}, nat{1}, 1}, 28 {nat{80235}, nat{12345}, nat{67890}, 0}, 29 {nat{_M - 1}, nat{_M}, nat{_M}, 1}, 30 {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, nat{1, 0, 0, 0}, 1}, 31 {nat{0, 0, 0, _M}, nat{_M, _M, _M, _M - 1}, nat{1, 0, 0, 0}, 0}, 32 {nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1}, 33 } 34 35 func testFunVV(t *testing.T, msg string, f funVV, a argVV) { 36 z := make(nat, len(a.z)) 37 c := f(z, a.x, a.y) 38 for i, zi := range z { 39 if zi != a.z[i] { 40 t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i]) 41 break 42 } 43 } 44 if c != a.c { 45 t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c) 46 } 47 } 48 49 func TestFunVV(t *testing.T) { 50 for _, a := range sumVV { 51 arg := a 52 testFunVV(t, "addVV_g", addVV_g, arg) 53 testFunVV(t, "addVV", addVV, arg) 54 55 arg = argVV{a.z, a.y, a.x, a.c} 56 testFunVV(t, "addVV_g symmetric", addVV_g, arg) 57 testFunVV(t, "addVV symmetric", addVV, arg) 58 59 arg = argVV{a.x, a.z, a.y, a.c} 60 testFunVV(t, "subVV_g", subVV_g, arg) 61 testFunVV(t, "subVV", subVV, arg) 62 63 arg = argVV{a.y, a.z, a.x, a.c} 64 testFunVV(t, "subVV_g symmetric", subVV_g, arg) 65 testFunVV(t, "subVV symmetric", subVV, arg) 66 } 67 } 68 69 // Always the same seed for reproducible results. 70 var rnd = rand.New(rand.NewSource(0)) 71 72 func rndW() Word { 73 return Word(rnd.Int63()<<1 | rnd.Int63n(2)) 74 } 75 76 func rndV(n int) []Word { 77 v := make([]Word, n) 78 for i := range v { 79 v[i] = rndW() 80 } 81 return v 82 } 83 84 var benchSizes = []int{1, 2, 3, 4, 5, 1e1, 1e2, 1e3, 1e4, 1e5} 85 86 func BenchmarkAddVV(b *testing.B) { 87 for _, n := range benchSizes { 88 if isRaceBuilder && n > 1e3 { 89 continue 90 } 91 x := rndV(n) 92 y := rndV(n) 93 z := make([]Word, n) 94 b.Run(fmt.Sprint(n), func(b *testing.B) { 95 b.SetBytes(int64(n * _W)) 96 for i := 0; i < b.N; i++ { 97 addVV(z, x, y) 98 } 99 }) 100 } 101 } 102 103 func BenchmarkSubVV(b *testing.B) { 104 for _, n := range benchSizes { 105 if isRaceBuilder && n > 1e3 { 106 continue 107 } 108 x := rndV(n) 109 y := rndV(n) 110 z := make([]Word, n) 111 b.Run(fmt.Sprint(n), func(b *testing.B) { 112 b.SetBytes(int64(n * _W)) 113 for i := 0; i < b.N; i++ { 114 subVV(z, x, y) 115 } 116 }) 117 } 118 } 119 120 type funVW func(z, x []Word, y Word) (c Word) 121 type argVW struct { 122 z, x nat 123 y Word 124 c Word 125 } 126 127 var sumVW = []argVW{ 128 {}, 129 {nil, nil, 2, 2}, 130 {nat{0}, nat{0}, 0, 0}, 131 {nat{1}, nat{0}, 1, 0}, 132 {nat{1}, nat{1}, 0, 0}, 133 {nat{0}, nat{_M}, 1, 1}, 134 {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1}, 135 {nat{585}, nat{314}, 271, 0}, 136 } 137 138 var lshVW = []argVW{ 139 {}, 140 {nat{0}, nat{0}, 0, 0}, 141 {nat{0}, nat{0}, 1, 0}, 142 {nat{0}, nat{0}, 20, 0}, 143 144 {nat{_M}, nat{_M}, 0, 0}, 145 {nat{_M << 1 & _M}, nat{_M}, 1, 1}, 146 {nat{_M << 20 & _M}, nat{_M}, 20, _M >> (_W - 20)}, 147 148 {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0}, 149 {nat{_M << 1 & _M, _M, _M}, nat{_M, _M, _M}, 1, 1}, 150 {nat{_M << 20 & _M, _M, _M}, nat{_M, _M, _M}, 20, _M >> (_W - 20)}, 151 } 152 153 var rshVW = []argVW{ 154 {}, 155 {nat{0}, nat{0}, 0, 0}, 156 {nat{0}, nat{0}, 1, 0}, 157 {nat{0}, nat{0}, 20, 0}, 158 159 {nat{_M}, nat{_M}, 0, 0}, 160 {nat{_M >> 1}, nat{_M}, 1, _M << (_W - 1) & _M}, 161 {nat{_M >> 20}, nat{_M}, 20, _M << (_W - 20) & _M}, 162 163 {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0}, 164 {nat{_M, _M, _M >> 1}, nat{_M, _M, _M}, 1, _M << (_W - 1) & _M}, 165 {nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M}, 166 } 167 168 func testFunVW(t *testing.T, msg string, f funVW, a argVW) { 169 z := make(nat, len(a.z)) 170 c := f(z, a.x, a.y) 171 for i, zi := range z { 172 if zi != a.z[i] { 173 t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i]) 174 break 175 } 176 } 177 if c != a.c { 178 t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c) 179 } 180 } 181 182 func makeFunVW(f func(z, x []Word, s uint) (c Word)) funVW { 183 return func(z, x []Word, s Word) (c Word) { 184 return f(z, x, uint(s)) 185 } 186 } 187 188 func TestFunVW(t *testing.T) { 189 for _, a := range sumVW { 190 arg := a 191 testFunVW(t, "addVW_g", addVW_g, arg) 192 testFunVW(t, "addVW", addVW, arg) 193 194 arg = argVW{a.x, a.z, a.y, a.c} 195 testFunVW(t, "subVW_g", subVW_g, arg) 196 testFunVW(t, "subVW", subVW, arg) 197 } 198 199 shlVW_g := makeFunVW(shlVU_g) 200 shlVW := makeFunVW(shlVU) 201 for _, a := range lshVW { 202 arg := a 203 testFunVW(t, "shlVU_g", shlVW_g, arg) 204 testFunVW(t, "shlVU", shlVW, arg) 205 } 206 207 shrVW_g := makeFunVW(shrVU_g) 208 shrVW := makeFunVW(shrVU) 209 for _, a := range rshVW { 210 arg := a 211 testFunVW(t, "shrVU_g", shrVW_g, arg) 212 testFunVW(t, "shrVU", shrVW, arg) 213 } 214 } 215 216 type argVU struct { 217 d []Word // d is a Word slice, the input parameters x and z come from this array. 218 l uint // l is the length of the input parameters x and z. 219 xp uint // xp is the starting position of the input parameter x, x := d[xp:xp+l]. 220 zp uint // zp is the starting position of the input parameter z, z := d[zp:zp+l]. 221 s uint // s is the shift number. 222 r []Word // r is the expected output result z. 223 c Word // c is the expected return value. 224 m string // message. 225 } 226 227 var argshlVU = []argVU{ 228 // test cases for shlVU 229 {[]Word{1, _M, _M, _M, _M, _M, 3 << (_W - 2), 0}, 7, 0, 0, 1, []Word{2, _M - 1, _M, _M, _M, _M, 1<<(_W-1) + 1}, 1, "complete overlap of shlVU"}, 230 {[]Word{1, _M, _M, _M, _M, _M, 3 << (_W - 2), 0, 0, 0, 0}, 7, 0, 3, 1, []Word{2, _M - 1, _M, _M, _M, _M, 1<<(_W-1) + 1}, 1, "partial overlap by half of shlVU"}, 231 {[]Word{1, _M, _M, _M, _M, _M, 3 << (_W - 2), 0, 0, 0, 0, 0, 0, 0}, 7, 0, 6, 1, []Word{2, _M - 1, _M, _M, _M, _M, 1<<(_W-1) + 1}, 1, "partial overlap by 1 Word of shlVU"}, 232 {[]Word{1, _M, _M, _M, _M, _M, 3 << (_W - 2), 0, 0, 0, 0, 0, 0, 0, 0}, 7, 0, 7, 1, []Word{2, _M - 1, _M, _M, _M, _M, 1<<(_W-1) + 1}, 1, "no overlap of shlVU"}, 233 } 234 235 var argshrVU = []argVU{ 236 // test cases for shrVU 237 {[]Word{0, 3, _M, _M, _M, _M, _M, 1 << (_W - 1)}, 7, 1, 1, 1, []Word{1<<(_W-1) + 1, _M, _M, _M, _M, _M >> 1, 1 << (_W - 2)}, 1 << (_W - 1), "complete overlap of shrVU"}, 238 {[]Word{0, 0, 0, 0, 3, _M, _M, _M, _M, _M, 1 << (_W - 1)}, 7, 4, 1, 1, []Word{1<<(_W-1) + 1, _M, _M, _M, _M, _M >> 1, 1 << (_W - 2)}, 1 << (_W - 1), "partial overlap by half of shrVU"}, 239 {[]Word{0, 0, 0, 0, 0, 0, 0, 3, _M, _M, _M, _M, _M, 1 << (_W - 1)}, 7, 7, 1, 1, []Word{1<<(_W-1) + 1, _M, _M, _M, _M, _M >> 1, 1 << (_W - 2)}, 1 << (_W - 1), "partial overlap by 1 Word of shrVU"}, 240 {[]Word{0, 0, 0, 0, 0, 0, 0, 0, 3, _M, _M, _M, _M, _M, 1 << (_W - 1)}, 7, 8, 1, 1, []Word{1<<(_W-1) + 1, _M, _M, _M, _M, _M >> 1, 1 << (_W - 2)}, 1 << (_W - 1), "no overlap of shrVU"}, 241 } 242 243 func testShiftFunc(t *testing.T, f func(z, x []Word, s uint) Word, a argVU) { 244 // save a.d for error message, or it will be overwritten. 245 b := make([]Word, len(a.d)) 246 copy(b, a.d) 247 z := a.d[a.zp : a.zp+a.l] 248 x := a.d[a.xp : a.xp+a.l] 249 c := f(z, x, a.s) 250 for i, zi := range z { 251 if zi != a.r[i] { 252 t.Errorf("d := %v, %s(d[%d:%d], d[%d:%d], %d)\n\tgot z[%d] = %#x; want %#x", b, a.m, a.zp, a.zp+a.l, a.xp, a.xp+a.l, a.s, i, zi, a.r[i]) 253 break 254 } 255 } 256 if c != a.c { 257 t.Errorf("d := %v, %s(d[%d:%d], d[%d:%d], %d)\n\tgot c = %#x; want %#x", b, a.m, a.zp, a.zp+a.l, a.xp, a.xp+a.l, a.s, c, a.c) 258 } 259 } 260 261 func TestShiftOverlap(t *testing.T) { 262 for _, a := range argshlVU { 263 arg := a 264 testShiftFunc(t, shlVU, arg) 265 } 266 267 for _, a := range argshrVU { 268 arg := a 269 testShiftFunc(t, shrVU, arg) 270 } 271 } 272 273 func TestIssue31084(t *testing.T) { 274 // compute 10^n via 5^n << n. 275 const n = 165 276 p := nat(nil).expNN(nat{5}, nat{n}, nil) 277 p = p.shl(p, uint(n)) 278 got := string(p.utoa(10)) 279 want := "1" + strings.Repeat("0", n) 280 if got != want { 281 t.Errorf("shl(%v, %v)\n\tgot %s; want %s\n", p, uint(n), got, want) 282 } 283 } 284 285 func BenchmarkAddVW(b *testing.B) { 286 for _, n := range benchSizes { 287 if isRaceBuilder && n > 1e3 { 288 continue 289 } 290 x := rndV(n) 291 y := rndW() 292 z := make([]Word, n) 293 b.Run(fmt.Sprint(n), func(b *testing.B) { 294 b.SetBytes(int64(n * _S)) 295 for i := 0; i < b.N; i++ { 296 addVW(z, x, y) 297 } 298 }) 299 } 300 } 301 302 func BenchmarkSubVW(b *testing.B) { 303 for _, n := range benchSizes { 304 if isRaceBuilder && n > 1e3 { 305 continue 306 } 307 x := rndV(n) 308 y := rndW() 309 z := make([]Word, n) 310 b.Run(fmt.Sprint(n), func(b *testing.B) { 311 b.SetBytes(int64(n * _S)) 312 for i := 0; i < b.N; i++ { 313 subVW(z, x, y) 314 } 315 }) 316 } 317 } 318 319 type funVWW func(z, x []Word, y, r Word) (c Word) 320 type argVWW struct { 321 z, x nat 322 y, r Word 323 c Word 324 } 325 326 var prodVWW = []argVWW{ 327 {}, 328 {nat{0}, nat{0}, 0, 0, 0}, 329 {nat{991}, nat{0}, 0, 991, 0}, 330 {nat{0}, nat{_M}, 0, 0, 0}, 331 {nat{991}, nat{_M}, 0, 991, 0}, 332 {nat{0}, nat{0}, _M, 0, 0}, 333 {nat{991}, nat{0}, _M, 991, 0}, 334 {nat{1}, nat{1}, 1, 0, 0}, 335 {nat{992}, nat{1}, 1, 991, 0}, 336 {nat{22793}, nat{991}, 23, 0, 0}, 337 {nat{22800}, nat{991}, 23, 7, 0}, 338 {nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0, 0}, 339 {nat{7, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 7, 0}, 340 {nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0, 0}, 341 {nat{991, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 991, 0}, 342 {nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0, 0}, 343 {nat{991, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 991, 0}, 344 {nat{_M << 1 & _M}, nat{_M}, 1 << 1, 0, _M >> (_W - 1)}, 345 {nat{_M<<1&_M + 1}, nat{_M}, 1 << 1, 1, _M >> (_W - 1)}, 346 {nat{_M << 7 & _M}, nat{_M}, 1 << 7, 0, _M >> (_W - 7)}, 347 {nat{_M<<7&_M + 1<<6}, nat{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)}, 348 {nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 0, _M >> (_W - 7)}, 349 {nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)}, 350 } 351 352 func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) { 353 z := make(nat, len(a.z)) 354 c := f(z, a.x, a.y, a.r) 355 for i, zi := range z { 356 if zi != a.z[i] { 357 t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i]) 358 break 359 } 360 } 361 if c != a.c { 362 t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c) 363 } 364 } 365 366 // TODO(gri) mulAddVWW and divWVW are symmetric operations but 367 // their signature is not symmetric. Try to unify. 368 369 type funWVW func(z []Word, xn Word, x []Word, y Word) (r Word) 370 type argWVW struct { 371 z nat 372 xn Word 373 x nat 374 y Word 375 r Word 376 } 377 378 func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) { 379 z := make(nat, len(a.z)) 380 r := f(z, a.xn, a.x, a.y) 381 for i, zi := range z { 382 if zi != a.z[i] { 383 t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i]) 384 break 385 } 386 } 387 if r != a.r { 388 t.Errorf("%s%+v\n\tgot r = %#x; want %#x", msg, a, r, a.r) 389 } 390 } 391 392 func TestFunVWW(t *testing.T) { 393 for _, a := range prodVWW { 394 arg := a 395 testFunVWW(t, "mulAddVWW_g", mulAddVWW_g, arg) 396 testFunVWW(t, "mulAddVWW", mulAddVWW, arg) 397 398 if a.y != 0 && a.r < a.y { 399 arg := argWVW{a.x, a.c, a.z, a.y, a.r} 400 testFunWVW(t, "divWVW_g", divWVW_g, arg) 401 testFunWVW(t, "divWVW", divWVW, arg) 402 } 403 } 404 } 405 406 var mulWWTests = []struct { 407 x, y Word 408 q, r Word 409 }{ 410 {_M, _M, _M - 1, 1}, 411 // 32 bit only: {0xc47dfa8c, 50911, 0x98a4, 0x998587f4}, 412 } 413 414 func TestMulWW(t *testing.T) { 415 for i, test := range mulWWTests { 416 q, r := mulWW_g(test.x, test.y) 417 if q != test.q || r != test.r { 418 t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r) 419 } 420 } 421 } 422 423 var mulAddWWWTests = []struct { 424 x, y, c Word 425 q, r Word 426 }{ 427 // TODO(agl): These will only work on 64-bit platforms. 428 // {15064310297182388543, 0xe7df04d2d35d5d80, 13537600649892366549, 13644450054494335067, 10832252001440893781}, 429 // {15064310297182388543, 0xdab2f18048baa68d, 13644450054494335067, 12869334219691522700, 14233854684711418382}, 430 {_M, _M, 0, _M - 1, 1}, 431 {_M, _M, _M, _M, 0}, 432 } 433 434 func TestMulAddWWW(t *testing.T) { 435 for i, test := range mulAddWWWTests { 436 q, r := mulAddWWW_g(test.x, test.y, test.c) 437 if q != test.q || r != test.r { 438 t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r) 439 } 440 } 441 } 442 443 func BenchmarkMulAddVWW(b *testing.B) { 444 for _, n := range benchSizes { 445 if isRaceBuilder && n > 1e3 { 446 continue 447 } 448 z := make([]Word, n+1) 449 x := rndV(n) 450 y := rndW() 451 r := rndW() 452 b.Run(fmt.Sprint(n), func(b *testing.B) { 453 b.SetBytes(int64(n * _W)) 454 for i := 0; i < b.N; i++ { 455 mulAddVWW(z, x, y, r) 456 } 457 }) 458 } 459 } 460 461 func BenchmarkAddMulVVW(b *testing.B) { 462 for _, n := range benchSizes { 463 if isRaceBuilder && n > 1e3 { 464 continue 465 } 466 x := rndV(n) 467 y := rndW() 468 z := make([]Word, n) 469 b.Run(fmt.Sprint(n), func(b *testing.B) { 470 b.SetBytes(int64(n * _W)) 471 for i := 0; i < b.N; i++ { 472 addMulVVW(z, x, y) 473 } 474 }) 475 } 476 }