All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.it.unimi.dsi.util.XorRShR128PlusRandomGenerator Maven / Gradle / Ivy

Go to download

The DSI utilities are a mish mash of classes accumulated during the last ten years in projects developed at the DSI (Dipartimento di Scienze dell'Informazione, i.e., Information Sciences Department), now DI (Dipartimento di Informatica, i.e., Informatics Department), of the Universita` degli Studi di Milano.

There is a newer version: 2.7.3
Show newest version
package it.unimi.dsi.util;

/*		 
 * DSI utilities
 *
 * Copyright (C) 2013-2016 Sebastiano Vigna 
 *
 *  This library is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU Lesser General Public License as published by the Free
 *  Software Foundation; either version 3 of the License, or (at your option)
 *  any later version.
 *
 *  This library is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 *  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 *  for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, see .
 *
 */


import it.unimi.dsi.Util;
import it.unimi.dsi.fastutil.HashCommon;
import it.unimi.dsi.logging.ProgressLogger;

import java.util.Random;

import org.apache.commons.math3.random.AbstractRandomGenerator;
import org.apache.commons.math3.random.RandomGenerator;

/** An unbelievably fast, top-quality {@linkplain RandomGenerator pseudorandom number generator} that
 * returns the sum of consecutive outputs of a Marsaglia Xorshift generator (described in “Xorshift RNGs”, Journal of
 * Statistical Software, 8:1−6, 2003) with 128 bits of state. 
 * 
 * 

More details can be found in my paper “Further scramblings * of Marsaglia's xorshift generators”, 2015, and * on the xorshift*/xorshift+ * generators and the PRNG shootout page. * The basic idea is taken from Mutsuo Saito and Makuto Matsumoto's * XSadd generator, which * is however based on 32-bit shifts and fails several statistical tests when reversed. * *

Note that this is * not a cryptographic-strength pseudorandom number generator, but its quality is * preposterously higher than {@link Random}'s, and its cycle length is * 2128 − 1, which is more than enough for any single-thread application. * *

By using the supplied {@link #jump()} method it is possible to generate non-overlapping long sequences * for parallel computations. This class provides also a {@link #split()} method to support recursive parallel computations, in the spirit of * Java 8's SplittableRandom. * * @see it.unimi.dsi.util * @see Random * @see XorShift128PlusRandom */ public class XorRShR128PlusRandomGenerator extends AbstractRandomGenerator { /** The internal state of the algorithm. */ private long s0, s1; /** Creates a new generator seeded using {@link Util#randomSeed()}. */ public XorRShR128PlusRandomGenerator() { this( Util.randomSeed() ); } /** Creates a new generator using a given seed. * * @param seed a nonzero seed for the generator (if zero, the generator will be seeded with -1). */ public XorRShR128PlusRandomGenerator( final long seed ) { setSeed( seed ); } @Override public long nextLong() { long s1 = this.s0; long s0 = this.s1; final long result = s0 + s1; s1 ^= s0; s0 = Long.rotateLeft(s0, 55) ^ s1 ^ s1 << 14; s1 = Long.rotateLeft(s1, 36); this.s0 = s0; this.s1 = s1; return result; } @Override public int nextInt() { return (int)nextLong(); } @Override public int nextInt( final int n ) { return (int)nextLong( n ); } /** Returns a pseudorandom uniformly distributed {@code long} value * between 0 (inclusive) and the specified value (exclusive), drawn from * this random number generator's sequence. The algorithm used to generate * the value guarantees that the result is uniform, provided that the * sequence of 64-bit values produced by this generator is. * * @param n the positive bound on the random number to be returned. * @return the next pseudorandom {@code long} value between {@code 0} (inclusive) and {@code n} (exclusive). */ public long nextLong( final long n ) { if ( n <= 0 ) throw new IllegalArgumentException(); // No special provision for n power of two: all our bits are good. for(;;) { final long bits = nextLong() >>> 1; final long value = bits % n; if ( bits - value + ( n - 1 ) >= 0 ) return value; } } @Override public double nextDouble() { return Double.longBitsToDouble( nextLong() >>> 12 | 0x3FFL << 52 ) - 1.0; } @Override public float nextFloat() { return Float.intBitsToFloat( (int)( nextLong() >>> 41 ) | 0x3F8 << 20 ) - 1.0f; } @Override public boolean nextBoolean() { return nextLong() < 0; } @Override public void nextBytes( final byte[] bytes ) { int i = bytes.length, n = 0; while( i != 0 ) { n = Math.min( i, 8 ); for ( long bits = nextLong(); n-- != 0; bits >>= 8 ) bytes[ --i ] = (byte)bits; } } private static final long JUMP[] = { 0xbeac0467eba5facbL, 0xd86b048b86aa9922L }; /** The the jump function for this generator. It is equivalent to 264 * calls to {@link #nextLong()}; it can be used to generate 264 * non-overlapping subsequences for parallel computations. */ public void jump() { long s0 = 0; long s1 = 0; for(int i = 0; i < JUMP.length; i++) for(int b = 0; b < 64; b++) { if ( ( JUMP[i] & 1L << b ) != 0 ) { s0 ^= this.s0; s1 ^= this.s1; } nextLong(); } this.s0 = s0; this.s1 = s1; } /** * Returns a new instance that shares no mutable state * with this instance. The sequence generated by the new instance * depends deterministically from the state of this instance, * but the possibility that the sequence generated by this * instance and by the new instance overlap is negligible. * * @return the new instance. */ public XorRShR128PlusRandomGenerator split() { final XorRShR128PlusRandomGenerator split = new XorRShR128PlusRandomGenerator(); split.s0 = HashCommon.murmurHash3( s0 ); split.s1 = HashCommon.murmurHash3( s1 ); return split; } /** Sets the seed of this generator. * *

The argument will be used to seed a {@link SplitMix64RandomGenerator}, whose output * will in turn be used to seed this generator. This approach makes “warmup” unnecessary, * and makes the possibility of starting from a state * with a large fraction of bits set to zero astronomically small. * * @param seed a nonzero seed for this generator. */ @Override public void setSeed( final long seed ) { final SplitMix64RandomGenerator r = new SplitMix64RandomGenerator( seed ); s0 = r.nextLong(); s1 = r.nextLong(); } /** Sets the state of this generator. * *

The internal state of the generator will be reset, and the state array filled with the provided array. * * @param state an array of 2 longs; at least one must be nonzero. */ public void setState( final long[] state ) { if ( state.length != 2 ) throw new IllegalArgumentException( "The argument array contains " + state.length + " longs instead of " + 2 ); s0 = state[ 0 ]; s1 = state[ 1 ]; } public static void main( String[] arg ) { long n = Long.parseLong( arg[ 0 ] ); long x = 0; ProgressLogger pl = new ProgressLogger(); XorRShR128PlusRandomGenerator r = new XorRShR128PlusRandomGenerator(0); for( int k = 10; k-- != 0; ) { pl.start( "Measuring..." ); for ( long i = n; i-- != 0; ) x ^= r.nextLong(); pl.done( n ); if ( x == 0 ) System.out.println( x ); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy