View Javadoc
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.source64;
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 a {@code long}-based
25   * source randomness.
26   */
27  public abstract class LongProvider
28      extends BaseProvider
29      implements RandomLongSource {
30  
31      /**
32       * Provides a bit source for booleans.
33       *
34       * <p>A cached value from a call to {@link #nextLong()}.
35       */
36      private long 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 long booleanBitMask; // Initialised as 0
48  
49      /**
50       * Provides a source for ints.
51       *
52       * <p>A cached value from a call to {@link #nextLong()}.
53       */
54      private long intSource;
55  
56      /** Flag to indicate an int source has been cached. */
57      private boolean cachedIntSource; // Initialised as false
58  
59      /**
60       * Creates a new instance.
61       */
62      public LongProvider() {
63          super();
64      }
65  
66      /**
67       * Creates a new instance copying the state from the source.
68       *
69       * <p>This provides base functionality to allow a generator to create a copy, for example
70       * for use in the {@link org.apache.commons.rng.JumpableUniformRandomProvider
71       * JumpableUniformRandomProvider} interface.
72       *
73       * @param source Source to copy.
74       * @since 1.3
75       */
76      protected LongProvider(LongProvider source) {
77          booleanSource = source.booleanSource;
78          booleanBitMask = source.booleanBitMask;
79          intSource = source.intSource;
80          cachedIntSource = source.cachedIntSource;
81      }
82  
83      /**
84       * Reset the cached state used in the default implementation of {@link #nextBoolean()}
85       * and {@link #nextInt()}.
86       *
87       * <p>This should be used when the state is no longer valid, for example after a jump
88       * performed for the {@link org.apache.commons.rng.JumpableUniformRandomProvider
89       * JumpableUniformRandomProvider} interface.</p>
90       *
91       * @since 1.3
92       */
93      protected void resetCachedState() {
94          booleanSource = 0L;
95          booleanBitMask = 0L;
96          intSource = 0L;
97          cachedIntSource = false;
98      }
99  
100     /** {@inheritDoc} */
101     @Override
102     protected byte[] getStateInternal() {
103         // Pack the boolean inefficiently as a long
104         final long[] state = new long[] {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 }