Ai
1 Star 0 Fork 0

nggs/micro

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
random.go 8.71 KB
一键复制 编辑 原始数据 按行查看 历史
李文建 提交于 2020-04-17 15:39 +08:00 . 1.持续完善actor,app
package random
import (
crank "crypto/rand"
"encoding/binary"
"fmt"
"log"
"math"
"math/rand"
"sync"
"time"
)
const letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
letterIndexBits = 6 // 6 bits to represent a letter index
letterIndexMask = 1<<letterIndexBits - 1 // All 1-bits, as many as letterIndexBits
letterIndexMax = 63 / letterIndexBits // # of letter indices fitting in 63 bits
)
// 生成一定长度的随机字节数组
func ByteArray(size int) []byte {
diceLock.Lock()
defer diceLock.Unlock()
b := make([]byte, size)
for i, cache, remain := size-1, dice.Int63(), letterIndexMax; i >= 0; {
if remain == 0 {
cache, remain = dice.Int63(), letterIndexMax
}
if idx := int(cache & letterIndexMask); idx < len(letterBytes) {
b[i] = letterBytes[idx]
i--
}
cache >>= letterIndexBits
remain--
}
return b
}
// 生成一定长度的随机字符串
func String(size int) string {
return string(ByteArray(size))
}
// rand不是线程/协程安全,必须加锁
var dice = rand.New(newCryptoSeededSource())
var diceLock = &sync.Mutex{}
func newCryptoSeededSource() rand.Source {
var seed int64
err := binary.Read(crank.Reader, binary.BigEndian, &seed)
if err != nil {
log.Panicf("newCryptoSeededSource binary.Read fail, %s", err)
}
return rand.NewSource(seed)
}
func NormalDistributionRandom(mu float64, sigma float64) float64 {
return dice.NormFloat64()*sigma + mu
}
func TimeDuration(min time.Duration, max time.Duration) time.Duration {
if min == max {
return min
}
diceLock.Lock()
defer diceLock.Unlock()
if min < max {
return min + time.Duration(dice.Int63n(int64(max-min)))
}
return max + time.Duration(dice.Int63n(int64(min-max)))
}
func Int(min int, max int) int {
if min == max {
return min
}
diceLock.Lock()
defer diceLock.Unlock()
if min < max {
return min + dice.Intn(max-min)
}
return max + dice.Intn(min-max)
}
func Int32(min int32, max int32) int32 {
if min == max {
return min
}
diceLock.Lock()
defer diceLock.Unlock()
if min < max {
return min + dice.Int31n(max-min)
}
return max + dice.Int31n(min-max)
}
func Int64(min int64, max int64) int64 {
if min == max {
return min
}
diceLock.Lock()
defer diceLock.Unlock()
if min < max {
return min + dice.Int63n(max-min)
}
return max + dice.Int63n(min-max)
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IDiscreteDistributionCandidate 按概率分布随机骰子候选项接口
type IDiscreteDistributionCandidate interface {
Context() interface{}
Weight() int
Key() interface{}
}
// DiscreteDistributionCandidate 按概率分布随机骰子候选项代理类
type DiscreteDistributionCandidate struct {
context interface{}
weight int
key interface{}
}
type DiscreteDistributionCandidateBuildFunc = func(context interface{}) (int, interface{})
// NewDiscreteDistributionCandidate 构造权重随机骰子候选项
func NewDiscreteDistributionCandidate(
context interface{},
buildFunc DiscreteDistributionCandidateBuildFunc) *DiscreteDistributionCandidate {
weight, key := buildFunc(context)
c := &DiscreteDistributionCandidate{
context: context,
weight: weight,
key: key,
}
return c
}
// Context 返回按概率分布随机骰子候选项的上下文
func (c DiscreteDistributionCandidate) Context() interface{} {
return c.context
}
// Weight 返回候选项的权重
func (c DiscreteDistributionCandidate) Weight() int {
return c.weight
}
// Key 返回候选项的键值
func (c DiscreteDistributionCandidate) Key() interface{} {
return c.key
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
type IDiscreteDistributionDice interface {
Append(c IDiscreteDistributionCandidate) IDiscreteDistributionDice
Build() (err error)
Roll() (ctx interface{}, err error)
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// discreteDistributionDice 按概率分布随机骰子
type discreteDistributionDice struct {
candidates []IDiscreteDistributionCandidate
totalWeight int
weightRange []int
}
// NewDiscreteDistributionDice 构造一个按概率分布随机骰子
func NewDiscreteDistributionDice() IDiscreteDistributionDice {
d := &discreteDistributionDice{}
return d
}
// Append 添加候选项
func (d *discreteDistributionDice) Append(c IDiscreteDistributionCandidate) IDiscreteDistributionDice {
w := c.Weight()
if w > 0 {
d.totalWeight += w
d.candidates = append(d.candidates, c)
}
return d
}
// Build 构建
func (d *discreteDistributionDice) Build() (err error) {
if len(d.candidates) == 0 {
return ErrCandidateIsEmpty
}
d.weightRange = make([]int, len(d.candidates)+1)
for i := range d.candidates {
var weightRange int
for j := 0; j < i+1; j++ {
weightRange += d.candidates[j].Weight()
}
d.weightRange[i+1] = weightRange
}
return
}
// Roll 随机一个候选项
func (d discreteDistributionDice) Roll() (ctx interface{}, err error) {
if len(d.candidates) == 0 {
return nil, ErrCandidateIsEmpty
}
seed := Int(0, d.totalWeight)
for i := range d.candidates {
if seed >= d.weightRange[i] && seed < d.weightRange[i+1] {
return d.candidates[i].Context(), nil
}
}
return nil, ErrNotHit
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// GenRandomRatesInt 根据整型权重值生成浮点权重值
func GenRandomRatesInt(weights map[int]int) (rates map[int]float64, err error) {
if len(weights) == 0 {
err = ErrWeightsIsEmpty
return
}
var totalWeight int
for _, w := range weights {
if w <= 0 {
continue
}
totalWeight += w
}
if totalWeight <= 0 {
err = ErrTotalWeightsIsZero
return
}
rates = map[int]float64{}
for i, weight := range weights {
if weight <= 0 {
continue
}
rates[i] = float64(weight) / float64(totalWeight)
}
return
}
// NormalDiscreteDistributionInt 键值是int的正态权重随机
func NormalDiscreteDistributionInt(fixRates map[int]float64, randomRates map[int]float64) (map[int]float64, int, error) {
if len(fixRates) == 0 {
return nil, 0, ErrRawRatesIsEmpty
}
if len(randomRates) == 0 {
if randomRates == nil {
randomRates = map[int]float64{}
}
for k, rate := range fixRates {
randomRates[k] = NormalDistributionRandom(1.0/rate, 1.0/rate/3.0)
}
}
var minRate = math.MaxFloat64
var hit int
for i, rate := range randomRates {
if rate < minRate {
minRate = rate
hit = i
}
}
for k, _ := range randomRates {
randomRates[k] -= minRate
}
randomRates[hit] = NormalDistributionRandom(1.0/fixRates[hit], 1.0/fixRates[hit]/3.0)
return randomRates, hit, nil
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// normalDiscreteDistributionIntDice 键值是int的正态权重随机随机骰子
type normalDiscreteDistributionIntDice struct {
candidates map[int]IDiscreteDistributionCandidate
// 原始权重值,不会发生变动
fixRates map[int]float64
// 随机权重值,每次随机都会发生变化
randomRates map[int]float64
// 锁
lock sync.Mutex
}
// NewNormalDiscreteDistributionIntDice 构造一个键值是int的正态权重随机骰子
func NewNormalDiscreteDistributionIntDice() IDiscreteDistributionDice {
d := &normalDiscreteDistributionIntDice{
candidates: map[int]IDiscreteDistributionCandidate{},
fixRates: map[int]float64{},
randomRates: map[int]float64{},
}
return d
}
// Append 添加候选项
func (d *normalDiscreteDistributionIntDice) Append(c IDiscreteDistributionCandidate) IDiscreteDistributionDice {
w := c.Weight()
if w > 0 {
d.candidates[c.Key().(int)] = c
}
return d
}
// Build 构建
func (d *normalDiscreteDistributionIntDice) Build() (err error) {
if len(d.candidates) == 0 {
return ErrCandidateIsEmpty
}
var weights = map[int]int{}
var totalWeight int
for _, c := range d.candidates {
w := c.Weight()
weights[c.Key().(int)] = w
totalWeight += w
}
if totalWeight <= 0 {
err = ErrTotalWeightsIsZero
return
}
for k, weight := range weights {
d.fixRates[k] = float64(weight) / float64(totalWeight)
}
for k, rate := range d.fixRates {
d.randomRates[k] = NormalDistributionRandom(1.0/rate, 1.0/rate/3.0)
}
return
}
// Roll 随机一个候选项
func (d *normalDiscreteDistributionIntDice) Roll() (ctx interface{}, err error) {
d.lock.Lock()
defer d.lock.Unlock()
if len(d.candidates) == 0 {
return nil, ErrCandidateIsEmpty
}
var hit int
d.randomRates, hit, err = NormalDiscreteDistributionInt(d.fixRates, d.randomRates)
if err != nil {
return nil, fmt.Errorf("%w", err)
}
return d.candidates[hit].Context(), nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/nggs/micro.git
git@gitee.com:nggs/micro.git
nggs
micro
micro
bac99dff65eb

搜索帮助