-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrng.go
More file actions
155 lines (132 loc) · 3.28 KB
/
rng.go
File metadata and controls
155 lines (132 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Copyright (c) 2022-present, Serhat Şevki Dinçer.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Package rng provides a compact, fast, [sponge]-based, lockless and hard-to-predict
// global random number generator. It also provides [Prng] for deterministic behavior.
// Neither is suitable for cryptographic applications because of 128 bits capacity.
//
// [sponge]: https://en.wikipedia.org/wiki/Sponge_function
package rng
import (
"unsafe"
sb "github.com/jfcg/sixb/v2"
)
var global Prng
//go:nosplit
//go:norace
func init() {
global.Randomize()
}
// Get 64 bits from global rng. Note that Get() % n is not uniform, use [Modn](n) instead.
//
//go:norace
func Get() uint64 {
return global.Get()
}
// One returns a uniformly distributed number in interval [0, 1) from global rng.
//
//go:norace
func One() float64 {
return global.One()
}
// OneR returns a uniformly distributed number in interval (0, 1] from global rng.
//
//go:norace
func OneR() float64 {
return global.OneR()
}
// Two returns a uniformly distributed number in interval [-1, 1) from global rng.
//
//go:norace
func Two() float64 {
return global.Two()
}
// TwoR returns a uniformly distributed number in interval (-1, 1] from global rng.
//
//go:norace
func TwoR() float64 {
return global.TwoR()
}
// Tri1 returns a number from symmetric triangular distribution in interval (0, 1) from global rng.
//
//go:norace
func Tri1() float64 {
return global.Tri1()
}
// Tri2 returns a number from symmetric triangular distribution in interval (-1, 1) from global rng.
//
//go:norace
func Tri2() float64 {
return global.Tri2()
}
// Exp returns an exponentially distributed number (mean=1) from global rng.
//
//go:norace
func Exp() float64 {
return global.Exp()
}
// Normal returns two independent & normally distributed
// numbers (mean=0, variance=1) from global rng.
//
//go:norace
func Normal() (float64, float64) {
return global.Normal()
}
// Modn returns a uniformly selected integer in 0,..,n-1
// from global rng for n ≥ 2, and returns n-1 for n < 2.
//
//go:norace
func Modn(n uint64) uint64 {
return global.Modn(n)
}
// Permute fills lu with a uniformly selected permutation of
// integers 0,..,len(lu)-1 from global rng, up to 2^32 entries.
//
//go:norace
func Permute(lu []uint32) {
global.Permute(lu)
}
// Fill buf with bytes from global rng.
//
//go:norace
func Fill(buf []byte) {
global.Fill(buf)
}
// put u into p.
func put[T sb.Integer](p *Prng, u T) {
p.Put(uint64(u))
}
// putStr inserts a pointer and a string into p.
//
//go:nosplit
func putStr(p *Prng, s string) {
lb := sb.Bytes(s)
if len(lb) <= 0 {
return
}
put(p, sb.PtrToInt(&lb[0]))
lu := sb.Slice[uint64](lb)
for _, u := range lu { // put 8 bytes at a time
p.Put(u)
}
if r := len(lu) << 3; r < len(lb) { // put 1 to 7 remaining bytes
var u [8]byte
copy(u[:], lb[r:])
p.Put(*(*uint64)(unsafe.Pointer(&u)))
}
}
// putList inserts a pointer and sum of strings into p.
//
//go:nosplit
func putList(p *Prng, ls []string) {
if len(ls) <= 0 {
return
}
put(p, sb.PtrToInt(&ls[0]))
sum := sb.Bytes(ls[0])
for i := 1; i < len(ls); i++ {
sum = append(sum, ls[i]...)
}
putStr(p, sb.String(sum))
}