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.source64; 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 a {@code long}-based 025 * source randomness. 026 */ 027public abstract class LongProvider 028 extends BaseProvider 029 implements RandomLongSource { 030 031 /** 032 * Provides a bit source for booleans. 033 * 034 * <p>A cached value from a call to {@link #nextLong()}. 035 */ 036 private long 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 long booleanBitMask; // Initialised as 0 048 049 /** 050 * Provides a source for ints. 051 * 052 * <p>A cached value from a call to {@link #nextLong()}. 053 */ 054 private long intSource; 055 056 /** Flag to indicate an int source has been cached. */ 057 private boolean cachedIntSource; // Initialised as false 058 059 /** 060 * Creates a new instance. 061 */ 062 public LongProvider() { 063 super(); 064 } 065 066 /** 067 * Creates a new instance copying the state from the source. 068 * 069 * <p>This provides base functionality to allow a generator to create a copy, for example 070 * for use in the {@link org.apache.commons.rng.JumpableUniformRandomProvider 071 * JumpableUniformRandomProvider} interface. 072 * 073 * @param source Source to copy. 074 * @since 1.3 075 */ 076 protected LongProvider(LongProvider source) { 077 booleanSource = source.booleanSource; 078 booleanBitMask = source.booleanBitMask; 079 intSource = source.intSource; 080 cachedIntSource = source.cachedIntSource; 081 } 082 083 /** 084 * Reset the cached state used in the default implementation of {@link #nextBoolean()} 085 * and {@link #nextInt()}. 086 * 087 * <p>This should be used when the state is no longer valid, for example after a jump 088 * performed for the {@link org.apache.commons.rng.JumpableUniformRandomProvider 089 * JumpableUniformRandomProvider} interface.</p> 090 * 091 * @since 1.3 092 */ 093 protected void resetCachedState() { 094 booleanSource = 0L; 095 booleanBitMask = 0L; 096 intSource = 0L; 097 cachedIntSource = false; 098 } 099 100 /** {@inheritDoc} */ 101 @Override 102 protected byte[] getStateInternal() { 103 // Pack the boolean inefficiently as a long 104 final long[] state = {booleanSource, 105 booleanBitMask, 106 intSource, 107 cachedIntSource ? 1 : 0 }; 108 return composeStateInternal(NumberFactory.makeByteArray(state), 109 super.getStateInternal()); 110 } 111 112 /** {@inheritDoc} */ 113 @Override 114 protected void setStateInternal(byte[] s) { 115 final byte[][] c = splitStateInternal(s, 32); 116 final long[] state = NumberFactory.makeLongArray(c[0]); 117 booleanSource = state[0]; 118 booleanBitMask = state[1]; 119 intSource = state[2]; 120 // Non-zero is true 121 cachedIntSource = state[3] != 0; 122 super.setStateInternal(c[1]); 123 } 124 125 /** {@inheritDoc} */ 126 @Override 127 public long nextLong() { 128 return next(); 129 } 130 131 /** {@inheritDoc} */ 132 @Override 133 public int nextInt() { 134 // Directly store and use the long value as a source for ints 135 if (cachedIntSource) { 136 // Consume the cache value 137 cachedIntSource = false; 138 // Return the lower 32 bits 139 return NumberFactory.extractLo(intSource); 140 } 141 // Fill the cache 142 cachedIntSource = true; 143 intSource = nextLong(); 144 // Return the upper 32 bits 145 return NumberFactory.extractHi(intSource); 146 } 147 148 /** {@inheritDoc} */ 149 @Override 150 public double nextDouble() { 151 return NumberFactory.makeDouble(nextLong()); 152 } 153 154 /** {@inheritDoc} */ 155 @Override 156 public boolean nextBoolean() { 157 // Shift up. This will eventually overflow and become zero. 158 booleanBitMask <<= 1; 159 // The mask will either contain a single bit or none. 160 if (booleanBitMask == 0) { 161 // Set the least significant bit 162 booleanBitMask = 1; 163 // Get the next value 164 booleanSource = nextLong(); 165 } 166 // Return if the bit is set 167 return (booleanSource & booleanBitMask) != 0; 168 } 169 170 /** {@inheritDoc} */ 171 @Override 172 public float nextFloat() { 173 return NumberFactory.makeFloat(nextInt()); 174 } 175 176 /** {@inheritDoc} */ 177 @Override 178 public void nextBytes(byte[] bytes) { 179 nextBytesFill(this, bytes, 0, bytes.length); 180 } 181 182 /** {@inheritDoc} */ 183 @Override 184 public void nextBytes(byte[] bytes, 185 int start, 186 int len) { 187 checkIndex(0, bytes.length - 1, start); 188 checkIndex(0, bytes.length - start, len); 189 190 nextBytesFill(this, bytes, start, len); 191 } 192 193 /** 194 * Generates random bytes and places them into a user-supplied array. 195 * 196 * <p> 197 * The array is filled with bytes extracted from random {@code long} values. 198 * This implies that the number of random bytes generated may be larger than 199 * the length of the byte array. 200 * </p> 201 * 202 * @param source Source of randomness. 203 * @param bytes Array in which to put the generated bytes. Cannot be null. 204 * @param start Index at which to start inserting the generated bytes. 205 * @param len Number of bytes to insert. 206 */ 207 static void nextBytesFill(RandomLongSource source, 208 byte[] bytes, 209 int start, 210 int len) { 211 int index = start; // Index of first insertion. 212 213 // Index of first insertion plus multiple of 8 part of length 214 // (i.e. length with 3 least significant bits unset). 215 final int indexLoopLimit = index + (len & 0x7ffffff8); 216 217 // Start filling in the byte array, 8 bytes at a time. 218 while (index < indexLoopLimit) { 219 final long random = source.next(); 220 bytes[index++] = (byte) random; 221 bytes[index++] = (byte) (random >>> 8); 222 bytes[index++] = (byte) (random >>> 16); 223 bytes[index++] = (byte) (random >>> 24); 224 bytes[index++] = (byte) (random >>> 32); 225 bytes[index++] = (byte) (random >>> 40); 226 bytes[index++] = (byte) (random >>> 48); 227 bytes[index++] = (byte) (random >>> 56); 228 } 229 230 final int indexLimit = start + len; // Index of last insertion + 1. 231 232 // Fill in the remaining bytes. 233 if (index < indexLimit) { 234 long random = source.next(); 235 while (true) { 236 bytes[index++] = (byte) random; 237 if (index < indexLimit) { 238 random >>>= 8; 239 } else { 240 break; 241 } 242 } 243 } 244 } 245}