github.com/CAFxX/fastrand@v0.1.0/xoshiro256.go (about)

     1  package fastrand
     2  
     3  import "math/bits"
     4  
     5  // Xoshiro256StarStar implements the Xoshiro256** PRNG.
     6  //
     7  // This generator is not safe for concurrent use by multiple goroutines.
     8  // The zero value is not a valid state: Seed() must be called
     9  // before generating random numbers.
    10  type Xoshiro256StarStar struct {
    11  	state [4]uint64
    12  }
    13  
    14  // Uint64 returns a random uint64.
    15  //
    16  // This function is not safe for concurrent use by multiple goroutines.
    17  func (r *Xoshiro256StarStar) Uint64() uint64 {
    18  	// TODO: this function has, unfortunately, an inline cost of 81.
    19  	// It would be ideal, especially for the sharded variant, if it was inlineable.
    20  
    21  	result := bits.RotateLeft64(r.state[1]*5, 7) * 9
    22  
    23  	t := r.state[1] << 17
    24  
    25  	r.state[2] ^= r.state[0]
    26  	r.state[3] ^= r.state[1]
    27  	r.state[1] ^= r.state[2]
    28  	r.state[0] ^= r.state[3]
    29  
    30  	r.state[2] ^= t
    31  
    32  	r.state[3] = bits.RotateLeft64(r.state[3], 45)
    33  
    34  	return result
    35  }
    36  
    37  // Seed sets the seed for the generator.
    38  //
    39  // The seed should not be all zeros (i.e. at least one of the four
    40  // uint64 should be non-zero).
    41  // This function is not safe for concurrent use by multiple goroutines.
    42  func (r *Xoshiro256StarStar) Seed(s0, s1, s2, s3 uint64) {
    43  	r.state[0] = s0
    44  	r.state[1] = s1
    45  	r.state[2] = s2
    46  	r.state[3] = s3
    47  }
    48  
    49  func (r *Xoshiro256StarStar) safeSeed() {
    50  retry:
    51  	a, b, c, d := Seed(), Seed(), Seed(), Seed()
    52  	if a == 0 && b == 0 && c == 0 && d == 0 {
    53  		goto retry
    54  	}
    55  	r.Seed(a, b, c, d)
    56  }