001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.math3.random; 018 019import java.io.Serializable; 020 021import org.apache.commons.math3.util.FastMath; 022 023 024/** This abstract class implements the WELL class of pseudo-random number generator 025 * from François Panneton, Pierre L'Ecuyer and Makoto Matsumoto. 026 027 * <p>This generator is described in a paper by François Panneton, 028 * Pierre L'Ecuyer and Makoto Matsumoto <a 029 * href="http://www.iro.umontreal.ca/~lecuyer/myftp/papers/wellrng.pdf">Improved 030 * Long-Period Generators Based on Linear Recurrences Modulo 2</a> ACM 031 * Transactions on Mathematical Software, 32, 1 (2006). The errata for the paper 032 * are in <a href="http://www.iro.umontreal.ca/~lecuyer/myftp/papers/wellrng-errata.txt">wellrng-errata.txt</a>.</p> 033 034 * @see <a href="http://www.iro.umontreal.ca/~panneton/WELLRNG.html">WELL Random number generator</a> 035 * @since 2.2 036 037 */ 038public abstract class AbstractWell extends BitsStreamGenerator implements Serializable { 039 040 /** Serializable version identifier. */ 041 private static final long serialVersionUID = -817701723016583596L; 042 043 /** Current index in the bytes pool. */ 044 protected int index; 045 046 /** Bytes pool. */ 047 protected final int[] v; 048 049 /** Index indirection table giving for each index its predecessor taking table size into account. */ 050 protected final int[] iRm1; 051 052 /** Index indirection table giving for each index its second predecessor taking table size into account. */ 053 protected final int[] iRm2; 054 055 /** Index indirection table giving for each index the value index + m1 taking table size into account. */ 056 protected final int[] i1; 057 058 /** Index indirection table giving for each index the value index + m2 taking table size into account. */ 059 protected final int[] i2; 060 061 /** Index indirection table giving for each index the value index + m3 taking table size into account. */ 062 protected final int[] i3; 063 064 /** Creates a new random number generator. 065 * <p>The instance is initialized using the current time plus the 066 * system identity hash code of this instance as the seed.</p> 067 * @param k number of bits in the pool (not necessarily a multiple of 32) 068 * @param m1 first parameter of the algorithm 069 * @param m2 second parameter of the algorithm 070 * @param m3 third parameter of the algorithm 071 */ 072 protected AbstractWell(final int k, final int m1, final int m2, final int m3) { 073 this(k, m1, m2, m3, null); 074 } 075 076 /** Creates a new random number generator using a single int seed. 077 * @param k number of bits in the pool (not necessarily a multiple of 32) 078 * @param m1 first parameter of the algorithm 079 * @param m2 second parameter of the algorithm 080 * @param m3 third parameter of the algorithm 081 * @param seed the initial seed (32 bits integer) 082 */ 083 protected AbstractWell(final int k, final int m1, final int m2, final int m3, final int seed) { 084 this(k, m1, m2, m3, new int[] { seed }); 085 } 086 087 /** Creates a new random number generator using an int array seed. 088 * @param k number of bits in the pool (not necessarily a multiple of 32) 089 * @param m1 first parameter of the algorithm 090 * @param m2 second parameter of the algorithm 091 * @param m3 third parameter of the algorithm 092 * @param seed the initial seed (32 bits integers array), if null 093 * the seed of the generator will be related to the current time 094 */ 095 protected AbstractWell(final int k, final int m1, final int m2, final int m3, final int[] seed) { 096 097 // the bits pool contains k bits, k = r w - p where r is the number 098 // of w bits blocks, w is the block size (always 32 in the original paper) 099 // and p is the number of unused bits in the last block 100 final int w = 32; 101 final int r = (k + w - 1) / w; 102 this.v = new int[r]; 103 this.index = 0; 104 105 // precompute indirection index tables. These tables are used for optimizing access 106 // they allow saving computations like "(j + r - 2) % r" with costly modulo operations 107 iRm1 = new int[r]; 108 iRm2 = new int[r]; 109 i1 = new int[r]; 110 i2 = new int[r]; 111 i3 = new int[r]; 112 for (int j = 0; j < r; ++j) { 113 iRm1[j] = (j + r - 1) % r; 114 iRm2[j] = (j + r - 2) % r; 115 i1[j] = (j + m1) % r; 116 i2[j] = (j + m2) % r; 117 i3[j] = (j + m3) % r; 118 } 119 120 // initialize the pool content 121 setSeed(seed); 122 123 } 124 125 /** Creates a new random number generator using a single long seed. 126 * @param k number of bits in the pool (not necessarily a multiple of 32) 127 * @param m1 first parameter of the algorithm 128 * @param m2 second parameter of the algorithm 129 * @param m3 third parameter of the algorithm 130 * @param seed the initial seed (64 bits integer) 131 */ 132 protected AbstractWell(final int k, final int m1, final int m2, final int m3, final long seed) { 133 this(k, m1, m2, m3, new int[] { (int) (seed >>> 32), (int) (seed & 0xffffffffl) }); 134 } 135 136 /** Reinitialize the generator as if just built with the given int seed. 137 * <p>The state of the generator is exactly the same as a new 138 * generator built with the same seed.</p> 139 * @param seed the initial seed (32 bits integer) 140 */ 141 @Override 142 public void setSeed(final int seed) { 143 setSeed(new int[] { seed }); 144 } 145 146 /** Reinitialize the generator as if just built with the given int array seed. 147 * <p>The state of the generator is exactly the same as a new 148 * generator built with the same seed.</p> 149 * @param seed the initial seed (32 bits integers array). If null 150 * the seed of the generator will be the system time plus the system identity 151 * hash code of the instance. 152 */ 153 @Override 154 public void setSeed(final int[] seed) { 155 if (seed == null) { 156 setSeed(System.currentTimeMillis() + System.identityHashCode(this)); 157 return; 158 } 159 160 System.arraycopy(seed, 0, v, 0, FastMath.min(seed.length, v.length)); 161 162 if (seed.length < v.length) { 163 for (int i = seed.length; i < v.length; ++i) { 164 final long l = v[i - seed.length]; 165 v[i] = (int) ((1812433253l * (l ^ (l >> 30)) + i) & 0xffffffffL); 166 } 167 } 168 169 index = 0; 170 clear(); // Clear normal deviate cache 171 } 172 173 /** Reinitialize the generator as if just built with the given long seed. 174 * <p>The state of the generator is exactly the same as a new 175 * generator built with the same seed.</p> 176 * @param seed the initial seed (64 bits integer) 177 */ 178 @Override 179 public void setSeed(final long seed) { 180 setSeed(new int[] { (int) (seed >>> 32), (int) (seed & 0xffffffffl) }); 181 } 182 183 /** {@inheritDoc} */ 184 @Override 185 protected abstract int next(final int bits); 186 187}