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.rng;
18
19 import java.util.stream.DoubleStream;
20 import java.util.stream.IntStream;
21 import java.util.stream.LongStream;
22
23 /**
24 * Applies to generators of random number sequences that follow a uniform
25 * distribution.
26 *
27 * @since 1.0
28 */
29 public interface UniformRandomProvider {
30 /**
31 * Generates {@code byte} values and places them into a user-supplied array.
32 *
33 * <p>The number of random bytes produced is equal to the length of the byte array.
34 *
35 * @param bytes Byte array in which to put the random bytes.
36 * Cannot be {@code null}.
37 */
38 default void nextBytes(byte[] bytes) {
39 UniformRandomProviderSupport.nextBytes(this, bytes, 0, bytes.length);
40 }
41
42 /**
43 * Generates {@code byte} values and places them into a user-supplied array.
44 *
45 * <p>The array is filled with bytes extracted from random integers.
46 * This implies that the number of random bytes generated may be larger than
47 * the length of the byte array.
48 *
49 * @param bytes Array in which to put the generated bytes.
50 * Cannot be {@code null}.
51 * @param start Index at which to start inserting the generated bytes.
52 * @param len Number of bytes to insert.
53 * @throws IndexOutOfBoundsException if {@code start < 0} or
54 * {@code start >= bytes.length}.
55 * @throws IndexOutOfBoundsException if {@code len < 0} or
56 * {@code len > bytes.length - start}.
57 */
58 default void nextBytes(byte[] bytes, int start, int len) {
59 UniformRandomProviderSupport.validateFromIndexSize(start, len, bytes.length);
60 UniformRandomProviderSupport.nextBytes(this, bytes, start, len);
61 }
62
63 /**
64 * Generates an {@code int} value.
65 *
66 * @return the next random value.
67 */
68 default int nextInt() {
69 return (int) (nextLong() >>> 32);
70 }
71
72 /**
73 * Generates an {@code int} value between 0 (inclusive) and the
74 * specified value (exclusive).
75 *
76 * @param n Bound on the random number to be returned. Must be positive.
77 * @return a random {@code int} value between 0 (inclusive) and {@code n}
78 * (exclusive).
79 * @throws IllegalArgumentException if {@code n} is not above zero.
80 */
81 default int nextInt(int n) {
82 UniformRandomProviderSupport.validateUpperBound(n);
83 return UniformRandomProviderSupport.nextInt(this, n);
84 }
85
86 /**
87 * Generates an {@code int} value between the specified {@code origin} (inclusive) and
88 * the specified {@code bound} (exclusive).
89 *
90 * @param origin Lower bound on the random number to be returned.
91 * @param bound Upper bound (exclusive) on the random number to be returned.
92 * @return a random {@code int} value between {@code origin} (inclusive) and
93 * {@code bound} (exclusive).
94 * @throws IllegalArgumentException if {@code origin} is greater than or equal to
95 * {@code bound}.
96 * @since 1.5
97 */
98 default int nextInt(int origin, int bound) {
99 UniformRandomProviderSupport.validateRange(origin, bound);
100 return UniformRandomProviderSupport.nextInt(this, origin, bound);
101 }
102
103 /**
104 * Generates a {@code long} value.
105 *
106 * @return the next random value.
107 */
108 long nextLong();
109
110 /**
111 * Generates a {@code long} value between 0 (inclusive) and the specified
112 * value (exclusive).
113 *
114 * @param n Bound on the random number to be returned. Must be positive.
115 * @return a random {@code long} value between 0 (inclusive) and {@code n}
116 * (exclusive).
117 * @throws IllegalArgumentException if {@code n} is not greater than 0.
118 */
119 default long nextLong(long n) {
120 UniformRandomProviderSupport.validateUpperBound(n);
121 return UniformRandomProviderSupport.nextLong(this, n);
122 }
123
124 /**
125 * Generates a {@code long} value between the specified {@code origin} (inclusive) and
126 * the specified {@code bound} (exclusive).
127 *
128 * @param origin Lower bound on the random number to be returned.
129 * @param bound Upper bound (exclusive) on the random number to be returned.
130 * @return a random {@code long} value between {@code origin} (inclusive) and
131 * {@code bound} (exclusive).
132 * @throws IllegalArgumentException if {@code origin} is greater than or equal to
133 * {@code bound}.
134 * @since 1.5
135 */
136 default long nextLong(long origin, long bound) {
137 UniformRandomProviderSupport.validateRange(origin, bound);
138 return UniformRandomProviderSupport.nextLong(this, origin, bound);
139 }
140
141 /**
142 * Generates a {@code boolean} value.
143 *
144 * @return the next random value.
145 */
146 default boolean nextBoolean() {
147 return nextInt() < 0;
148 }
149
150 /**
151 * Generates a {@code float} value between 0 (inclusive) and 1 (exclusive).
152 *
153 * @return the next random value between 0 (inclusive) and 1 (exclusive).
154 */
155 default float nextFloat() {
156 return (nextInt() >>> 8) * 0x1.0p-24f;
157 }
158
159 /**
160 * Generates a {@code float} value between 0 (inclusive) and the
161 * specified {@code bound} (exclusive).
162 *
163 * @param bound Upper bound (exclusive) on the random number to be returned.
164 * @return a random {@code float} value between 0 (inclusive) and {@code bound}
165 * (exclusive).
166 * @throws IllegalArgumentException if {@code bound} is not both finite and greater than 0.
167 * @since 1.5
168 */
169 default float nextFloat(float bound) {
170 UniformRandomProviderSupport.validateUpperBound(bound);
171 return UniformRandomProviderSupport.nextFloat(this, bound);
172 }
173
174 /**
175 * Generates a {@code float} value between the specified {@code origin} (inclusive)
176 * and the specified {@code bound} (exclusive).
177 *
178 * @param origin Lower bound on the random number to be returned.
179 * @param bound Upper bound (exclusive) on the random number to be returned.
180 * @return a random {@code float} value between {@code origin} (inclusive) and
181 * {@code bound} (exclusive).
182 * @throws IllegalArgumentException if {@code origin} is not finite, or {@code bound}
183 * is not finite, or {@code origin} is greater than or equal to {@code bound}.
184 * @since 1.5
185 */
186 default float nextFloat(float origin, float bound) {
187 UniformRandomProviderSupport.validateRange(origin, bound);
188 return UniformRandomProviderSupport.nextFloat(this, origin, bound);
189 }
190
191 /**
192 * Generates a {@code double} value between 0 (inclusive) and 1 (exclusive).
193 *
194 * @return the next random value between 0 (inclusive) and 1 (exclusive).
195 */
196 default double nextDouble() {
197 return (nextLong() >>> 11) * 0x1.0p-53;
198 }
199
200 /**
201 * Generates a {@code double} value between 0 (inclusive) and the
202 * specified {@code bound} (exclusive).
203 *
204 * @param bound Upper bound (exclusive) on the random number to be returned.
205 * @return a random {@code double} value between 0 (inclusive) and {@code bound}
206 * (exclusive).
207 * @throws IllegalArgumentException if {@code bound} is not both finite and greater than 0.
208 * @since 1.5
209 */
210 default double nextDouble(double bound) {
211 UniformRandomProviderSupport.validateUpperBound(bound);
212 return UniformRandomProviderSupport.nextDouble(this, bound);
213 }
214
215 /**
216 * Generates a {@code double} value between the specified {@code origin} (inclusive)
217 * and the specified {@code bound} (exclusive).
218 *
219 * @param origin Lower bound on the random number to be returned.
220 * @param bound Upper bound (exclusive) on the random number to be returned.
221 * @return a random {@code double} value between {@code origin} (inclusive) and
222 * {@code bound} (exclusive).
223 * @throws IllegalArgumentException if {@code origin} is not finite, or {@code bound}
224 * is not finite, or {@code origin} is greater than or equal to {@code bound}.
225 * @since 1.5
226 */
227 default double nextDouble(double origin, double bound) {
228 UniformRandomProviderSupport.validateRange(origin, bound);
229 return UniformRandomProviderSupport.nextDouble(this, origin, bound);
230 }
231
232 /**
233 * Returns an effectively unlimited stream of {@code int} values.
234 *
235 * @return a stream of random {@code int} values.
236 * @since 1.5
237 */
238 default IntStream ints() {
239 return IntStream.generate(this::nextInt).sequential();
240 }
241
242 /**
243 * Returns an effectively unlimited stream of {@code int} values between the specified
244 * {@code origin} (inclusive) and the specified {@code bound} (exclusive).
245 *
246 * @param origin Lower bound on the random number to be returned.
247 * @param bound Upper bound (exclusive) on the random number to be returned.
248 * @return a stream of random values between the specified {@code origin} (inclusive)
249 * and the specified {@code bound} (exclusive).
250 * @throws IllegalArgumentException if {@code origin} is greater than or equal to
251 * {@code bound}.
252 * @since 1.5
253 */
254 default IntStream ints(int origin, int bound) {
255 UniformRandomProviderSupport.validateRange(origin, bound);
256 return IntStream.generate(() -> nextInt(origin, bound)).sequential();
257 }
258
259 /**
260 * Returns a stream producing the given {@code streamSize} number of {@code int}
261 * values.
262 *
263 * @param streamSize Number of values to generate.
264 * @return a stream of random {@code int} values; the stream is limited to the given
265 * {@code streamSize}.
266 * @throws IllegalArgumentException if {@code streamSize} is negative.
267 * @since 1.5
268 */
269 default IntStream ints(long streamSize) {
270 UniformRandomProviderSupport.validateStreamSize(streamSize);
271 return ints().limit(streamSize);
272 }
273
274 /**
275 * Returns a stream producing the given {@code streamSize} number of {@code int}
276 * values between the specified {@code origin} (inclusive) and the specified
277 * {@code bound} (exclusive).
278 *
279 * @param streamSize Number of values to generate.
280 * @param origin Lower bound on the random number to be returned.
281 * @param bound Upper bound (exclusive) on the random number to be returned.
282 * @return a stream of random values between the specified {@code origin} (inclusive)
283 * and the specified {@code bound} (exclusive); the stream is limited to the given
284 * {@code streamSize}.
285 * @throws IllegalArgumentException if {@code streamSize} is negative, or if
286 * {@code origin} is greater than or equal to {@code bound}.
287 * @since 1.5
288 */
289 default IntStream ints(long streamSize, int origin, int bound) {
290 UniformRandomProviderSupport.validateStreamSize(streamSize);
291 UniformRandomProviderSupport.validateRange(origin, bound);
292 return ints(origin, bound).limit(streamSize);
293 }
294
295 /**
296 * Returns an effectively unlimited stream of {@code long} values.
297 *
298 * @return a stream of random {@code long} values.
299 * @since 1.5
300 */
301 default LongStream longs() {
302 return LongStream.generate(this::nextLong).sequential();
303 }
304
305 /**
306 * Returns an effectively unlimited stream of {@code long} values between the
307 * specified {@code origin} (inclusive) and the specified {@code bound} (exclusive).
308 *
309 * @param origin Lower bound on the random number to be returned.
310 * @param bound Upper bound (exclusive) on the random number to be returned.
311 * @return a stream of random values between the specified {@code origin} (inclusive)
312 * and the specified {@code bound} (exclusive).
313 * @throws IllegalArgumentException if {@code origin} is greater than or equal to
314 * {@code bound}.
315 * @since 1.5
316 */
317 default LongStream longs(long origin, long bound) {
318 UniformRandomProviderSupport.validateRange(origin, bound);
319 return LongStream.generate(() -> nextLong(origin, bound)).sequential();
320 }
321
322 /**
323 * Returns a stream producing the given {@code streamSize} number of {@code long}
324 * values.
325 *
326 * @param streamSize Number of values to generate.
327 * @return a stream of random {@code long} values; the stream is limited to the given
328 * {@code streamSize}.
329 * @throws IllegalArgumentException if {@code streamSize} is negative.
330 * @since 1.5
331 */
332 default LongStream longs(long streamSize) {
333 UniformRandomProviderSupport.validateStreamSize(streamSize);
334 return longs().limit(streamSize);
335 }
336
337 /**
338 * Returns a stream producing the given {@code streamSize} number of {@code long}
339 * values between the specified {@code origin} (inclusive) and the specified
340 * {@code bound} (exclusive).
341 *
342 * @param streamSize Number of values to generate.
343 * @param origin Lower bound on the random number to be returned.
344 * @param bound Upper bound (exclusive) on the random number to be returned.
345 * @return a stream of random values between the specified {@code origin} (inclusive)
346 * and the specified {@code bound} (exclusive); the stream is limited to the given
347 * {@code streamSize}.
348 * @throws IllegalArgumentException if {@code streamSize} is negative, or if
349 * {@code origin} is greater than or equal to {@code bound}.
350 * @since 1.5
351 */
352 default LongStream longs(long streamSize, long origin, long bound) {
353 UniformRandomProviderSupport.validateStreamSize(streamSize);
354 UniformRandomProviderSupport.validateRange(origin, bound);
355 return longs(origin, bound).limit(streamSize);
356 }
357
358 /**
359 * Returns an effectively unlimited stream of {@code double} values between 0
360 * (inclusive) and 1 (exclusive).
361 *
362 * @return a stream of random values between 0 (inclusive) and 1 (exclusive).
363 * @since 1.5
364 */
365 default DoubleStream doubles() {
366 return DoubleStream.generate(this::nextDouble).sequential();
367 }
368
369 /**
370 * Returns an effectively unlimited stream of {@code double} values between the
371 * specified {@code origin} (inclusive) and the specified {@code bound} (exclusive).
372 *
373 * @param origin Lower bound on the random number to be returned.
374 * @param bound Upper bound (exclusive) on the random number to be returned.
375 * @return a stream of random values between the specified {@code origin} (inclusive)
376 * and the specified {@code bound} (exclusive).
377 * @throws IllegalArgumentException if {@code origin} is not finite, or {@code bound}
378 * is not finite, or {@code origin} is greater than or equal to {@code bound}.
379 * @since 1.5
380 */
381 default DoubleStream doubles(double origin, double bound) {
382 UniformRandomProviderSupport.validateRange(origin, bound);
383 return DoubleStream.generate(() -> nextDouble(origin, bound)).sequential();
384 }
385
386 /**
387 * Returns a stream producing the given {@code streamSize} number of {@code double}
388 * values between 0 (inclusive) and 1 (exclusive).
389 *
390 * @param streamSize Number of values to generate.
391 * @return a stream of random values between 0 (inclusive) and 1 (exclusive);
392 * the stream is limited to the given {@code streamSize}.
393 * @throws IllegalArgumentException if {@code streamSize} is negative.
394 * @since 1.5
395 */
396 default DoubleStream doubles(long streamSize) {
397 UniformRandomProviderSupport.validateStreamSize(streamSize);
398 return doubles().limit(streamSize);
399 }
400
401 /**
402 * Returns a stream producing the given {@code streamSize} number of {@code double}
403 * values between the specified {@code origin} (inclusive) and the specified
404 * {@code bound} (exclusive).
405 *
406 * @param streamSize Number of values to generate.
407 * @param origin Lower bound on the random number to be returned.
408 * @param bound Upper bound (exclusive) on the random number to be returned.
409 * @return a stream of random values between the specified {@code origin} (inclusive)
410 * and the specified {@code bound} (exclusive); the stream is limited to the given
411 * {@code streamSize}.
412 * @throws IllegalArgumentException if {@code streamSize} is negative, or if
413 * {@code origin} is not finite, or {@code bound} is not finite, or {@code origin} is
414 * greater than or equal to {@code bound}.
415 * @since 1.5
416 */
417 default DoubleStream doubles(long streamSize, double origin, double bound) {
418 UniformRandomProviderSupport.validateStreamSize(streamSize);
419 UniformRandomProviderSupport.validateRange(origin, bound);
420 return doubles(origin, bound).limit(streamSize);
421 }
422 }