Files
kjv_api/internal/kjv/mt.go
T
2026-10-26 20:30:43 -07:00

87 lines
1.6 KiB
Go

package kjv
// MT19937 seeded with init_by_array from one integer, and a choice made by
// rejection sampling over its bits, so the verse of the day for any given date
// never changes.
type mtRandom struct {
mt [624]uint32
idx int
}
func newMTRandom(seed uint32) *mtRandom {
r := &mtRandom{}
r.initGenrand(19650218)
key := []uint32{seed}
i, j := 1, 0
k := max(624, len(key))
for ; k > 0; k-- {
r.mt[i] = (r.mt[i] ^ ((r.mt[i-1] ^ (r.mt[i-1] >> 30)) * 1664525)) + key[j] + uint32(j)
i++
j++
if i >= 624 {
r.mt[0] = r.mt[623]
i = 1
}
if j >= len(key) {
j = 0
}
}
for k = 623; k > 0; k-- {
r.mt[i] = (r.mt[i] ^ ((r.mt[i-1] ^ (r.mt[i-1] >> 30)) * 1566083941)) - uint32(i)
i++
if i >= 624 {
r.mt[0] = r.mt[623]
i = 1
}
}
r.mt[0] = 0x80000000
r.idx = 624
return r
}
func (r *mtRandom) initGenrand(s uint32) {
r.mt[0] = s
for i := 1; i < 624; i++ {
r.mt[i] = 1812433253*(r.mt[i-1]^(r.mt[i-1]>>30)) + uint32(i)
}
r.idx = 624
}
func (r *mtRandom) next() uint32 {
if r.idx >= 624 {
for k := 0; k < 624; k++ {
y := (r.mt[k] & 0x80000000) | (r.mt[(k+1)%624] & 0x7fffffff)
v := r.mt[(k+397)%624] ^ (y >> 1)
if y&1 != 0 {
v ^= 0x9908b0df
}
r.mt[k] = v
}
r.idx = 0
}
y := r.mt[r.idx]
r.idx++
y ^= y >> 11
y ^= (y << 7) & 0x9d2c5680
y ^= (y << 15) & 0xefc60000
y ^= y >> 18
return y
}
// choiceIndex is random.choice's _randbelow(n) for n < 2**32.
func (r *mtRandom) choiceIndex(n int) int {
if n <= 0 {
return 0
}
k := 0
for v := n; v > 0; v >>= 1 {
k++
}
for {
if x := int(r.next() >> (32 - k)); x < n {
return x
}
}
}