fastrand.go 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. // Package fastrand implements fast pesudorandom number generator
  2. // that should scale well on multi-CPU systems.
  3. //
  4. // Use crypto/rand instead of this package for generating
  5. // cryptographically secure random numbers.
  6. package fastrand
  7. import (
  8. "sync"
  9. "time"
  10. )
  11. // Uint32 returns pseudorandom uint32.
  12. //
  13. // It is safe calling this function from concurrent goroutines.
  14. func Uint32() uint32 {
  15. v := rngPool.Get()
  16. if v == nil {
  17. v = &RNG{}
  18. }
  19. r := v.(*RNG)
  20. x := r.Uint32()
  21. rngPool.Put(r)
  22. return x
  23. }
  24. var rngPool sync.Pool
  25. // Uint32n returns pseudorandom uint32 in the range [0..maxN).
  26. //
  27. // It is safe calling this function from concurrent goroutines.
  28. func Uint32n(maxN uint32) uint32 {
  29. x := Uint32()
  30. // See http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
  31. return uint32((uint64(x) * uint64(maxN)) >> 32)
  32. }
  33. // RNG is a pseudorandom number generator.
  34. //
  35. // It is unsafe to call RNG methods from concurrent goroutines.
  36. type RNG struct {
  37. x uint32
  38. }
  39. // Uint32 returns pseudorandom uint32.
  40. //
  41. // It is unsafe to call this method from concurrent goroutines.
  42. func (r *RNG) Uint32() uint32 {
  43. for r.x == 0 {
  44. r.x = getRandomUint32()
  45. }
  46. // See https://en.wikipedia.org/wiki/Xorshift
  47. x := r.x
  48. x ^= x << 13
  49. x ^= x >> 17
  50. x ^= x << 5
  51. r.x = x
  52. return x
  53. }
  54. // Uint32n returns pseudorandom uint32 in the range [0..maxN).
  55. //
  56. // It is unsafe to call this method from concurrent goroutines.
  57. func (r *RNG) Uint32n(maxN uint32) uint32 {
  58. x := r.Uint32()
  59. // See http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
  60. return uint32((uint64(x) * uint64(maxN)) >> 32)
  61. }
  62. func getRandomUint32() uint32 {
  63. x := time.Now().UnixNano()
  64. return uint32((x >> 32) ^ x)
  65. }