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.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 }