1. package utils
  2. import (
  3. "crypto/rand"
  4. "errors"
  5. "math/big"
  6. prand "math/rand"
  7. "time"
  8. )
  9. //权重随机器
  10. // WeightItem interface
  11. type WeightItem interface {
  12. // GetWeight 当前 Item 权重
  13. GetWeight() int64
  14. }
  15. // WeightRand 权重随机器
  16. type WeightRand struct {
  17. sum int64
  18. weightList []WeightItem
  19. }
  20. // NewWeightRand New WeightRand
  21. func NewWeightRand(items []WeightItem) *WeightRand {
  22. if len(items) <= 0 {
  23. return nil
  24. }
  25. w := &WeightRand{
  26. sum: 0,
  27. weightList: items,
  28. }
  29. w.intWeightSum()
  30. return w
  31. }
  32. // Rand 随机出结果
  33. func (w *WeightRand) Rand() (WeightItem, error) {
  34. items := w.weightList
  35. if len(items) <= 0 || w.sum <= 0 {
  36. return nil, errors.New("weight Items nil")
  37. }
  38. var err error
  39. var num, num2 int64
  40. num2, err = Rand(w.sum)
  41. if err != nil {
  42. return nil, err
  43. }
  44. for _, v := range items {
  45. num += v.GetWeight()
  46. if num > num2 {
  47. return v, nil
  48. }
  49. }
  50. return nil, errors.New("no result")
  51. }
  52. // initSum 初始化计算所有随机项权重总和
  53. func (w *WeightRand) intWeightSum() {
  54. if w.weightList == nil {
  55. return
  56. }
  57. for _, v := range w.weightList {
  58. w.sum += v.GetWeight()
  59. }
  60. }
  61. // -----------基本随机函数----------------
  62. var globalRand = prand.New(prand.NewSource(time.Now().UnixNano() / int64(time.Now().Minute()))) //基本伪随机
  63. // PseudoRandRange 范围伪随机
  64. // seed:伪随机种子, <=0:使用默认随机种子
  65. func PseudoRandRange(seed int64, min, max int64) (int64, error) {
  66. if min > max {
  67. return 0, errors.New("min <= max")
  68. }
  69. if min == max {
  70. return min, nil
  71. }
  72. r, err := PseudoRand(seed, max-min)
  73. if err != nil {
  74. return 0, err
  75. }
  76. return r + min, nil
  77. }
  78. // PseudoRand 伪随机
  79. // seed:伪随机种子, <=0:使用默认随机种子
  80. func PseudoRand(seed int64, max int64) (int64, error) {
  81. if max <= 0 {
  82. return 0, nil
  83. }
  84. var r *prand.Rand
  85. if seed <= 0 {
  86. r = prand.New(prand.NewSource(seed))
  87. } else {
  88. r = globalRand
  89. }
  90. return r.Int63n(max), nil
  91. }
  92. // RandRangeFloat 范围随机
  93. // min/max 必须为 [0~1] 的浮点数
  94. func RandRangeFloat(min, max float64) (float64, error) {
  95. if min > max {
  96. return 0, errors.New("min <= max")
  97. }
  98. if min == max {
  99. return min, nil
  100. }
  101. if max > 1 || min < 0 {
  102. return 0, errors.New("min/max 必须为 [0~1] 的浮点数")
  103. }
  104. b := 10000.0
  105. r, err := Rand(int64((max - min) * b))
  106. if err != nil {
  107. return 0, err
  108. }
  109. return float64(r)/b + min, nil
  110. }
  111. // RandRange 范围随机
  112. func RandRange(min, max int64) (int64, error) {
  113. if min > max {
  114. return 0, errors.New("min <= max")
  115. }
  116. if min == max {
  117. return min, nil
  118. }
  119. r, err := Rand(max - min)
  120. if err != nil {
  121. return 0, err
  122. }
  123. return r + min, nil
  124. }
  125. // Rand 随机
  126. func Rand(max int64) (int64, error) {
  127. if max <= 0 {
  128. return 0, nil
  129. }
  130. var bigRandNum *big.Int
  131. var err error
  132. var bigSum = big.NewInt(max)
  133. if bigRandNum, err = rand.Int(rand.Reader, bigSum); err != nil {
  134. return 0, err
  135. }
  136. return bigRandNum.Int64(), nil
  137. }
  138. // RandByWeight 根据某权重判断是否命中
  139. // weight 随机权重, >=1 直接命中
  140. func RandByWeight(weight float64) bool {
  141. if weight <= 0 {
  142. return false
  143. }
  144. if weight >= 1.0 {
  145. return true
  146. }
  147. w := int64(weight * 1000.0) //归置到0~1000
  148. r, _ := RandRange(0, 1000)
  149. return r < w
  150. }

  1. package utils
  2. import "testing"
  3. // tWeightItem WeightItem
  4. type tWeightItem struct {
  5. Weight int64
  6. Value string
  7. }
  8. // GetWeight 当前 Item 权重
  9. func (w *tWeightItem) GetWeight() int64 {
  10. return w.Weight
  11. }
  12. func TestRand(t *testing.T) {
  13. weightItems := []WeightItem{
  14. &tWeightItem{Weight: 1, Value: "1"},
  15. &tWeightItem{Weight: 1, Value: "2"},
  16. &tWeightItem{Weight: 2, Value: "3"},
  17. }
  18. rand := NewWeightRand(weightItems)
  19. for i := 0; i < 5; i++ {
  20. if v, err := rand.Rand(); err != nil {
  21. t.Errorf("rand:%#v-err:%#v", v, err)
  22. } else {
  23. t.Logf("rand:%#v-err:%#v", v, err)
  24. }
  25. }
  26. }
ft_authoradmin  ft_create_time2017-08-18 10:50
 ft_update_time2017-10-29 14:42