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 */ 017 018package org.apache.commons.rng.core.source32; 019 020import org.apache.commons.rng.core.util.NumberFactory; 021import org.apache.commons.rng.core.BaseProvider; 022 023/** 024 * Base class for all implementations that provide an {@code int}-based 025 * source randomness. 026 */ 027public abstract class IntProvider 028 extends BaseProvider 029 implements RandomIntSource { 030 031 /** 032 * Provides a bit source for booleans. 033 * 034 * <p>A cached value from a call to {@link #nextInt()}. 035 */ 036 private int booleanSource; // Initialised as 0 037 038 /** 039 * The bit mask of the boolean source to obtain the boolean bit. 040 * 041 * <p>The bit mask contains a single bit set. This begins at the least 042 * significant bit and is gradually shifted upwards until overflow to zero. 043 * 044 * <p>When zero a new boolean source should be created and the mask set to the 045 * least significant bit (i.e. 1). 046 */ 047 private int booleanBitMask; // Initialised as 0 048 049 /** 050 * Creates a new instance. 051 */ 052 public IntProvider() { 053 super(); 054 } 055 056 /** 057 * Creates a new instance copying the state from the source. 058 * 059 * <p>This provides base functionality to allow a generator to create a copy, for example 060 * for use in the {@link org.apache.commons.rng.JumpableUniformRandomProvider 061 * JumpableUniformRandomProvider} interface. 062 * 063 * @param source Source to copy. 064 * @since 1.3 065 */ 066 protected IntProvider(IntProvider source) { 067 booleanSource = source.booleanSource; 068 booleanBitMask = source.booleanBitMask; 069 } 070 071 /** 072 * Reset the cached state used in the default implementation of {@link #nextBoolean()}. 073 * 074 * <p>This should be used when the state is no longer valid, for example after a jump 075 * performed for the {@link org.apache.commons.rng.JumpableUniformRandomProvider 076 * JumpableUniformRandomProvider} interface.</p> 077 * 078 * @since 1.3 079 */ 080 protected void resetCachedState() { 081 booleanSource = 0; 082 booleanBitMask = 0; 083 } 084 085 /** {@inheritDoc} */ 086 @Override 087 protected byte[] getStateInternal() { 088 final int[] state = {booleanSource, 089 booleanBitMask}; 090 return composeStateInternal(NumberFactory.makeByteArray(state), 091 super.getStateInternal()); 092 } 093 094 /** {@inheritDoc} */ 095 @Override 096 protected void setStateInternal(byte[] s) { 097 final byte[][] c = splitStateInternal(s, 8); 098 final int[] state = NumberFactory.makeIntArray(c[0]); 099 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}