rnd.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. // Copyright (c) 2014 The mathutil 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 mathutil
  5. import (
  6. "fmt"
  7. "math"
  8. "math/big"
  9. )
  10. // FC32 is a full cycle PRNG covering the 32 bit signed integer range.
  11. // In contrast to full cycle generators shown at e.g. http://en.wikipedia.org/wiki/Full_cycle,
  12. // this code doesn't produce values at constant delta (mod cycle length).
  13. // The 32 bit limit is per this implementation, the algorithm used has no intrinsic limit on the cycle size.
  14. // Properties include:
  15. // - Adjustable limits on creation (hi, lo).
  16. // - Positionable/randomly accessible (Pos, Seek).
  17. // - Repeatable (deterministic).
  18. // - Can run forward or backward (Next, Prev).
  19. // - For a billion numbers cycle the Next/Prev PRN can be produced in cca 100-150ns.
  20. // That's like 5-10 times slower compared to PRNs generated using the (non FC) rand package.
  21. type FC32 struct {
  22. cycle int64 // On average: 3 * delta / 2, (HQ: 2 * delta)
  23. delta int64 // hi - lo
  24. factors [][]int64 // This trades some space for hopefully a bit of speed (multiple adding vs multiplying).
  25. lo int
  26. mods []int // pos % set
  27. pos int64 // Within cycle.
  28. primes []int64 // Ordered. ∏ primes == cycle.
  29. set []int64 // Reordered primes (magnitude order bases) according to seed.
  30. }
  31. // NewFC32 returns a newly created FC32 adjusted for the closed interval [lo, hi] or an Error if any.
  32. // If hq == true then trade some generation time for improved (pseudo)randomness.
  33. func NewFC32(lo, hi int, hq bool) (r *FC32, err error) {
  34. if lo > hi {
  35. return nil, fmt.Errorf("invalid range %d > %d", lo, hi)
  36. }
  37. if uint64(hi)-uint64(lo) > math.MaxUint32 {
  38. return nil, fmt.Errorf("range out of int32 limits %d, %d", lo, hi)
  39. }
  40. delta := int64(hi) - int64(lo)
  41. // Find the primorial covering whole delta
  42. n, set, p := int64(1), []int64{}, uint32(2)
  43. if hq {
  44. p++
  45. }
  46. for {
  47. set = append(set, int64(p))
  48. n *= int64(p)
  49. if n > delta {
  50. break
  51. }
  52. p, _ = NextPrime(p)
  53. }
  54. // Adjust the set so n ∊ [delta, 2 * delta] (HQ: [delta, 3 * delta])
  55. // while keeping the cardinality of the set (correlates with the statistic "randomness quality")
  56. // at max, i.e. discard atmost one member.
  57. i := -1 // no candidate prime
  58. if n > 2*(delta+1) {
  59. for j, p := range set {
  60. q := n / p
  61. if q < delta+1 {
  62. break
  63. }
  64. i = j // mark the highest candidate prime set index
  65. }
  66. }
  67. if i >= 0 { // shrink the inner cycle
  68. n = n / set[i]
  69. set = delete(set, i)
  70. }
  71. r = &FC32{
  72. cycle: n,
  73. delta: delta,
  74. factors: make([][]int64, len(set)),
  75. lo: lo,
  76. mods: make([]int, len(set)),
  77. primes: set,
  78. }
  79. r.Seed(1) // the default seed should be always non zero
  80. return
  81. }
  82. // Cycle reports the length of the inner FCPRNG cycle.
  83. // Cycle is atmost the double (HQ: triple) of the generator period (hi - lo + 1).
  84. func (r *FC32) Cycle() int64 {
  85. return r.cycle
  86. }
  87. // Next returns the first PRN after Pos.
  88. func (r *FC32) Next() int {
  89. return r.step(1)
  90. }
  91. // Pos reports the current position within the inner cycle.
  92. func (r *FC32) Pos() int64 {
  93. return r.pos
  94. }
  95. // Prev return the first PRN before Pos.
  96. func (r *FC32) Prev() int {
  97. return r.step(-1)
  98. }
  99. // Seed uses the provided seed value to initialize the generator to a deterministic state.
  100. // A zero seed produces a "canonical" generator with worse randomness than for most non zero seeds.
  101. // Still, the FC property holds for any seed value.
  102. func (r *FC32) Seed(seed int64) {
  103. u := uint64(seed)
  104. r.set = mix(r.primes, &u)
  105. n := int64(1)
  106. for i, p := range r.set {
  107. k := make([]int64, p)
  108. v := int64(0)
  109. for j := range k {
  110. k[j] = v
  111. v += n
  112. }
  113. n *= p
  114. r.factors[i] = mix(k, &u)
  115. }
  116. }
  117. // Seek sets Pos to |pos| % Cycle.
  118. func (r *FC32) Seek(pos int64) { //vet:ignore
  119. if pos < 0 {
  120. pos = -pos
  121. }
  122. pos %= r.cycle
  123. r.pos = pos
  124. for i, p := range r.set {
  125. r.mods[i] = int(pos % p)
  126. }
  127. }
  128. func (r *FC32) step(dir int) int {
  129. for { // avg loops per step: 3/2 (HQ: 2)
  130. y := int64(0)
  131. pos := r.pos
  132. pos += int64(dir)
  133. switch {
  134. case pos < 0:
  135. pos = r.cycle - 1
  136. case pos >= r.cycle:
  137. pos = 0
  138. }
  139. r.pos = pos
  140. for i, mod := range r.mods {
  141. mod += dir
  142. p := int(r.set[i])
  143. switch {
  144. case mod < 0:
  145. mod = p - 1
  146. case mod >= p:
  147. mod = 0
  148. }
  149. r.mods[i] = mod
  150. y += r.factors[i][mod]
  151. }
  152. if y <= r.delta {
  153. return int(y) + r.lo
  154. }
  155. }
  156. }
  157. func delete(set []int64, i int) (y []int64) {
  158. for j, v := range set {
  159. if j != i {
  160. y = append(y, v)
  161. }
  162. }
  163. return
  164. }
  165. func mix(set []int64, seed *uint64) (y []int64) {
  166. for len(set) != 0 {
  167. *seed = rol(*seed)
  168. i := int(*seed % uint64(len(set)))
  169. y = append(y, set[i])
  170. set = delete(set, i)
  171. }
  172. return
  173. }
  174. func rol(u uint64) (y uint64) {
  175. y = u << 1
  176. if int64(u) < 0 {
  177. y |= 1
  178. }
  179. return
  180. }
  181. // FCBig is a full cycle PRNG covering ranges outside of the int32 limits.
  182. // For more info see the FC32 docs.
  183. // Next/Prev PRN on a 1e15 cycle can be produced in about 2 µsec.
  184. type FCBig struct {
  185. cycle *big.Int // On average: 3 * delta / 2, (HQ: 2 * delta)
  186. delta *big.Int // hi - lo
  187. factors [][]*big.Int // This trades some space for hopefully a bit of speed (multiple adding vs multiplying).
  188. lo *big.Int
  189. mods []int // pos % set
  190. pos *big.Int // Within cycle.
  191. primes []int64 // Ordered. ∏ primes == cycle.
  192. set []int64 // Reordered primes (magnitude order bases) according to seed.
  193. }
  194. // NewFCBig returns a newly created FCBig adjusted for the closed interval [lo, hi] or an Error if any.
  195. // If hq == true then trade some generation time for improved (pseudo)randomness.
  196. func NewFCBig(lo, hi *big.Int, hq bool) (r *FCBig, err error) {
  197. if lo.Cmp(hi) > 0 {
  198. return nil, fmt.Errorf("invalid range %d > %d", lo, hi)
  199. }
  200. delta := big.NewInt(0)
  201. delta.Add(delta, hi).Sub(delta, lo)
  202. // Find the primorial covering whole delta
  203. n, set, pp, p := big.NewInt(1), []int64{}, big.NewInt(0), uint32(2)
  204. if hq {
  205. p++
  206. }
  207. for {
  208. set = append(set, int64(p))
  209. pp.SetInt64(int64(p))
  210. n.Mul(n, pp)
  211. if n.Cmp(delta) > 0 {
  212. break
  213. }
  214. p, _ = NextPrime(p)
  215. }
  216. // Adjust the set so n ∊ [delta, 2 * delta] (HQ: [delta, 3 * delta])
  217. // while keeping the cardinality of the set (correlates with the statistic "randomness quality")
  218. // at max, i.e. discard atmost one member.
  219. dd1 := big.NewInt(1)
  220. dd1.Add(dd1, delta)
  221. dd2 := big.NewInt(0)
  222. dd2.Lsh(dd1, 1)
  223. i := -1 // no candidate prime
  224. if n.Cmp(dd2) > 0 {
  225. q := big.NewInt(0)
  226. for j, p := range set {
  227. pp.SetInt64(p)
  228. q.Set(n)
  229. q.Div(q, pp)
  230. if q.Cmp(dd1) < 0 {
  231. break
  232. }
  233. i = j // mark the highest candidate prime set index
  234. }
  235. }
  236. if i >= 0 { // shrink the inner cycle
  237. pp.SetInt64(set[i])
  238. n.Div(n, pp)
  239. set = delete(set, i)
  240. }
  241. r = &FCBig{
  242. cycle: n,
  243. delta: delta,
  244. factors: make([][]*big.Int, len(set)),
  245. lo: lo,
  246. mods: make([]int, len(set)),
  247. pos: big.NewInt(0),
  248. primes: set,
  249. }
  250. r.Seed(1) // the default seed should be always non zero
  251. return
  252. }
  253. // Cycle reports the length of the inner FCPRNG cycle.
  254. // Cycle is atmost the double (HQ: triple) of the generator period (hi - lo + 1).
  255. func (r *FCBig) Cycle() *big.Int {
  256. return r.cycle
  257. }
  258. // Next returns the first PRN after Pos.
  259. func (r *FCBig) Next() *big.Int {
  260. return r.step(1)
  261. }
  262. // Pos reports the current position within the inner cycle.
  263. func (r *FCBig) Pos() *big.Int {
  264. return r.pos
  265. }
  266. // Prev return the first PRN before Pos.
  267. func (r *FCBig) Prev() *big.Int {
  268. return r.step(-1)
  269. }
  270. // Seed uses the provided seed value to initialize the generator to a deterministic state.
  271. // A zero seed produces a "canonical" generator with worse randomness than for most non zero seeds.
  272. // Still, the FC property holds for any seed value.
  273. func (r *FCBig) Seed(seed int64) {
  274. u := uint64(seed)
  275. r.set = mix(r.primes, &u)
  276. n := big.NewInt(1)
  277. v := big.NewInt(0)
  278. pp := big.NewInt(0)
  279. for i, p := range r.set {
  280. k := make([]*big.Int, p)
  281. v.SetInt64(0)
  282. for j := range k {
  283. k[j] = big.NewInt(0)
  284. k[j].Set(v)
  285. v.Add(v, n)
  286. }
  287. pp.SetInt64(p)
  288. n.Mul(n, pp)
  289. r.factors[i] = mixBig(k, &u)
  290. }
  291. }
  292. // Seek sets Pos to |pos| % Cycle.
  293. func (r *FCBig) Seek(pos *big.Int) {
  294. r.pos.Set(pos)
  295. r.pos.Abs(r.pos)
  296. r.pos.Mod(r.pos, r.cycle)
  297. mod := big.NewInt(0)
  298. pp := big.NewInt(0)
  299. for i, p := range r.set {
  300. pp.SetInt64(p)
  301. r.mods[i] = int(mod.Mod(r.pos, pp).Int64())
  302. }
  303. }
  304. func (r *FCBig) step(dir int) (y *big.Int) {
  305. y = big.NewInt(0)
  306. d := big.NewInt(int64(dir))
  307. for { // avg loops per step: 3/2 (HQ: 2)
  308. r.pos.Add(r.pos, d)
  309. switch {
  310. case r.pos.Sign() < 0:
  311. r.pos.Add(r.pos, r.cycle)
  312. case r.pos.Cmp(r.cycle) >= 0:
  313. r.pos.SetInt64(0)
  314. }
  315. for i, mod := range r.mods {
  316. mod += dir
  317. p := int(r.set[i])
  318. switch {
  319. case mod < 0:
  320. mod = p - 1
  321. case mod >= p:
  322. mod = 0
  323. }
  324. r.mods[i] = mod
  325. y.Add(y, r.factors[i][mod])
  326. }
  327. if y.Cmp(r.delta) <= 0 {
  328. y.Add(y, r.lo)
  329. return
  330. }
  331. y.SetInt64(0)
  332. }
  333. }
  334. func deleteBig(set []*big.Int, i int) (y []*big.Int) {
  335. for j, v := range set {
  336. if j != i {
  337. y = append(y, v)
  338. }
  339. }
  340. return
  341. }
  342. func mixBig(set []*big.Int, seed *uint64) (y []*big.Int) {
  343. for len(set) != 0 {
  344. *seed = rol(*seed)
  345. i := int(*seed % uint64(len(set)))
  346. y = append(y, set[i])
  347. set = deleteBig(set, i)
  348. }
  349. return
  350. }