github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/go.mongodb.org/mongo-driver/internal/randutil/rand/rng.go (about) 1 // Copied from https://cs.opensource.google/go/x/exp/+/24438e51023af3bfc1db8aed43c1342817e8cfcd:rand/rng.go 2 3 // Copyright 2017 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 package rand 8 9 import ( 10 "encoding/binary" 11 "io" 12 "math/bits" 13 ) 14 15 // PCGSource is an implementation of a 64-bit permuted congruential 16 // generator as defined in 17 // 18 // PCG: A Family of Simple Fast Space-Efficient Statistically Good 19 // Algorithms for Random Number Generation 20 // Melissa E. O’Neill, Harvey Mudd College 21 // http://www.pcg-random.org/pdf/toms-oneill-pcg-family-v1.02.pdf 22 // 23 // The generator here is the congruential generator PCG XSL RR 128/64 (LCG) 24 // as found in the software available at http://www.pcg-random.org/. 25 // It has period 2^128 with 128 bits of state, producing 64-bit values. 26 // Is state is represented by two uint64 words. 27 type PCGSource struct { 28 low uint64 29 high uint64 30 } 31 32 const ( 33 maxUint32 = (1 << 32) - 1 34 35 multiplier = 47026247687942121848144207491837523525 36 mulHigh = multiplier >> 64 37 mulLow = multiplier & maxUint64 38 39 increment = 117397592171526113268558934119004209487 40 incHigh = increment >> 64 41 incLow = increment & maxUint64 42 43 // TODO: Use these? 44 initializer = 245720598905631564143578724636268694099 45 initHigh = initializer >> 64 46 initLow = initializer & maxUint64 47 ) 48 49 // Seed uses the provided seed value to initialize the generator to a deterministic state. 50 func (pcg *PCGSource) Seed(seed uint64) { 51 pcg.low = seed 52 pcg.high = seed // TODO: What is right? 53 } 54 55 // Uint64 returns a pseudo-random 64-bit unsigned integer as a uint64. 56 func (pcg *PCGSource) Uint64() uint64 { 57 pcg.multiply() 58 pcg.add() 59 // XOR high and low 64 bits together and rotate right by high 6 bits of state. 60 return bits.RotateLeft64(pcg.high^pcg.low, -int(pcg.high>>58)) 61 } 62 63 func (pcg *PCGSource) add() { 64 var carry uint64 65 pcg.low, carry = Add64(pcg.low, incLow, 0) 66 pcg.high, _ = Add64(pcg.high, incHigh, carry) 67 } 68 69 func (pcg *PCGSource) multiply() { 70 hi, lo := Mul64(pcg.low, mulLow) 71 hi += pcg.high * mulLow 72 hi += pcg.low * mulHigh 73 pcg.low = lo 74 pcg.high = hi 75 } 76 77 // MarshalBinary returns the binary representation of the current state of the generator. 78 func (pcg *PCGSource) MarshalBinary() ([]byte, error) { 79 var buf [16]byte 80 binary.BigEndian.PutUint64(buf[:8], pcg.high) 81 binary.BigEndian.PutUint64(buf[8:], pcg.low) 82 return buf[:], nil 83 } 84 85 // UnmarshalBinary sets the state of the generator to the state represented in data. 86 func (pcg *PCGSource) UnmarshalBinary(data []byte) error { 87 if len(data) < 16 { 88 return io.ErrUnexpectedEOF 89 } 90 pcg.low = binary.BigEndian.Uint64(data[8:]) 91 pcg.high = binary.BigEndian.Uint64(data[:8]) 92 return nil 93 }