1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.rng.core.source32; 19 20 import org.apache.commons.rng.core.util.NumberFactory; 21 import org.apache.commons.rng.core.BaseProvider; 22 23 /** 24 * Base class for all implementations that provide an {@code int}-based 25 * source randomness. 26 */ 27 public abstract class IntProvider 28 extends BaseProvider 29 implements RandomIntSource { 30 31 /** 32 * Provides a bit source for booleans. 33 * 34 * <p>A cached value from a call to {@link #nextInt()}. 35 */ 36 private int booleanSource; // Initialised as 0 37 38 /** 39 * The bit mask of the boolean source to obtain the boolean bit. 40 * 41 * <p>The bit mask contains a single bit set. This begins at the least 42 * significant bit and is gradually shifted upwards until overflow to zero. 43 * 44 * <p>When zero a new boolean source should be created and the mask set to the 45 * least significant bit (i.e. 1). 46 */ 47 private int booleanBitMask; // Initialised as 0 48 49 /** 50 * Creates a new instance. 51 */ 52 public IntProvider() { 53 super(); 54 } 55 56 /** 57 * Creates a new instance copying the state from the source. 58 * 59 * <p>This provides base functionality to allow a generator to create a copy, for example 60 * for use in the {@link org.apache.commons.rng.JumpableUniformRandomProvider 61 * JumpableUniformRandomProvider} interface. 62 * 63 * @param source Source to copy. 64 * @since 1.3 65 */ 66 protected IntProvider(IntProvider source) { 67 booleanSource = source.booleanSource; 68 booleanBitMask = source.booleanBitMask; 69 } 70 71 /** 72 * Reset the cached state used in the default implementation of {@link #nextBoolean()}. 73 * 74 * <p>This should be used when the state is no longer valid, for example after a jump 75 * performed for the {@link org.apache.commons.rng.JumpableUniformRandomProvider 76 * JumpableUniformRandomProvider} interface.</p> 77 * 78 * @since 1.3 79 */ 80 protected void resetCachedState() { 81 booleanSource = 0; 82 booleanBitMask = 0; 83 } 84 85 /** {@inheritDoc} */ 86 @Override 87 protected byte[] getStateInternal() { 88 final int[] state = new int[] {booleanSource, 89 booleanBitMask}; 90 return composeStateInternal(NumberFactory.makeByteArray(state), 91 super.getStateInternal()); 92 } 93 94 /** {@inheritDoc} */ 95 @Override 96 protected void setStateInternal(byte[] s) { 97 final byte[][] c = splitStateInternal(s, 8); 98 final int[] state = NumberFactory.makeIntArray(c[0]); 99 booleanSource = state[0]; 100 booleanBitMask = state[1]; 101 super.setStateInternal(c[1]); 102 } 103 104 /** {@inheritDoc} */ 105 @Override 106 public int nextInt() { 107 return next(); 108 } 109 110 /** {@inheritDoc} */ 111 @Override 112 public boolean nextBoolean() { 113 // Shift up. This will eventually overflow and become zero. 114 booleanBitMask <<= 1; 115 // The mask will either contain a single bit or none. 116 if (booleanBitMask == 0) { 117 // Set the least significant bit 118 booleanBitMask = 1; 119 // Get the next value 120 booleanSource = nextInt(); 121 } 122 // Return if the bit is set 123 return (booleanSource & booleanBitMask) != 0; 124 } 125 126 /** {@inheritDoc} */ 127 @Override 128 public double nextDouble() { 129 return NumberFactory.makeDouble(nextInt(), nextInt()); 130 } 131 132 /** {@inheritDoc} */ 133 @Override 134 public float nextFloat() { 135 return NumberFactory.makeFloat(nextInt()); 136 } 137 138 /** {@inheritDoc} */ 139 @Override 140 public long nextLong() { 141 return NumberFactory.makeLong(nextInt(), nextInt()); 142 } 143 144 /** {@inheritDoc} */ 145 @Override 146 public void nextBytes(byte[] bytes) { 147 nextBytesFill(this, bytes, 0, bytes.length); 148 } 149 150 /** {@inheritDoc} */ 151 @Override 152 public void nextBytes(byte[] bytes, 153 int start, 154 int len) { 155 checkIndex(0, bytes.length - 1, start); 156 checkIndex(0, bytes.length - start, len); 157 158 nextBytesFill(this, bytes, start, len); 159 } 160 161 /** 162 * Generates random bytes and places them into a user-supplied array. 163 * 164 * <p> 165 * The array is filled with bytes extracted from random {@code int} values. 166 * This implies that the number of random bytes generated may be larger than 167 * the length of the byte array. 168 * </p> 169 * 170 * @param source Source of randomness. 171 * @param bytes Array in which to put the generated bytes. Cannot be null. 172 * @param start Index at which to start inserting the generated bytes. 173 * @param len Number of bytes to insert. 174 */ 175 static void nextBytesFill(RandomIntSource source, 176 byte[] bytes, 177 int start, 178 int len) { 179 int index = start; // Index of first insertion. 180 181 // Index of first insertion plus multiple of 4 part of length 182 // (i.e. length with 2 least significant bits unset). 183 final int indexLoopLimit = index + (len & 0x7ffffffc); 184 185 // Start filling in the byte array, 4 bytes at a time. 186 while (index < indexLoopLimit) { 187 final int random = source.next(); 188 bytes[index++] = (byte) random; 189 bytes[index++] = (byte) (random >>> 8); 190 bytes[index++] = (byte) (random >>> 16); 191 bytes[index++] = (byte) (random >>> 24); 192 } 193 194 final int indexLimit = start + len; // Index of last insertion + 1. 195 196 // Fill in the remaining bytes. 197 if (index < indexLimit) { 198 int random = source.next(); 199 while (true) { 200 bytes[index++] = (byte) random; 201 if (index < indexLimit) { 202 random >>>= 8; 203 } else { 204 break; 205 } 206 } 207 } 208 } 209 }