github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/perf/fastrand/pcg.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package fastrand 6 7 import "math/bits" 8 9 // https://numpy.org/devdocs/reference/random/upgrading-pcg64.html 10 // https://github.com/imneme/pcg-cpp/commit/871d0494ee9c9a7b7c43f753e3d8ca47c26f8005 11 12 // NewPCG returns a new PCG generator seeded with the given values. 13 func NewPCG(seed1, seed2 uint64) *Rand { 14 return &Rand{ 15 src: &pcgSource{seed1, seed2}, 16 } 17 } 18 19 // A pcgSource is a PCG generator with 128 bits of internal state. 20 // A zero pcgSource is equivalent to pcgSource{0, 0}. 21 type pcgSource struct { 22 hi uint64 23 lo uint64 24 } 25 26 func (p *pcgSource) next() (hi, lo uint64) { 27 // https://github.com/imneme/pcg-cpp/blob/428802d1a5/include/pcg_random.hpp#L161 28 // 29 // Numpy's pcgSource multiplies by the 64-bit value cheapMul 30 // instead of the 128-bit value used here and in the official pcgSource code. 31 // This does not seem worthwhile, at least for Go: not having any high 32 // bits in the multiplier reduces the effect of low bits on the highest bits, 33 // and it only saves 1 multiply out of 3. 34 // (On 32-bit systems, it saves 1 out of 6, since Mul64 is doing 4.) 35 const ( 36 mulHi = 2549297995355413924 37 mulLo = 4865540595714422341 38 incHi = 6364136223846793005 39 incLo = 1442695040888963407 40 ) 41 42 // state = state * mul + inc 43 hi, lo = bits.Mul64(p.lo, mulLo) 44 hi += p.hi*mulLo + p.lo*mulHi 45 lo, c := bits.Add64(lo, incLo, 0) 46 hi, _ = bits.Add64(hi, incHi, c) 47 p.lo = lo 48 p.hi = hi 49 return hi, lo 50 } 51 52 // Uint64 return a uniformly-distributed random uint64 value. 53 func (p *pcgSource) Uint64() uint64 { 54 hi, lo := p.next() 55 56 // XSL-RR would be 57 // hi, lo := p.next() 58 // return bits.RotateLeft64(lo^hi, -int(hi>>58)) 59 // but Numpy uses DXSM and O'Neill suggests doing the same. 60 // See https://github.com/golang/go/issues/21835#issuecomment-739065688 61 // and following comments. 62 63 // DXSM "double xorshift multiply" 64 // https://github.com/imneme/pcg-cpp/blob/428802d1a5/include/pcg_random.hpp#L1015 65 66 // https://github.com/imneme/pcg-cpp/blob/428802d1a5/include/pcg_random.hpp#L176 67 const cheapMul = 0xda942042e4dd58b5 68 hi ^= hi >> 32 69 hi *= cheapMul 70 hi ^= hi >> 48 71 hi *= (lo | 1) 72 return hi 73 }