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      /** {@inheritDoc} */
50      @Override
51      protected byte[] getStateInternal() {
52          final int[] state = new int[] { booleanSource,
53                                          booleanBitMask };
54          return composeStateInternal(super.getStateInternal(),
55                                      NumberFactory.makeByteArray(state));
56      }
57  
58      /** {@inheritDoc} */
59      @Override
60      protected void setStateInternal(byte[] s) {
61          final byte[][] c = splitStateInternal(s, 8);
62          final int[] state = NumberFactory.makeIntArray(c[0]);
63          booleanSource  = state[0];
64          booleanBitMask = state[1];
65          super.setStateInternal(c[1]);
66      }
67  
68      /** {@inheritDoc} */
69      @Override
70      public int nextInt() {
71          return next();
72      }
73  
74      /** {@inheritDoc} */
75      @Override
76      public boolean nextBoolean() {
77          // Shift up. This will eventually overflow and become zero.
78          booleanBitMask <<= 1;
79          // The mask will either contain a single bit or none.
80          if (booleanBitMask == 0) {
81              // Set the least significant bit
82              booleanBitMask = 1;
83              // Get the next value
84              booleanSource = nextInt();
85          }
86          // Return if the bit is set
87          return (booleanSource & booleanBitMask) != 0;
88      }
89  
90      /** {@inheritDoc} */
91      @Override
92      public double nextDouble() {
93          return NumberFactory.makeDouble(nextInt(), nextInt());
94      }
95  
96      /** {@inheritDoc} */
97      @Override
98      public float nextFloat() {
99          return NumberFactory.makeFloat(nextInt());
100     }
101 
102     /** {@inheritDoc} */
103     @Override
104     public long nextLong() {
105         return NumberFactory.makeLong(nextInt(), nextInt());
106     }
107 
108     /** {@inheritDoc} */
109     @Override
110     public void nextBytes(byte[] bytes) {
111         nextBytesFill(this, bytes, 0, bytes.length);
112     }
113 
114     /** {@inheritDoc} */
115     @Override
116     public void nextBytes(byte[] bytes,
117                           int start,
118                           int len) {
119         checkIndex(0, bytes.length - 1, start);
120         checkIndex(0, bytes.length - start, len);
121 
122         nextBytesFill(this, bytes, start, len);
123     }
124 
125     /**
126      * Generates random bytes and places them into a user-supplied array.
127      *
128      * <p>
129      * The array is filled with bytes extracted from random {@code int} values.
130      * This implies that the number of random bytes generated may be larger than
131      * the length of the byte array.
132      * </p>
133      *
134      * @param source Source of randomness.
135      * @param bytes Array in which to put the generated bytes. Cannot be null.
136      * @param start Index at which to start inserting the generated bytes.
137      * @param len Number of bytes to insert.
138      */
139     static void nextBytesFill(RandomIntSource source,
140                               byte[] bytes,
141                               int start,
142                               int len) {
143         int index = start; // Index of first insertion.
144 
145         // Index of first insertion plus multiple of 4 part of length
146         // (i.e. length with 2 least significant bits unset).
147         final int indexLoopLimit = index + (len & 0x7ffffffc);
148 
149         // Start filling in the byte array, 4 bytes at a time.
150         while (index < indexLoopLimit) {
151             final int random = source.next();
152             bytes[index++] = (byte) random;
153             bytes[index++] = (byte) (random >>> 8);
154             bytes[index++] = (byte) (random >>> 16);
155             bytes[index++] = (byte) (random >>> 24);
156         }
157 
158         final int indexLimit = start + len; // Index of last insertion + 1.
159 
160         // Fill in the remaining bytes.
161         if (index < indexLimit) {
162             int random = source.next();
163             while (true) {
164                 bytes[index++] = (byte) random;
165                 if (index < indexLimit) {
166                     random >>>= 8;
167                 } else {
168                     break;
169                 }
170             }
171         }
172     }
173 }