arith_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  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. package big
  5. import (
  6. "fmt"
  7. "internal/testenv"
  8. "math/bits"
  9. "math/rand"
  10. "strings"
  11. "testing"
  12. )
  13. var isRaceBuilder = strings.HasSuffix(testenv.Builder(), "-race")
  14. type funVV func(z, x, y []Word) (c Word)
  15. type argVV struct {
  16. z, x, y nat
  17. c Word
  18. }
  19. var sumVV = []argVV{
  20. {},
  21. {nat{0}, nat{0}, nat{0}, 0},
  22. {nat{1}, nat{1}, nat{0}, 0},
  23. {nat{0}, nat{_M}, nat{1}, 1},
  24. {nat{80235}, nat{12345}, nat{67890}, 0},
  25. {nat{_M - 1}, nat{_M}, nat{_M}, 1},
  26. {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, nat{1, 0, 0, 0}, 1},
  27. {nat{0, 0, 0, _M}, nat{_M, _M, _M, _M - 1}, nat{1, 0, 0, 0}, 0},
  28. {nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1},
  29. }
  30. func testFunVV(t *testing.T, msg string, f funVV, a argVV) {
  31. z := make(nat, len(a.z))
  32. c := f(z, a.x, a.y)
  33. for i, zi := range z {
  34. if zi != a.z[i] {
  35. t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
  36. break
  37. }
  38. }
  39. if c != a.c {
  40. t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
  41. }
  42. }
  43. func TestFunVV(t *testing.T) {
  44. for _, a := range sumVV {
  45. arg := a
  46. testFunVV(t, "addVV_g", addVV_g, arg)
  47. testFunVV(t, "addVV", addVV, arg)
  48. arg = argVV{a.z, a.y, a.x, a.c}
  49. testFunVV(t, "addVV_g symmetric", addVV_g, arg)
  50. testFunVV(t, "addVV symmetric", addVV, arg)
  51. arg = argVV{a.x, a.z, a.y, a.c}
  52. testFunVV(t, "subVV_g", subVV_g, arg)
  53. testFunVV(t, "subVV", subVV, arg)
  54. arg = argVV{a.y, a.z, a.x, a.c}
  55. testFunVV(t, "subVV_g symmetric", subVV_g, arg)
  56. testFunVV(t, "subVV symmetric", subVV, arg)
  57. }
  58. }
  59. // Always the same seed for reproducible results.
  60. var rnd = rand.New(rand.NewSource(0))
  61. func rndW() Word {
  62. return Word(rnd.Int63()<<1 | rnd.Int63n(2))
  63. }
  64. func rndV(n int) []Word {
  65. v := make([]Word, n)
  66. for i := range v {
  67. v[i] = rndW()
  68. }
  69. return v
  70. }
  71. var benchSizes = []int{1, 2, 3, 4, 5, 1e1, 1e2, 1e3, 1e4, 1e5}
  72. func BenchmarkAddVV(b *testing.B) {
  73. for _, n := range benchSizes {
  74. if isRaceBuilder && n > 1e3 {
  75. continue
  76. }
  77. x := rndV(n)
  78. y := rndV(n)
  79. z := make([]Word, n)
  80. b.Run(fmt.Sprint(n), func(b *testing.B) {
  81. b.SetBytes(int64(n * _W))
  82. for i := 0; i < b.N; i++ {
  83. addVV(z, x, y)
  84. }
  85. })
  86. }
  87. }
  88. func BenchmarkSubVV(b *testing.B) {
  89. for _, n := range benchSizes {
  90. if isRaceBuilder && n > 1e3 {
  91. continue
  92. }
  93. x := rndV(n)
  94. y := rndV(n)
  95. z := make([]Word, n)
  96. b.Run(fmt.Sprint(n), func(b *testing.B) {
  97. b.SetBytes(int64(n * _W))
  98. for i := 0; i < b.N; i++ {
  99. subVV(z, x, y)
  100. }
  101. })
  102. }
  103. }
  104. type funVW func(z, x []Word, y Word) (c Word)
  105. type argVW struct {
  106. z, x nat
  107. y Word
  108. c Word
  109. }
  110. var sumVW = []argVW{
  111. {},
  112. {nil, nil, 2, 2},
  113. {nat{0}, nat{0}, 0, 0},
  114. {nat{1}, nat{0}, 1, 0},
  115. {nat{1}, nat{1}, 0, 0},
  116. {nat{0}, nat{_M}, 1, 1},
  117. {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
  118. {nat{585}, nat{314}, 271, 0},
  119. }
  120. var lshVW = []argVW{
  121. {},
  122. {nat{0}, nat{0}, 0, 0},
  123. {nat{0}, nat{0}, 1, 0},
  124. {nat{0}, nat{0}, 20, 0},
  125. {nat{_M}, nat{_M}, 0, 0},
  126. {nat{_M << 1 & _M}, nat{_M}, 1, 1},
  127. {nat{_M << 20 & _M}, nat{_M}, 20, _M >> (_W - 20)},
  128. {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
  129. {nat{_M << 1 & _M, _M, _M}, nat{_M, _M, _M}, 1, 1},
  130. {nat{_M << 20 & _M, _M, _M}, nat{_M, _M, _M}, 20, _M >> (_W - 20)},
  131. }
  132. var rshVW = []argVW{
  133. {},
  134. {nat{0}, nat{0}, 0, 0},
  135. {nat{0}, nat{0}, 1, 0},
  136. {nat{0}, nat{0}, 20, 0},
  137. {nat{_M}, nat{_M}, 0, 0},
  138. {nat{_M >> 1}, nat{_M}, 1, _M << (_W - 1) & _M},
  139. {nat{_M >> 20}, nat{_M}, 20, _M << (_W - 20) & _M},
  140. {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
  141. {nat{_M, _M, _M >> 1}, nat{_M, _M, _M}, 1, _M << (_W - 1) & _M},
  142. {nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M},
  143. }
  144. func testFunVW(t *testing.T, msg string, f funVW, a argVW) {
  145. z := make(nat, len(a.z))
  146. c := f(z, a.x, a.y)
  147. for i, zi := range z {
  148. if zi != a.z[i] {
  149. t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
  150. break
  151. }
  152. }
  153. if c != a.c {
  154. t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
  155. }
  156. }
  157. func testFunVWext(t *testing.T, msg string, f funVW, f_g funVW, a argVW) {
  158. // using the result of addVW_g/subVW_g as golden
  159. z_g := make(nat, len(a.z))
  160. c_g := f_g(z_g, a.x, a.y)
  161. c := f(a.z, a.x, a.y)
  162. for i, zi := range a.z {
  163. if zi != z_g[i] {
  164. t.Errorf("%s\n\tgot z[%d] = %#x; want %#x", msg, i, zi, z_g[i])
  165. break
  166. }
  167. }
  168. if c != c_g {
  169. t.Errorf("%s\n\tgot c = %#x; want %#x", msg, c, c_g)
  170. }
  171. }
  172. func makeFunVW(f func(z, x []Word, s uint) (c Word)) funVW {
  173. return func(z, x []Word, s Word) (c Word) {
  174. return f(z, x, uint(s))
  175. }
  176. }
  177. func TestFunVW(t *testing.T) {
  178. for _, a := range sumVW {
  179. arg := a
  180. testFunVW(t, "addVW_g", addVW_g, arg)
  181. testFunVW(t, "addVW", addVW, arg)
  182. arg = argVW{a.x, a.z, a.y, a.c}
  183. testFunVW(t, "subVW_g", subVW_g, arg)
  184. testFunVW(t, "subVW", subVW, arg)
  185. }
  186. shlVW_g := makeFunVW(shlVU_g)
  187. shlVW := makeFunVW(shlVU)
  188. for _, a := range lshVW {
  189. arg := a
  190. testFunVW(t, "shlVU_g", shlVW_g, arg)
  191. testFunVW(t, "shlVU", shlVW, arg)
  192. }
  193. shrVW_g := makeFunVW(shrVU_g)
  194. shrVW := makeFunVW(shrVU)
  195. for _, a := range rshVW {
  196. arg := a
  197. testFunVW(t, "shrVU_g", shrVW_g, arg)
  198. testFunVW(t, "shrVU", shrVW, arg)
  199. }
  200. }
  201. // Construct a vector comprising the same word, usually '0' or 'maximum uint'
  202. func makeWordVec(e Word, n int) []Word {
  203. v := make([]Word, n)
  204. for i := range v {
  205. v[i] = e
  206. }
  207. return v
  208. }
  209. // Extended testing to addVW and subVW using various kinds of input data.
  210. // We utilize the results of addVW_g and subVW_g as golden reference to check
  211. // correctness.
  212. func TestFunVWExt(t *testing.T) {
  213. // 32 is the current threshold that triggers an optimized version of
  214. // calculation for large-sized vector, ensure we have sizes around it tested.
  215. var vwSizes = []int{0, 1, 3, 4, 5, 8, 9, 23, 31, 32, 33, 34, 35, 36, 50, 120}
  216. for _, n := range vwSizes {
  217. // vector of random numbers, using the result of addVW_g/subVW_g as golden
  218. x := rndV(n)
  219. y := rndW()
  220. z := make(nat, n)
  221. arg := argVW{z, x, y, 0}
  222. testFunVWext(t, "addVW, random inputs", addVW, addVW_g, arg)
  223. testFunVWext(t, "subVW, random inputs", subVW, subVW_g, arg)
  224. // vector of random numbers, but make 'x' and 'z' share storage
  225. arg = argVW{x, x, y, 0}
  226. testFunVWext(t, "addVW, random inputs, sharing storage", addVW, addVW_g, arg)
  227. testFunVWext(t, "subVW, random inputs, sharing storage", subVW, subVW_g, arg)
  228. // vector of maximum uint, to force carry flag set in each 'add'
  229. y = ^Word(0)
  230. x = makeWordVec(y, n)
  231. arg = argVW{z, x, y, 0}
  232. testFunVWext(t, "addVW, vector of max uint", addVW, addVW_g, arg)
  233. // vector of '0', to force carry flag set in each 'sub'
  234. x = makeWordVec(0, n)
  235. arg = argVW{z, x, 1, 0}
  236. testFunVWext(t, "subVW, vector of zero", subVW, subVW_g, arg)
  237. }
  238. }
  239. type argVU struct {
  240. d []Word // d is a Word slice, the input parameters x and z come from this array.
  241. l uint // l is the length of the input parameters x and z.
  242. xp uint // xp is the starting position of the input parameter x, x := d[xp:xp+l].
  243. zp uint // zp is the starting position of the input parameter z, z := d[zp:zp+l].
  244. s uint // s is the shift number.
  245. r []Word // r is the expected output result z.
  246. c Word // c is the expected return value.
  247. m string // message.
  248. }
  249. var argshlVUIn = []Word{1, 2, 4, 8, 16, 32, 64, 0, 0, 0}
  250. var argshlVUr0 = []Word{1, 2, 4, 8, 16, 32, 64}
  251. var argshlVUr1 = []Word{2, 4, 8, 16, 32, 64, 128}
  252. var argshlVUrWm1 = []Word{1 << (_W - 1), 0, 1, 2, 4, 8, 16}
  253. var argshlVU = []argVU{
  254. // test cases for shlVU
  255. {[]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"},
  256. {[]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"},
  257. {[]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"},
  258. {[]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"},
  259. // additional test cases with shift values of 0, 1 and (_W-1)
  260. {argshlVUIn, 7, 0, 0, 0, argshlVUr0, 0, "complete overlap of shlVU and shift of 0"},
  261. {argshlVUIn, 7, 0, 0, 1, argshlVUr1, 0, "complete overlap of shlVU and shift of 1"},
  262. {argshlVUIn, 7, 0, 0, _W - 1, argshlVUrWm1, 32, "complete overlap of shlVU and shift of _W - 1"},
  263. {argshlVUIn, 7, 0, 1, 0, argshlVUr0, 0, "partial overlap by 6 Words of shlVU and shift of 0"},
  264. {argshlVUIn, 7, 0, 1, 1, argshlVUr1, 0, "partial overlap by 6 Words of shlVU and shift of 1"},
  265. {argshlVUIn, 7, 0, 1, _W - 1, argshlVUrWm1, 32, "partial overlap by 6 Words of shlVU and shift of _W - 1"},
  266. {argshlVUIn, 7, 0, 2, 0, argshlVUr0, 0, "partial overlap by 5 Words of shlVU and shift of 0"},
  267. {argshlVUIn, 7, 0, 2, 1, argshlVUr1, 0, "partial overlap by 5 Words of shlVU and shift of 1"},
  268. {argshlVUIn, 7, 0, 2, _W - 1, argshlVUrWm1, 32, "partial overlap by 5 Words of shlVU abd shift of _W - 1"},
  269. {argshlVUIn, 7, 0, 3, 0, argshlVUr0, 0, "partial overlap by 4 Words of shlVU and shift of 0"},
  270. {argshlVUIn, 7, 0, 3, 1, argshlVUr1, 0, "partial overlap by 4 Words of shlVU and shift of 1"},
  271. {argshlVUIn, 7, 0, 3, _W - 1, argshlVUrWm1, 32, "partial overlap by 4 Words of shlVU and shift of _W - 1"},
  272. }
  273. var argshrVUIn = []Word{0, 0, 0, 1, 2, 4, 8, 16, 32, 64}
  274. var argshrVUr0 = []Word{1, 2, 4, 8, 16, 32, 64}
  275. var argshrVUr1 = []Word{0, 1, 2, 4, 8, 16, 32}
  276. var argshrVUrWm1 = []Word{4, 8, 16, 32, 64, 128, 0}
  277. var argshrVU = []argVU{
  278. // test cases for shrVU
  279. {[]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"},
  280. {[]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"},
  281. {[]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"},
  282. {[]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"},
  283. // additional test cases with shift values of 0, 1 and (_W-1)
  284. {argshrVUIn, 7, 3, 3, 0, argshrVUr0, 0, "complete overlap of shrVU and shift of 0"},
  285. {argshrVUIn, 7, 3, 3, 1, argshrVUr1, 1 << (_W - 1), "complete overlap of shrVU and shift of 1"},
  286. {argshrVUIn, 7, 3, 3, _W - 1, argshrVUrWm1, 2, "complete overlap of shrVU and shift of _W - 1"},
  287. {argshrVUIn, 7, 3, 2, 0, argshrVUr0, 0, "partial overlap by 6 Words of shrVU and shift of 0"},
  288. {argshrVUIn, 7, 3, 2, 1, argshrVUr1, 1 << (_W - 1), "partial overlap by 6 Words of shrVU and shift of 1"},
  289. {argshrVUIn, 7, 3, 2, _W - 1, argshrVUrWm1, 2, "partial overlap by 6 Words of shrVU and shift of _W - 1"},
  290. {argshrVUIn, 7, 3, 1, 0, argshrVUr0, 0, "partial overlap by 5 Words of shrVU and shift of 0"},
  291. {argshrVUIn, 7, 3, 1, 1, argshrVUr1, 1 << (_W - 1), "partial overlap by 5 Words of shrVU and shift of 1"},
  292. {argshrVUIn, 7, 3, 1, _W - 1, argshrVUrWm1, 2, "partial overlap by 5 Words of shrVU and shift of _W - 1"},
  293. {argshrVUIn, 7, 3, 0, 0, argshrVUr0, 0, "partial overlap by 4 Words of shrVU and shift of 0"},
  294. {argshrVUIn, 7, 3, 0, 1, argshrVUr1, 1 << (_W - 1), "partial overlap by 4 Words of shrVU and shift of 1"},
  295. {argshrVUIn, 7, 3, 0, _W - 1, argshrVUrWm1, 2, "partial overlap by 4 Words of shrVU and shift of _W - 1"},
  296. }
  297. func testShiftFunc(t *testing.T, f func(z, x []Word, s uint) Word, a argVU) {
  298. // work on copy of a.d to preserve the original data.
  299. b := make([]Word, len(a.d))
  300. copy(b, a.d)
  301. z := b[a.zp : a.zp+a.l]
  302. x := b[a.xp : a.xp+a.l]
  303. c := f(z, x, a.s)
  304. for i, zi := range z {
  305. if zi != a.r[i] {
  306. t.Errorf("d := %v, %s(d[%d:%d], d[%d:%d], %d)\n\tgot z[%d] = %#x; want %#x", a.d, a.m, a.zp, a.zp+a.l, a.xp, a.xp+a.l, a.s, i, zi, a.r[i])
  307. break
  308. }
  309. }
  310. if c != a.c {
  311. t.Errorf("d := %v, %s(d[%d:%d], d[%d:%d], %d)\n\tgot c = %#x; want %#x", a.d, a.m, a.zp, a.zp+a.l, a.xp, a.xp+a.l, a.s, c, a.c)
  312. }
  313. }
  314. func TestShiftOverlap(t *testing.T) {
  315. for _, a := range argshlVU {
  316. arg := a
  317. testShiftFunc(t, shlVU, arg)
  318. }
  319. for _, a := range argshrVU {
  320. arg := a
  321. testShiftFunc(t, shrVU, arg)
  322. }
  323. }
  324. func TestIssue31084(t *testing.T) {
  325. // compute 10^n via 5^n << n.
  326. const n = 165
  327. p := nat(nil).expNN(nat{5}, nat{n}, nil)
  328. p = p.shl(p, n)
  329. got := string(p.utoa(10))
  330. want := "1" + strings.Repeat("0", n)
  331. if got != want {
  332. t.Errorf("shl(%v, %v)\n\tgot %s\n\twant %s", p, n, got, want)
  333. }
  334. }
  335. const issue42838Value = "159309191113245227702888039776771180559110455519261878607388585338616290151305816094308987472018268594098344692611135542392730712890625"
  336. func TestIssue42838(t *testing.T) {
  337. const s = 192
  338. z, _, _, _ := nat(nil).scan(strings.NewReader(issue42838Value), 0, false)
  339. z = z.shl(z, s)
  340. got := string(z.utoa(10))
  341. want := "1" + strings.Repeat("0", s)
  342. if got != want {
  343. t.Errorf("shl(%v, %v)\n\tgot %s\n\twant %s", z, s, got, want)
  344. }
  345. }
  346. func BenchmarkAddVW(b *testing.B) {
  347. for _, n := range benchSizes {
  348. if isRaceBuilder && n > 1e3 {
  349. continue
  350. }
  351. x := rndV(n)
  352. y := rndW()
  353. z := make([]Word, n)
  354. b.Run(fmt.Sprint(n), func(b *testing.B) {
  355. b.SetBytes(int64(n * _S))
  356. for i := 0; i < b.N; i++ {
  357. addVW(z, x, y)
  358. }
  359. })
  360. }
  361. }
  362. // Benchmarking addVW using vector of maximum uint to force carry flag set
  363. func BenchmarkAddVWext(b *testing.B) {
  364. for _, n := range benchSizes {
  365. if isRaceBuilder && n > 1e3 {
  366. continue
  367. }
  368. y := ^Word(0)
  369. x := makeWordVec(y, n)
  370. z := make([]Word, n)
  371. b.Run(fmt.Sprint(n), func(b *testing.B) {
  372. b.SetBytes(int64(n * _S))
  373. for i := 0; i < b.N; i++ {
  374. addVW(z, x, y)
  375. }
  376. })
  377. }
  378. }
  379. func BenchmarkSubVW(b *testing.B) {
  380. for _, n := range benchSizes {
  381. if isRaceBuilder && n > 1e3 {
  382. continue
  383. }
  384. x := rndV(n)
  385. y := rndW()
  386. z := make([]Word, n)
  387. b.Run(fmt.Sprint(n), func(b *testing.B) {
  388. b.SetBytes(int64(n * _S))
  389. for i := 0; i < b.N; i++ {
  390. subVW(z, x, y)
  391. }
  392. })
  393. }
  394. }
  395. // Benchmarking subVW using vector of zero to force carry flag set
  396. func BenchmarkSubVWext(b *testing.B) {
  397. for _, n := range benchSizes {
  398. if isRaceBuilder && n > 1e3 {
  399. continue
  400. }
  401. x := makeWordVec(0, n)
  402. y := Word(1)
  403. z := make([]Word, n)
  404. b.Run(fmt.Sprint(n), func(b *testing.B) {
  405. b.SetBytes(int64(n * _S))
  406. for i := 0; i < b.N; i++ {
  407. subVW(z, x, y)
  408. }
  409. })
  410. }
  411. }
  412. type funVWW func(z, x []Word, y, r Word) (c Word)
  413. type argVWW struct {
  414. z, x nat
  415. y, r Word
  416. c Word
  417. }
  418. var prodVWW = []argVWW{
  419. {},
  420. {nat{0}, nat{0}, 0, 0, 0},
  421. {nat{991}, nat{0}, 0, 991, 0},
  422. {nat{0}, nat{_M}, 0, 0, 0},
  423. {nat{991}, nat{_M}, 0, 991, 0},
  424. {nat{0}, nat{0}, _M, 0, 0},
  425. {nat{991}, nat{0}, _M, 991, 0},
  426. {nat{1}, nat{1}, 1, 0, 0},
  427. {nat{992}, nat{1}, 1, 991, 0},
  428. {nat{22793}, nat{991}, 23, 0, 0},
  429. {nat{22800}, nat{991}, 23, 7, 0},
  430. {nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0, 0},
  431. {nat{7, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 7, 0},
  432. {nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0, 0},
  433. {nat{991, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 991, 0},
  434. {nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0, 0},
  435. {nat{991, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 991, 0},
  436. {nat{_M << 1 & _M}, nat{_M}, 1 << 1, 0, _M >> (_W - 1)},
  437. {nat{_M<<1&_M + 1}, nat{_M}, 1 << 1, 1, _M >> (_W - 1)},
  438. {nat{_M << 7 & _M}, nat{_M}, 1 << 7, 0, _M >> (_W - 7)},
  439. {nat{_M<<7&_M + 1<<6}, nat{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
  440. {nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 0, _M >> (_W - 7)},
  441. {nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
  442. }
  443. func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) {
  444. z := make(nat, len(a.z))
  445. c := f(z, a.x, a.y, a.r)
  446. for i, zi := range z {
  447. if zi != a.z[i] {
  448. t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
  449. break
  450. }
  451. }
  452. if c != a.c {
  453. t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
  454. }
  455. }
  456. // TODO(gri) mulAddVWW and divWVW are symmetric operations but
  457. // their signature is not symmetric. Try to unify.
  458. type funWVW func(z []Word, xn Word, x []Word, y Word) (r Word)
  459. type argWVW struct {
  460. z nat
  461. xn Word
  462. x nat
  463. y Word
  464. r Word
  465. }
  466. func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) {
  467. z := make(nat, len(a.z))
  468. r := f(z, a.xn, a.x, a.y)
  469. for i, zi := range z {
  470. if zi != a.z[i] {
  471. t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
  472. break
  473. }
  474. }
  475. if r != a.r {
  476. t.Errorf("%s%+v\n\tgot r = %#x; want %#x", msg, a, r, a.r)
  477. }
  478. }
  479. func TestFunVWW(t *testing.T) {
  480. for _, a := range prodVWW {
  481. arg := a
  482. testFunVWW(t, "mulAddVWW_g", mulAddVWW_g, arg)
  483. testFunVWW(t, "mulAddVWW", mulAddVWW, arg)
  484. if a.y != 0 && a.r < a.y {
  485. arg := argWVW{a.x, a.c, a.z, a.y, a.r}
  486. testFunWVW(t, "divWVW", divWVW, arg)
  487. }
  488. }
  489. }
  490. var mulWWTests = []struct {
  491. x, y Word
  492. q, r Word
  493. }{
  494. {_M, _M, _M - 1, 1},
  495. // 32 bit only: {0xc47dfa8c, 50911, 0x98a4, 0x998587f4},
  496. }
  497. func TestMulWW(t *testing.T) {
  498. for i, test := range mulWWTests {
  499. q, r := mulWW_g(test.x, test.y)
  500. if q != test.q || r != test.r {
  501. t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
  502. }
  503. }
  504. }
  505. var mulAddWWWTests = []struct {
  506. x, y, c Word
  507. q, r Word
  508. }{
  509. // TODO(agl): These will only work on 64-bit platforms.
  510. // {15064310297182388543, 0xe7df04d2d35d5d80, 13537600649892366549, 13644450054494335067, 10832252001440893781},
  511. // {15064310297182388543, 0xdab2f18048baa68d, 13644450054494335067, 12869334219691522700, 14233854684711418382},
  512. {_M, _M, 0, _M - 1, 1},
  513. {_M, _M, _M, _M, 0},
  514. }
  515. func TestMulAddWWW(t *testing.T) {
  516. for i, test := range mulAddWWWTests {
  517. q, r := mulAddWWW_g(test.x, test.y, test.c)
  518. if q != test.q || r != test.r {
  519. t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
  520. }
  521. }
  522. }
  523. var divWWTests = []struct {
  524. x1, x0, y Word
  525. q, r Word
  526. }{
  527. {_M >> 1, 0, _M, _M >> 1, _M >> 1},
  528. {_M - (1 << (_W - 2)), _M, 3 << (_W - 2), _M, _M - (1 << (_W - 2))},
  529. }
  530. const testsNumber = 1 << 16
  531. func TestDivWW(t *testing.T) {
  532. i := 0
  533. for i, test := range divWWTests {
  534. rec := reciprocalWord(test.y)
  535. q, r := divWW(test.x1, test.x0, test.y, rec)
  536. if q != test.q || r != test.r {
  537. t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
  538. }
  539. }
  540. //random tests
  541. for ; i < testsNumber; i++ {
  542. x1 := rndW()
  543. x0 := rndW()
  544. y := rndW()
  545. if x1 >= y {
  546. continue
  547. }
  548. rec := reciprocalWord(y)
  549. qGot, rGot := divWW(x1, x0, y, rec)
  550. qWant, rWant := bits.Div(uint(x1), uint(x0), uint(y))
  551. if uint(qGot) != qWant || uint(rGot) != rWant {
  552. t.Errorf("#%d got (%x, %x) want (%x, %x)", i, qGot, rGot, qWant, rWant)
  553. }
  554. }
  555. }
  556. func BenchmarkMulAddVWW(b *testing.B) {
  557. for _, n := range benchSizes {
  558. if isRaceBuilder && n > 1e3 {
  559. continue
  560. }
  561. z := make([]Word, n+1)
  562. x := rndV(n)
  563. y := rndW()
  564. r := rndW()
  565. b.Run(fmt.Sprint(n), func(b *testing.B) {
  566. b.SetBytes(int64(n * _W))
  567. for i := 0; i < b.N; i++ {
  568. mulAddVWW(z, x, y, r)
  569. }
  570. })
  571. }
  572. }
  573. func BenchmarkAddMulVVW(b *testing.B) {
  574. for _, n := range benchSizes {
  575. if isRaceBuilder && n > 1e3 {
  576. continue
  577. }
  578. x := rndV(n)
  579. y := rndW()
  580. z := make([]Word, n)
  581. b.Run(fmt.Sprint(n), func(b *testing.B) {
  582. b.SetBytes(int64(n * _W))
  583. for i := 0; i < b.N; i++ {
  584. addMulVVW(z, x, y)
  585. }
  586. })
  587. }
  588. }
  589. func BenchmarkDivWVW(b *testing.B) {
  590. for _, n := range benchSizes {
  591. if isRaceBuilder && n > 1e3 {
  592. continue
  593. }
  594. x := rndV(n)
  595. y := rndW()
  596. z := make([]Word, n)
  597. b.Run(fmt.Sprint(n), func(b *testing.B) {
  598. b.SetBytes(int64(n * _W))
  599. for i := 0; i < b.N; i++ {
  600. divWVW(z, 0, x, y)
  601. }
  602. })
  603. }
  604. }
  605. func BenchmarkNonZeroShifts(b *testing.B) {
  606. for _, n := range benchSizes {
  607. if isRaceBuilder && n > 1e3 {
  608. continue
  609. }
  610. x := rndV(n)
  611. s := uint(rand.Int63n(_W-2)) + 1 // avoid 0 and over-large shifts
  612. z := make([]Word, n)
  613. b.Run(fmt.Sprint(n), func(b *testing.B) {
  614. b.SetBytes(int64(n * _W))
  615. b.Run("shrVU", func(b *testing.B) {
  616. for i := 0; i < b.N; i++ {
  617. _ = shrVU(z, x, s)
  618. }
  619. })
  620. b.Run("shlVU", func(b *testing.B) {
  621. for i := 0; i < b.N; i++ {
  622. _ = shlVU(z, x, s)
  623. }
  624. })
  625. })
  626. }
  627. }