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  package org.apache.commons.math.random;
18  
19  import org.apache.commons.math.MathRuntimeException;
20  
21  /** Base class for random number generators that generates bits streams.
22  
23   * @version $Revision: 796552 $ $Date: 2009-07-21 17:51:30 -0400 (Tue, 21 Jul 2009) $
24   * @since 2.0
25  
26   */
27  public abstract class BitsStreamGenerator implements RandomGenerator {
28  
29      /** Next gaussian. */
30      private double nextGaussian;
31  
32      /** Creates a new random number generator.
33       */
34      public BitsStreamGenerator() {
35          nextGaussian = Double.NaN;
36      }
37  
38      /** {@inheritDoc} */
39      public abstract void setSeed(int seed);
40  
41      /** {@inheritDoc} */
42      public abstract void setSeed(int[] seed);
43  
44      /** {@inheritDoc} */
45      public abstract void setSeed(long seed);
46  
47      /** Generate next pseudorandom number.
48       * <p>This method is the core generation algorithm. It is used by all the
49       * public generation methods for the various primitive types {@link
50       * #nextBoolean()}, {@link #nextBytes(byte[])}, {@link #nextDouble()},
51       * {@link #nextFloat()}, {@link #nextGaussian()}, {@link #nextInt()},
52       * {@link #next(int)} and {@link #nextLong()}.</p>
53       * @param bits number of random bits to produce
54       * @return random bits generated
55       */
56      protected abstract int next(int bits);
57  
58      /** {@inheritDoc} */
59      public boolean nextBoolean() {
60          return next(1) != 0;
61      }
62  
63      /** {@inheritDoc} */
64      public void nextBytes(byte[] bytes) {
65          int i = 0;
66          final int iEnd = bytes.length - 3;
67          while (i < iEnd) {
68              final int random = next(32);
69              bytes[i]     = (byte) (random & 0xff);
70              bytes[i + 1] = (byte) ((random >>  8) & 0xff);
71              bytes[i + 2] = (byte) ((random >> 16) & 0xff);
72              bytes[i + 3] = (byte) ((random >> 24) & 0xff);
73              i += 4;
74          }
75          int random = next(32);
76          while (i < bytes.length) {
77              bytes[i++] = (byte) (random & 0xff); 
78              random     = random >> 8;
79          }
80      }
81  
82      /** {@inheritDoc} */
83      public double nextDouble() {
84          final long high = ((long) next(26)) << 26;
85          final int  low  = next(26);
86          return (high | low) * 0x1.0p-52d;
87      }
88  
89      /** {@inheritDoc} */
90      public float nextFloat() {
91          return next(23) * 0x1.0p-23f;
92      }
93  
94      /** {@inheritDoc} */
95      public double nextGaussian() {
96  
97          final double random;
98          if (Double.isNaN(nextGaussian)) {
99              // generate a new pair of gaussian numbers
100             final double x = nextDouble();
101             final double y = nextDouble();
102             final double alpha = 2 * Math.PI * x;
103             final double r      = Math.sqrt(-2 * Math.log(y));
104             random       = r * Math.cos(alpha);
105             nextGaussian = r * Math.sin(alpha);
106         } else {
107             // use the second element of the pair already generated
108             random = nextGaussian;
109             nextGaussian = Double.NaN;
110         }
111 
112         return random;
113 
114     }
115 
116     /** {@inheritDoc} */
117     public int nextInt() {
118         return next(32);
119     }
120 
121     /** {@inheritDoc} */
122     public int nextInt(int n) throws IllegalArgumentException {
123 
124         if (n < 1) {
125             throw MathRuntimeException.createIllegalArgumentException(
126                   "upper bound must be positive ({0})", n);
127         }
128 
129         // find bit mask for n
130         int mask = n;
131         mask |= mask >> 1;
132         mask |= mask >> 2;
133         mask |= mask >> 4;
134         mask |= mask >> 8;
135         mask |= mask >> 16;
136 
137         while (true) {
138             final int random = next(32) & mask;
139             if (random < n) {
140                 return random;
141             }
142         }
143 
144     }
145 
146     /** {@inheritDoc} */
147     public long nextLong() {
148         final long high  = ((long) next(32)) << 32;
149         final long  low  = ((long) next(32)) & 0xffffffffL;
150         return high | low;
151     }
152 
153 }