newrandom/RngSupport.java
author briangoetz
Thu, 23 May 2019 16:45:56 -0400
branchbriangoetz-test-branch
changeset 57369 6d87e9f7a1ec
permissions -rwxr-xr-x
Initial comment in newrandom/
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
57369
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
     1
/*
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
     2
 * Copyright (c) 2013, 2016, 2019, Oracle and/or its affiliates. All rights reserved.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
     3
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
     4
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
     5
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
     6
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
     7
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
     8
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
     9
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    10
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    11
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    12
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    13
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    14
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    15
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    16
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    17
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    18
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    19
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    20
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    21
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    22
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    23
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    24
 */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    25
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    26
// package java.util;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    27
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    28
import java.util.Spliterator;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    29
import java.util.function.Consumer;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    30
import java.util.function.IntConsumer;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    31
import java.util.function.LongConsumer;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    32
import java.util.function.DoubleConsumer;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    33
import java.util.stream.StreamSupport;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    34
import java.util.stream.IntStream;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    35
import java.util.stream.LongStream;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    36
import java.util.stream.DoubleStream;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    37
// import java.util.DoubleZigguratTables;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    38
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    39
/**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    40
 * Low-level utility methods helpful for implementing pseudorandom number generators.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    41
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    42
 * This class is mostly for library writers creating specific implementations of the interface {@link java.util.Rng}.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    43
 *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    44
 * @author  Guy Steele
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    45
 * @author  Doug Lea
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    46
 * @since   1.9
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    47
 */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    48
public class RngSupport {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    49
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    50
    /*
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    51
     * Implementation Overview.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    52
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    53
     * This class provides utility methods and constants frequently
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    54
     * useful in the implentation of pseudorandom number generators
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    55
     * that satisfy the interface {@code java.util.Rng}.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    56
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    57
     * File organization: First some message strings, then the main
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    58
     * public methods, followed by a non-public base spliterator class.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    59
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    60
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    61
    // IllegalArgumentException messages
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    62
    static final String BadSize = "size must be non-negative";
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    63
    static final String BadDistance = "jump distance must be finite, positive, and an exact integer";
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    64
    static final String BadBound = "bound must be positive";
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    65
    static final String BadFloatingBound = "bound must be finite and positive";
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    66
    static final String BadRange = "bound must be greater than origin";
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    67
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    68
    /* ---------------- public methods ---------------- */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    69
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    70
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    71
     * Check a {@code long} proposed stream size for validity.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    72
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    73
     * @param streamSize the proposed stream size
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    74
     * @throws IllegalArgumentException if {@code streamSize} is negative
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    75
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    76
    public static void checkStreamSize(long streamSize) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    77
	if (streamSize < 0L)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    78
            throw new IllegalArgumentException(BadSize);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    79
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    80
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    81
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    82
     * Check a {@code double} proposed jump distance for validity.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    83
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    84
     * @param distance the proposed jump distance
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    85
     * @throws IllegalArgumentException if {@code size} not positive,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    86
     * finite, and an exact integer
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    87
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    88
    public static void checkJumpDistance(double distance) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    89
	if (!(distance > 0.0 && distance < Float.POSITIVE_INFINITY && distance == Math.floor(distance)))
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    90
            throw new IllegalArgumentException(BadDistance);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    91
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    92
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    93
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    94
     * Checks a {@code float} upper bound value for validity.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    95
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    96
     * @param bound the upper bound (exclusive)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    97
     * @throws IllegalArgumentException if {@code bound} is not
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    98
     *         positive and finite
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
    99
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   100
    public static void checkBound(float bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   101
	if (!(bound > 0.0 && bound < Float.POSITIVE_INFINITY))
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   102
            throw new IllegalArgumentException(BadFloatingBound);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   103
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   104
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   105
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   106
     * Checks a {@code double} upper bound value for validity.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   107
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   108
     * @param bound the upper bound (exclusive)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   109
     * @throws IllegalArgumentException if {@code bound} is not
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   110
     *         positive and finite
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   111
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   112
    public static void checkBound(double bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   113
	if (!(bound > 0.0 && bound < Double.POSITIVE_INFINITY))
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   114
            throw new IllegalArgumentException(BadFloatingBound);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   115
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   116
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   117
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   118
     * Checks an {@code int} upper bound value for validity.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   119
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   120
     * @param bound the upper bound (exclusive)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   121
     * @throws IllegalArgumentException if {@code bound} is not positive
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   122
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   123
    public static void checkBound(int bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   124
        if (bound <= 0)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   125
            throw new IllegalArgumentException(BadBound);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   126
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   127
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   128
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   129
     * Checks a {@code long} upper bound value for validity.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   130
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   131
     * @param bound the upper bound (exclusive)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   132
     * @throws IllegalArgumentException if {@code bound} is not positive
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   133
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   134
    public static void checkBound(long bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   135
        if (bound <= 0)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   136
            throw new IllegalArgumentException(BadBound);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   137
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   138
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   139
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   140
     * Checks a {@code float} range for validity.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   141
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   142
     * @param origin the least value (inclusive) in the range
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   143
     * @param bound the upper bound (exclusive) of the range
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   144
     * @throws IllegalArgumentException unless {@code origin} is finite,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   145
     *         {@code bound} is finite, and {@code bound - origin} is finite
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   146
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   147
    public static void checkRange(float origin, float bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   148
        if (!(origin < bound && (bound - origin) < Float.POSITIVE_INFINITY))
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   149
            throw new IllegalArgumentException(BadRange);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   150
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   151
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   152
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   153
     * Checks a {@code double} range for validity.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   154
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   155
     * @param origin the least value (inclusive) in the range
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   156
     * @param bound the upper bound (exclusive) of the range
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   157
     * @throws IllegalArgumentException unless {@code origin} is finite,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   158
     *         {@code bound} is finite, and {@code bound - origin} is finite
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   159
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   160
    public static void checkRange(double origin, double bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   161
        if (!(origin < bound && (bound - origin) < Double.POSITIVE_INFINITY))
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   162
            throw new IllegalArgumentException(BadRange);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   163
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   164
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   165
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   166
     * Checks an {@code int} range for validity.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   167
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   168
     * @param origin the least value that can be returned
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   169
     * @param bound the upper bound (exclusive) for the returned value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   170
     * @throws IllegalArgumentException if {@code origin} is greater than
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   171
     *         or equal to {@code bound}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   172
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   173
    public static void checkRange(int origin, int bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   174
        if (origin >= bound)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   175
            throw new IllegalArgumentException(BadRange);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   176
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   177
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   178
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   179
     * Checks a {@code long} range for validity.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   180
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   181
     * @param origin the least value that can be returned
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   182
     * @param bound the upper bound (exclusive) for the returned value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   183
     * @throws IllegalArgumentException if {@code origin} is greater than
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   184
     *         or equal to {@code bound}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   185
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   186
    public static void checkRange(long origin, long bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   187
        if (origin >= bound)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   188
            throw new IllegalArgumentException(BadRange);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   189
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   190
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   191
    public static long[] convertSeedBytesToLongs(byte[] seed, int n, int z) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   192
	final long[] result = new long[n];
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   193
	final int m = Math.min(seed.length, n << 3);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   194
	// Distribute seed bytes into the words to be formed.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   195
	for (int j = 0; j < m; j++) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   196
	    result[j>>3] = (result[j>>3] << 8) | seed[j];
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   197
	}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   198
	// If there aren't enough seed bytes for all the words we need,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   199
	// use a SplitMix-style PRNG to fill in the rest.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   200
	long v = result[0];
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   201
	for (int j = (m + 7) >> 3; j < n; j++) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   202
	    result[j] = mixMurmur64(v += SILVER_RATIO_64);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   203
	}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   204
	// Finally, we need to make sure the last z words are not all zero.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   205
	search: {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   206
	    for (int j = n - z; j < n; j++) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   207
		if (result[j] != 0) break search;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   208
	    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   209
	    // If they are, fill in using a SplitMix-style PRNG.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   210
	    // Using "& ~1L" in the next line defends against the case z==1
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   211
	    // by guaranteeing that the first generated value will be nonzero.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   212
	    long w = result[0] & ~1L;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   213
	    for (int j = n - z; j < n; j++) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   214
		result[j] = mixMurmur64(w += SILVER_RATIO_64);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   215
	    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   216
	}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   217
	return result;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   218
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   219
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   220
    public static int[] convertSeedBytesToInts(byte[] seed, int n, int z) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   221
	final int[] result = new int[n];
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   222
	final int m = Math.min(seed.length, n << 2);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   223
	// Distribute seed bytes into the words to be formed.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   224
	for (int j = 0; j < m; j++) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   225
	    result[j>>2] = (result[j>>2] << 8) | seed[j];
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   226
	}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   227
	// If there aren't enough seed bytes for all the words we need,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   228
	// use a SplitMix-style PRNG to fill in the rest.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   229
	int v = result[0];
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   230
	for (int j = (m + 3) >> 2; j < n; j++) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   231
	    result[j] = mixMurmur32(v += SILVER_RATIO_32);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   232
	}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   233
	// Finally, we need to make sure the last z words are not all zero.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   234
	search: {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   235
	    for (int j = n - z; j < n; j++) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   236
		if (result[j] != 0) break search;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   237
	    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   238
	    // If they are, fill in using a SplitMix-style PRNG.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   239
	    // Using "& ~1" in the next line defends against the case z==1
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   240
	    // by guaranteeing that the first generated value will be nonzero.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   241
	    int w = result[0] & ~1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   242
	    for (int j = n - z; j < n; j++) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   243
		result[j] = mixMurmur32(w += SILVER_RATIO_32);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   244
	    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   245
	}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   246
	return result;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   247
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   248
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   249
    /*
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   250
     * Bounded versions of nextX methods used by streams, as well as
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   251
     * the public nextX(origin, bound) methods.  These exist mainly to
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   252
     * avoid the need for multiple versions of stream spliterators
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   253
     * across the different exported forms of streams.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   254
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   255
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   256
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   257
     * This is the form of {@code nextLong} used by a {@code LongStream}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   258
     * {@code Spliterator} and by the public method
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   259
     * {@code nextLong(origin, bound)}.  If {@code origin} is greater
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   260
     * than {@code bound}, then this method simply calls the unbounded
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   261
     * version of {@code nextLong()}, choosing pseudorandomly from
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   262
     * among all 2<sup>64</sup> possible {@code long} values}, and
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   263
     * otherwise uses one or more calls to {@code nextLong()} to
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   264
     * choose a value pseudorandomly from the possible values
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   265
     * between {@code origin} (inclusive) and {@code bound} (exclusive).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   266
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   267
     * @implNote This method first calls {@code nextLong()} to obtain
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   268
     * a {@code long} value that is assumed to be pseudorandomly
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   269
     * chosen uniformly and independently from the 2<sup>64</sup>
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   270
     * possible {@code long} values (that is, each of the 2<sup>64</sup>
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   271
     * possible long values is equally likely to be chosen).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   272
     * Under some circumstances (when the specified range is not
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   273
     * a power of 2), {@code nextLong()} may be called additional times
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   274
     * to ensure that that the values in the specified range are
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   275
     * equally likely to be chosen (provided the assumption holds).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   276
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   277
     * <p> The implementation considers four cases:
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   278
     * <ol>
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   279
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   280
     * <li> If the {@code} bound} is less than or equal to the {@code origin}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   281
     *      (indicated an unbounded form), the 64-bit {@code long} value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   282
     *      obtained from {@code nextLong()} is returned directly.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   283
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   284
     * <li> Otherwise, if the length <it>n</it> of the specified range is an
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   285
     *      exact power of two 2<sup><it>m</it></sup> for some integer
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   286
     *      <it>m</it>, then return the sum of {@code origin} and the
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   287
     *      <it>m</it> lowest-order bits of the value from {@code nextLong()}.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   288
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   289
     * <li> Otherwise, if the length <it>n</it> of the specified range
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   290
     *      is less than 2<sup>63</sup>, then the basic idea is to use the
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   291
     *      remainder modulo <it>n</it> of the value from {@code nextLong()},
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   292
     *      but with this approach some values will be over-represented.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   293
     *      Therefore a loop is used to avoid potential bias by rejecting
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   294
     *      candidates that are too large.  Assuming that the results from
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   295
     *      {@code nextLong()} are truly chosen uniformly and independently,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   296
     *      the expected number of iterations will be somewhere between
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   297
     *      1 and 2, depending on the precise value of <it>n</it>.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   298
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   299
     * <li> Otherwise, the length <it>n</it> of the specified range
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   300
     *      cannot be represented as a positive {@code long} value.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   301
     *      A loop repeatedly calls {@code nextlong()} until obtaining
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   302
     *      a suitable candidate,  Again, the expected number of iterations
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   303
     *      is less than 2.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   304
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   305
     * </ol>
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   306
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   307
     * @param origin the least value that can be produced,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   308
     *        unless greater than or equal to {@code bound}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   309
     * @param bound the upper bound (exclusive), unless {@code origin}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   310
     *        is greater than or equal to {@code bound}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   311
     * @return a pseudorandomly chosen {@code long} value,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   312
     *         which will be between {@code origin} (inclusive) and
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   313
     *         {@code bound} exclusive unless {@code origin}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   314
     *         is greater than or equal to {@code bound}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   315
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   316
    public static long boundedNextLong(Rng rng, long origin, long bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   317
        long r = rng.nextLong();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   318
        if (origin < bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   319
	    // It's not case (1).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   320
            final long n = bound - origin;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   321
	    final long m = n - 1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   322
            if ((n & m) == 0L) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   323
		// It is case (2): length of range is a power of 2.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   324
                r = (r & m) + origin;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   325
	    } else if (n > 0L) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   326
		// It is case (3): need to reject over-represented candidates.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   327
		/* This loop takes an unlovable form (but it works):
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   328
		   because the first candidate is already available,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   329
		   we need a break-in-the-middle construction,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   330
		   which is concisely but cryptically performed
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   331
		   within the while-condition of a body-less for loop. */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   332
                for (long u = r >>> 1;            // ensure nonnegative
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   333
                     u + m - (r = u % n) < 0L;    // rejection check
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   334
                     u = rng.nextLong() >>> 1) // retry
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   335
                    ;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   336
                r += origin;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   337
            }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   338
            else {              
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   339
		// It is case (4): length of range not representable as long.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   340
                while (r < origin || r >= bound)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   341
                    r = rng.nextLong();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   342
            }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   343
        }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   344
        return r;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   345
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   346
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   347
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   348
     * This is the form of {@code nextLong} used by the public method
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   349
     * {@code nextLong(bound)}.  This is essentially a version of
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   350
     * {@code boundedNextLong(origin, bound)} that has been
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   351
     * specialized for the case where the {@code origin} is zero
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   352
     * and the {@code bound} is greater than zero.  The value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   353
     * returned is chosen pseudorandomly from nonnegative integer
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   354
     * values less than {@code bound}.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   355
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   356
     * @implNote This method first calls {@code nextLong()} to obtain
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   357
     * a {@code long} value that is assumed to be pseudorandomly
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   358
     * chosen uniformly and independently from the 2<sup>64</sup>
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   359
     * possible {@code long} values (that is, each of the 2<sup>64</sup>
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   360
     * possible long values is equally likely to be chosen).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   361
     * Under some circumstances (when the specified range is not
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   362
     * a power of 2), {@code nextLong()} may be called additional times
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   363
     * to ensure that that the values in the specified range are
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   364
     * equally likely to be chosen (provided the assumption holds).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   365
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   366
     * <p> The implementation considers two cases:
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   367
     * <ol>
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   368
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   369
     * <li> If {@code bound} is an exact power of two 2<sup><it>m</it></sup>
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   370
     *      for some integer <it>m</it>, then return the sum of {@code origin}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   371
     *      and the <it>m</it> lowest-order bits of the value from
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   372
     *      {@code nextLong()}.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   373
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   374
     * <li> Otherwise, the basic idea is to use the remainder modulo
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   375
     *      <it>bound</it> of the value from {@code nextLong()},
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   376
     *      but with this approach some values will be over-represented.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   377
     *      Therefore a loop is used to avoid potential bias by rejecting
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   378
     *      candidates that vare too large.  Assuming that the results from
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   379
     *      {@code nextLong()} are truly chosen uniformly and independently,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   380
     *      the expected number of iterations will be somewhere between
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   381
     *      1 and 2, depending on the precise value of <it>bound</it>.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   382
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   383
     * </ol>
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   384
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   385
     * @param bound the upper bound (exclusive); must be greater than zero
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   386
     * @return a pseudorandomly chosen {@code long} value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   387
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   388
    public static long boundedNextLong(Rng rng, long bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   389
        // Specialize boundedNextLong for origin == 0, bound > 0
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   390
        final long m = bound - 1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   391
        long r = rng.nextLong();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   392
        if ((bound & m) == 0L) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   393
	    // The bound is a power of 2.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   394
            r &= m;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   395
	} else {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   396
	    // Must reject over-represented candidates
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   397
	    /* This loop takes an unlovable form (but it works):
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   398
	       because the first candidate is already available,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   399
	       we need a break-in-the-middle construction,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   400
	       which is concisely but cryptically performed
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   401
	       within the while-condition of a body-less for loop. */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   402
            for (long u = r >>> 1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   403
                 u + m - (r = u % bound) < 0L;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   404
                 u = rng.nextLong() >>> 1)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   405
                ;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   406
        }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   407
        return r;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   408
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   409
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   410
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   411
     * This is the form of {@code nextInt} used by an {@code IntStream}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   412
     * {@code Spliterator} and by the public method
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   413
     * {@code nextInt(origin, bound)}.  If {@code origin} is greater
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   414
     * than {@code bound}, then this method simply calls the unbounded
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   415
     * version of {@code nextInt()}, choosing pseudorandomly from
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   416
     * among all 2<sup>64</sup> possible {@code int} values}, and
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   417
     * otherwise uses one or more calls to {@code nextInt()} to
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   418
     * choose a value pseudorandomly from the possible values
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   419
     * between {@code origin} (inclusive) and {@code bound} (exclusive).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   420
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   421
     * @implNote The implementation of this method is identical to
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   422
     *     the implementation of {@code nextLong(origin, bound)}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   423
     *     except that {@code int} values and the {@code nextInt()}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   424
     *     method are used rather than {@code long} values and the
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   425
     *     {@code nextLong()} method.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   426
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   427
     * @param origin the least value that can be produced,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   428
     *        unless greater than or equal to {@code bound}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   429
     * @param bound the upper bound (exclusive), unless {@code origin}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   430
     *        is greater than or equal to {@code bound}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   431
     * @return a pseudorandomly chosen {@code int} value,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   432
     *         which will be between {@code origin} (inclusive) and
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   433
     *         {@code bound} exclusive unless {@code origin}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   434
     *         is greater than or equal to {@code bound}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   435
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   436
    public static int boundedNextInt(Rng rng, int origin, int bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   437
        int r = rng.nextInt();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   438
        if (origin < bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   439
	    // It's not case (1).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   440
            final int n = bound - origin;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   441
	    final int m = n - 1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   442
            if ((n & m) == 0) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   443
		// It is case (2): length of range is a power of 2.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   444
                r = (r & m) + origin;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   445
	    } else if (n > 0) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   446
		// It is case (3): need to reject over-represented candidates.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   447
                for (int u = r >>> 1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   448
                     u + m - (r = u % n) < 0;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   449
                     u = rng.nextInt() >>> 1)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   450
                    ;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   451
                r += origin;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   452
            }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   453
            else {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   454
		// It is case (4): length of range not representable as long.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   455
                while (r < origin || r >= bound)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   456
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   457
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   458
		    r = rng.nextInt();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   459
            }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   460
        }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   461
        return r;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   462
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   463
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   464
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   465
     * This is the form of {@code nextInt} used by the public method
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   466
     * {@code nextInt(bound)}.  This is essentially a version of
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   467
     * {@code boundedNextInt(origin, bound)} that has been
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   468
     * specialized for the case where the {@code origin} is zero
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   469
     * and the {@code bound} is greater than zero.  The value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   470
     * returned is chosen pseudorandomly from nonnegative integer
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   471
     * values less than {@code bound}.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   472
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   473
     * @implNote The implementation of this method is identical to
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   474
     *     the implementation of {@code nextLong(bound)}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   475
     *     except that {@code int} values and the {@code nextInt()}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   476
     *     method are used rather than {@code long} values and the
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   477
     *     {@code nextLong()} method.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   478
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   479
     * @param bound the upper bound (exclusive); must be greater than zero
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   480
     * @return a pseudorandomly chosen {@code long} value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   481
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   482
    public static int boundedNextInt(Rng rng, int bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   483
        // Specialize boundedNextInt for origin == 0, bound > 0
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   484
        final int m = bound - 1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   485
        int r = rng.nextInt();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   486
        if ((bound & m) == 0) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   487
	    // The bound is a power of 2.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   488
            r &= m;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   489
	} else {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   490
	    // Must reject over-represented candidates
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   491
            for (int u = r >>> 1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   492
                 u + m - (r = u % bound) < 0;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   493
                 u = rng.nextInt() >>> 1)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   494
                ;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   495
        }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   496
        return r;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   497
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   498
    
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   499
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   500
     * This is the form of {@code nextDouble} used by a {@code DoubleStream}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   501
     * {@code Spliterator} and by the public method
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   502
     * {@code nextDouble(origin, bound)}.  If {@code origin} is greater
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   503
     * than {@code bound}, then this method simply calls the unbounded
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   504
     * version of {@code nextDouble()}, and otherwise scales and translates
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   505
     * the result of a call to {@code nextDouble()} so that it lies
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   506
     * between {@code origin} (inclusive) and {@code bound} (exclusive).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   507
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   508
     * @implNote The implementation considers two cases:
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   509
     * <ol>
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   510
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   511
     * <li> If the {@code bound} is less than or equal to the {@code origin}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   512
     *      (indicated an unbounded form), the 64-bit {@code double} value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   513
     *      obtained from {@code nextDouble()} is returned directly.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   514
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   515
     * <li> Otherwise, the result of a call to {@code nextDouble} is
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   516
     *      multiplied by {@code (bound - origin)}, then {@code origin}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   517
     *      is added, and then if this this result is not less than
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   518
     *      {@code bound} (which can sometimes occur because of rounding),
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   519
     *      it is replaced with the largest {@code double} value that
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   520
     *      is less than {@code bound}.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   521
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   522
     * </ol>
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   523
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   524
     * @param origin the least value that can be produced,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   525
     *        unless greater than or equal to {@code bound}; must be finite
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   526
     * @param bound the upper bound (exclusive), unless {@code origin}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   527
     *        is greater than or equal to {@code bound}; must be finite
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   528
     * @return a pseudorandomly chosen {@code double} value,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   529
     *         which will be between {@code origin} (inclusive) and
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   530
     *         {@code bound} exclusive unless {@code origin}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   531
     *         is greater than or equal to {@code bound},
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   532
     *         in which case it will be between 0.0 (inclusive)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   533
     *         and 1.0 (exclusive)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   534
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   535
    public static double boundedNextDouble(Rng rng, double origin, double bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   536
        double r = rng.nextDouble();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   537
        if (origin < bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   538
            r = r * (bound - origin) + origin;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   539
            if (r >= bound)  // may need to correct a rounding problem
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   540
                r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   541
        }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   542
        return r;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   543
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   544
    
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   545
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   546
     * This is the form of {@code nextDouble} used by the public method
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   547
     * {@code nextDouble(bound)}.  This is essentially a version of
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   548
     * {@code boundedNextDouble(origin, bound)} that has been
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   549
     * specialized for the case where the {@code origin} is zero
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   550
     * and the {@code bound} is greater than zero.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   551
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   552
     * @implNote The result of a call to {@code nextDouble} is
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   553
     *      multiplied by {@code bound}, and then if this result is
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   554
     *      not less than {@code bound} (which can sometimes occur
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   555
     *      because of rounding), it is replaced with the largest
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   556
     *      {@code double} value that is less than {@code bound}.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   557
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   558
     * @param bound the upper bound (exclusive); must be finite and
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   559
     *        greater than zero
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   560
     * @return a pseudorandomly chosen {@code double} value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   561
     *         between zero (inclusive) and {@code bound} (exclusive)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   562
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   563
    public static double boundedNextDouble(Rng rng, double bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   564
        // Specialize boundedNextDouble for origin == 0, bound > 0
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   565
        double r = rng.nextDouble();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   566
	r = r * bound;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   567
	if (r >= bound)  // may need to correct a rounding problem
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   568
	    r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   569
        return r;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   570
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   571
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   572
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   573
     * This is the form of {@code nextFloat} used by a {@code FloatStream}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   574
     * {@code Spliterator} (if there were any) and by the public method
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   575
     * {@code nextFloat(origin, bound)}.  If {@code origin} is greater
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   576
     * than {@code bound}, then this method simply calls the unbounded
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   577
     * version of {@code nextFloat()}, and otherwise scales and translates
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   578
     * the result of a call to {@code nextFloat()} so that it lies
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   579
     * between {@code origin} (inclusive) and {@code bound} (exclusive).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   580
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   581
     * @implNote The implementation of this method is identical to
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   582
     *     the implementation of {@code nextDouble(origin, bound)}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   583
     *     except that {@code float} values and the {@code nextFloat()}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   584
     *     method are used rather than {@code double} values and the
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   585
     *     {@code nextDouble()} method.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   586
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   587
     * @param origin the least value that can be produced,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   588
     *        unless greater than or equal to {@code bound}; must be finite
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   589
     * @param bound the upper bound (exclusive), unless {@code origin}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   590
     *        is greater than or equal to {@code bound}; must be finite
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   591
     * @return a pseudorandomly chosen {@code float} value,
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   592
     *         which will be between {@code origin} (inclusive) and
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   593
     *         {@code bound} exclusive unless {@code origin}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   594
     *         is greater than or equal to {@code bound},
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   595
     *         in which case it will be between 0.0 (inclusive)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   596
     *         and 1.0 (exclusive)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   597
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   598
    public static float boundedNextFloat(Rng rng, float origin, float bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   599
        float r = rng.nextFloat();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   600
        if (origin < bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   601
            r = r * (bound - origin) + origin;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   602
            if (r >= bound) // may need to correct a rounding problem
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   603
                r = Float.intBitsToFloat(Float.floatToIntBits(bound) - 1);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   604
        }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   605
        return r;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   606
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   607
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   608
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   609
     * This is the form of {@code nextFloat} used by the public method
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   610
     * {@code nextFloat(bound)}.  This is essentially a version of
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   611
     * {@code boundedNextFloat(origin, bound)} that has been
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   612
     * specialized for the case where the {@code origin} is zero
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   613
     * and the {@code bound} is greater than zero.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   614
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   615
     * @implNote The implementation of this method is identical to
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   616
     *     the implementation of {@code nextDouble(bound)}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   617
     *     except that {@code float} values and the {@code nextFloat()}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   618
     *     method are used rather than {@code double} values and the
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   619
     *     {@code nextDouble()} method.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   620
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   621
     * @param bound the upper bound (exclusive); must be finite and
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   622
     *        greater than zero
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   623
     * @return a pseudorandomly chosen {@code float} value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   624
     *         between zero (inclusive) and {@code bound} (exclusive)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   625
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   626
    public static float boundedNextFloat(Rng rng, float bound) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   627
        // Specialize boundedNextFloat for origin == 0, bound > 0
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   628
        float r = rng.nextFloat();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   629
	r = r * bound;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   630
	if (r >= bound) // may need to correct a rounding problem
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   631
	    r = Float.intBitsToFloat(Float.floatToIntBits(bound) - 1);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   632
        return r;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   633
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   634
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   635
    // The following decides which of two strategies initialSeed() will use.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   636
    private static boolean secureRandomSeedRequested() {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   637
	String pp = java.security.AccessController.doPrivileged(
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   638
                new sun.security.action.GetPropertyAction(
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   639
                        "java.util.secureRandomSeed"));
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   640
	return (pp != null && pp.equalsIgnoreCase("true"));
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   641
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   642
    
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   643
    private static final boolean useSecureRandomSeed = secureRandomSeedRequested();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   644
	
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   645
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   646
     * Returns a {@code long} value (chosen from some
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   647
     * machine-dependent entropy source) that may be useful for
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   648
     * initializing a source of seed values for instances of {@code Rng}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   649
     * created by zero-argument constructors.  (This method should
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   650
     * <it>not</it> be called repeatedly, once per constructed
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   651
     * object; at most it should be called once per class.)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   652
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   653
     * @return a {@code long} value, randomly chosen using
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   654
     *         appropriate environmental entropy
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   655
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   656
    public static long initialSeed() {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   657
        if (useSecureRandomSeed) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   658
            byte[] seedBytes = java.security.SecureRandom.getSeed(8);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   659
            long s = (long)(seedBytes[0]) & 0xffL;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   660
            for (int i = 1; i < 8; ++i)
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   661
                s = (s << 8) | ((long)(seedBytes[i]) & 0xffL);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   662
            return s;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   663
        }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   664
        return (mixStafford13(System.currentTimeMillis()) ^
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   665
                mixStafford13(System.nanoTime()));
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   666
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   667
    
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   668
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   669
     * The fractional part (first 32 or 64 bits, then forced odd) of
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   670
     * the golden ratio (1+sqrt(5))/2 and of the silver ratio 1+sqrt(2).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   671
     * Useful for producing good Weyl sequences or as arbitrary nonzero values.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   672
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   673
    public static final int  GOLDEN_RATIO_32 = 0x9e3779b9;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   674
    public static final long GOLDEN_RATIO_64 = 0x9e3779b97f4a7c15L;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   675
    public static final int  SILVER_RATIO_32 = 0x6A09E667;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   676
    public static final long SILVER_RATIO_64 = 0x6A09E667F3BCC909L;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   677
    
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   678
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   679
     * Computes the 64-bit mixing function for MurmurHash3.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   680
     * This is a 64-bit hashing function with excellent avalanche statistics.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   681
     * https://github.com/aappleby/smhasher/wiki/MurmurHash3
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   682
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   683
     * Note that if the argument {@code z} is 0, the result is 0.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   684
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   685
     * @param z any long value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   686
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   687
     * @return the result of hashing z
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   688
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   689
    public static long mixMurmur64(long z) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   690
        z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   691
        z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   692
        return z ^ (z >>> 33);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   693
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   694
    
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   695
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   696
     * Computes Stafford variant 13 of the 64-bit mixing function for MurmurHash3.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   697
     * This is a 64-bit hashing function with excellent avalanche statistics.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   698
     * http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   699
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   700
     * Note that if the argument {@code z} is 0, the result is 0.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   701
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   702
     * @param z any long value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   703
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   704
     * @return the result of hashing z
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   705
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   706
    public static long mixStafford13(long z) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   707
        z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   708
        z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   709
        return z ^ (z >>> 31);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   710
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   711
    
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   712
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   713
     * Computes Doug Lea's 64-bit mixing function.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   714
     * This is a 64-bit hashing function with excellent avalanche statistics.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   715
     * It has the advantages of using the same multiplicative constant twice
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   716
     * and of using only 32-bit shifts.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   717
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   718
     * Note that if the argument {@code z} is 0, the result is 0.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   719
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   720
     * @param z any long value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   721
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   722
     * @return the result of hashing z
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   723
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   724
    public static long mixLea64(long z) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   725
        z = (z ^ (z >>> 32)) * 0xdaba0b6eb09322e3L;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   726
        z = (z ^ (z >>> 32)) * 0xdaba0b6eb09322e3L;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   727
        return z ^ (z >>> 32);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   728
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   729
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   730
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   731
     * Computes the 32-bit mixing function for MurmurHash3.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   732
     * This is a 32-bit hashing function with excellent avalanche statistics.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   733
     * https://github.com/aappleby/smhasher/wiki/MurmurHash3
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   734
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   735
     * Note that if the argument {@code z} is 0, the result is 0.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   736
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   737
     * @param z any long value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   738
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   739
     * @return the result of hashing z
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   740
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   741
    public static int mixMurmur32(int z) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   742
        z = (z ^ (z >>> 16)) * 0x85ebca6b;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   743
        z = (z ^ (z >>> 13)) * 0xc2b2ae35;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   744
        return z ^ (z >>> 16);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   745
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   746
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   747
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   748
     * Computes Doug Lea's 32-bit mixing function.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   749
     * This is a 32-bit hashing function with excellent avalanche statistics.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   750
     * It has the advantages of using the same multiplicative constant twice
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   751
     * and of using only 16-bit shifts.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   752
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   753
     * Note that if the argument {@code z} is 0, the result is 0.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   754
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   755
     * @param z any long value
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   756
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   757
     * @return the result of hashing z
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   758
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   759
    public static int mixLea32(int z) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   760
        z = (z ^ (z >>> 16)) * 0xd36d884b;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   761
        z = (z ^ (z >>> 16)) * 0xd36d884b;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   762
        return z ^ (z >>> 16);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   763
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   764
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   765
    // Non-public (package only) support for spliterators needed by AbstractSplittableRng
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   766
    // and AbstractArbitrarilyJumpableRng and AbstractSharedRng
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   767
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   768
    /**
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   769
     * Base class for making Spliterator classes for streams of randomly chosen values.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   770
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   771
    static abstract class RandomSpliterator {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   772
        long index;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   773
        final long fence;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   774
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   775
	RandomSpliterator(long index, long fence) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   776
	    this.index = index; this.fence = fence;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   777
        }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   778
	
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   779
        public long estimateSize() {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   780
            return fence - index;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   781
        }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   782
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   783
        public int characteristics() {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   784
            return (Spliterator.SIZED | Spliterator.SUBSIZED |
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   785
                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   786
        }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   787
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   788
    
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   789
    
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   790
    /* 
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   791
     * Implementation support for nextExponential() and nextGaussian() methods of Rng.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   792
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   793
     * Each is implemented using McFarland's fast modified ziggurat algorithm (largely
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   794
     * table-driven, with rare cases handled by computation and rejection sampling).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   795
     * Walker's alias method for sampling a discrete distribution also plays a role.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   796
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   797
     * The tables themselves, as well as a number of associated parameters, are defined
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   798
     * in class java.util.DoubleZigguratTables, which is automatically generated by the
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   799
     * program create_ziggurat_tables.c (which takes only a few seconds to run).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   800
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   801
     * For more information about the algorithms, see these articles:
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   802
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   803
     * Christopher D. McFarland.  2016 (published online 24 Jun 2015).  A modified ziggurat
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   804
     * algorithm for generating exponentially and normally distributed pseudorandom numbers.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   805
     * Journal of Statistical Computation and Simulation 86 (7), pages 1281-1294.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   806
     * https://www.tandfonline.com/doi/abs/10.1080/00949655.2015.1060234
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   807
     * Also at https://arxiv.org/abs/1403.6870 (26 March 2014).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   808
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   809
     * Alastair J. Walker.  1977.  An efficient method for generating discrete random
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   810
     * variables with general distributions. ACM Trans. Math. Software 3, 3
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   811
     * (September 1977), 253-256. DOI: https://doi.org/10.1145/355744.355749
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   812
     *
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   813
     * Certain details of these algorithms depend critically on the quality of the
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   814
     * low-order bits delivered by NextLong().  These algorithms should not be used
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   815
     * with RNG algorithms (such as a simple Linear Congruential Generator) whose
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   816
     * low-order output bits do not have good statistical quality.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   817
     */
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   818
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   819
    // Implementation support for nextExponential()
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   820
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   821
    static double computeNextExponential(Rng rng) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   822
	long U1 = rng.nextLong();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   823
	// Experimentation on a variety of machines indicates that it is overall much faster
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   824
	// to do the following & and < operations on longs rather than first cast U1 to int
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   825
	// (but then we need to cast to int before doing the array indexing operation).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   826
	long i = U1 & DoubleZigguratTables.exponentialLayerMask;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   827
	if (i < DoubleZigguratTables.exponentialNumberOfLayers) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   828
	    // This is the fast path (occurring more than 98% of the time).  Make an early exit.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   829
	    return DoubleZigguratTables.exponentialX[(int)i] * (U1 >>> 1);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   830
	}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   831
	// We didn't use the upper part of U1 after all.  We'll be able to use it later.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   832
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   833
	for (double extra = 0.0; ; ) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   834
	    // Use Walker's alias method to sample an (unsigned) integer j from a discrete
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   835
	    // probability distribution that includes the tail and all the ziggurat overhangs;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   836
	    // j will be less than DoubleZigguratTables.exponentialNumberOfLayers + 1.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   837
	    long UA = rng.nextLong();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   838
	    int j = (int)UA & DoubleZigguratTables.exponentialAliasMask;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   839
	    if (UA >= DoubleZigguratTables.exponentialAliasThreshold[j]) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   840
		j = DoubleZigguratTables.exponentialAliasMap[j] & DoubleZigguratTables.exponentialSignCorrectionMask;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   841
	    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   842
	    if (j > 0) {   // Sample overhang j
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   843
		// For the exponential distribution, every overhang is convex.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   844
		final double[] X = DoubleZigguratTables.exponentialX;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   845
		final double[] Y = DoubleZigguratTables.exponentialY;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   846
		for (;; U1 = (rng.nextLong() >>> 1)) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   847
		    long U2 = (rng.nextLong() >>> 1);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   848
		    // Compute the actual x-coordinate of the randomly chosen point.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   849
		    double x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   850
		    // Does the point lie below the curve?
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   851
		    long Udiff = U2 - U1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   852
		    if (Udiff < 0) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   853
			// We picked a point in the upper-right triangle.  None of those can be accepted.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   854
			// So remap the point into the lower-left triangle and try that.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   855
			// In effect, we swap U1 and U2, and invert the sign of Udiff.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   856
			Udiff = -Udiff;               
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   857
			U2 = U1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   858
			U1 -= Udiff;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   859
		    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   860
		    if (Udiff >= DoubleZigguratTables.exponentialConvexMargin) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   861
			return x + extra;   // The chosen point is way below the curve; accept it.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   862
		    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   863
		    // Compute the actual y-coordinate of the randomly chosen point.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   864
		    double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   865
		    // Now see how that y-coordinate compares to the curve
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   866
		    if (y <= Math.exp(-x)) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   867
			return x + extra;   // The chosen point is below the curve; accept it.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   868
		    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   869
		    // Otherwise, we reject this sample and have to try again.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   870
		}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   871
	    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   872
	    // We are now committed to sampling from the tail.  We could do a recursive call
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   873
	    // and then add X[0] but we save some time and stack space by using an iterative loop.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   874
	    extra += DoubleZigguratTables.exponentialX0;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   875
	    // This is like the first five lines of this method, but if it returns, it first adds "extra".
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   876
	    U1 = rng.nextLong();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   877
	    i = U1 & DoubleZigguratTables.exponentialLayerMask;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   878
	    if (i < DoubleZigguratTables.exponentialNumberOfLayers) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   879
		return DoubleZigguratTables.exponentialX[(int)i] * (U1 >>> 1) + extra;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   880
	    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   881
	}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   882
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   883
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   884
    // Implementation support for nextGaussian()
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   885
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   886
    static double computeNextGaussian(Rng rng) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   887
	long U1 = rng.nextLong();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   888
	// Experimentation on a variety of machines indicates that it is overall much faster
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   889
	// to do the following & and < operations on longs rather than first cast U1 to int
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   890
	// (but then we need to cast to int before doing the array indexing operation).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   891
	long i = U1 & DoubleZigguratTables.normalLayerMask;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   892
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   893
	if (i < DoubleZigguratTables.normalNumberOfLayers) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   894
	    // This is the fast path (occurring more than 98% of the time).  Make an early exit.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   895
	    return DoubleZigguratTables.normalX[(int)i] * U1;   // Note that the sign bit of U1 is used here.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   896
	}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   897
	// We didn't use the upper part of U1 after all.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   898
	// Pull U1 apart into a sign bit and a 63-bit value for later use.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   899
	double signBit = (U1 >= 0) ? 1.0 : -1.0;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   900
	U1 = (U1 << 1) >>> 1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   901
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   902
	// Use Walker's alias method to sample an (unsigned) integer j from a discrete
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   903
	// probability distribution that includes the tail and all the ziggurat overhangs;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   904
	// j will be less than DoubleZigguratTables.normalNumberOfLayers + 1.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   905
	long UA = rng.nextLong();
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   906
	int j = (int)UA & DoubleZigguratTables.normalAliasMask;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   907
	if (UA >= DoubleZigguratTables.normalAliasThreshold[j]) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   908
	    j = DoubleZigguratTables.normalAliasMap[j] & DoubleZigguratTables.normalSignCorrectionMask;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   909
	}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   910
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   911
	double x;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   912
	// Now the goal is to choose the result, which will be multiplied by signBit just before return.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   913
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   914
        // There are four kinds of overhangs:
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   915
	//
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   916
        //  j == 0                          :  Sample from tail
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   917
        //  0 < j < normalInflectionIndex   :  Overhang is convex; can reject upper-right triangle
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   918
        //  j == normalInflectionIndex      :  Overhang includes the inflection point
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   919
        //  j > normalInflectionIndex       :  Overhang is concave; can accept point in lower-left triangle
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   920
	//
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   921
        // Choose one of four loops to compute x, each specialized for a specific kind of overhang.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   922
	// Conditional statements are arranged such that the more likely outcomes are first.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   923
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   924
	// In the three cases other than the tail case:
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   925
	// U1 represents a fraction (scaled by 2**63) of the width of rectangle measured from the left.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   926
	// U2 represents a fraction (scaled by 2**63) of the height of rectangle measured from the top.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   927
	// Together they indicate a randomly chosen point within the rectangle.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   928
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   929
	final double[] X = DoubleZigguratTables.normalX;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   930
	final double[] Y = DoubleZigguratTables.normalY;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   931
	if (j > DoubleZigguratTables.normalInflectionIndex) {   // Concave overhang
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   932
	    for (;; U1 = (rng.nextLong() >>> 1)) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   933
		long U2 = (rng.nextLong() >>> 1);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   934
		// Compute the actual x-coordinate of the randomly chosen point.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   935
		x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   936
		// Does the point lie below the curve?
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   937
		long Udiff = U2 - U1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   938
		if (Udiff >= 0) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   939
		    break;   // The chosen point is in the lower-left triangle; accept it.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   940
		}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   941
		if (Udiff <= -DoubleZigguratTables.normalConcaveMargin) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   942
		    continue;   // The chosen point is way above the curve; reject it.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   943
		}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   944
		// Compute the actual y-coordinate of the randomly chosen point.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   945
		double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   946
		// Now see how that y-coordinate compares to the curve
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   947
		if (y <= Math.exp(-0.5*x*x)) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   948
		    break;   // The chosen point is below the curve; accept it.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   949
		}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   950
		// Otherwise, we reject this sample and have to try again.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   951
            }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   952
	} else if (j == 0) {   // Tail
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   953
	    // Tail-sampling method of Marsaglia and Tsang.  See any one of:
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   954
	    // Marsaglia and Tsang. 1984. A fast, easily implemented method for sampling from decreasing
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   955
	    //    or symmetric unimodal density functions. SIAM J. Sci. Stat. Comput. 5, 349-359.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   956
	    // Marsaglia and Tsang. 1998. The Monty Python method for generating random variables.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   957
	    //    ACM Trans. Math. Softw. 24, 3 (September 1998), 341-350.  See page 342, step (4).
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   958
	    //    http://doi.org/10.1145/292395.292453
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   959
	    // Thomas, Luk, Leong, and Villasenor. 2007. Gaussian random number generators.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   960
	    //    ACM Comput. Surv. 39, 4, Article 11 (November 2007).  See Algorithm 16.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   961
	    //    http://doi.org/10.1145/1287620.1287622
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   962
	    // Compute two separate random exponential samples and then compare them in certain way.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   963
	    do {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   964
		x = (1.0 / DoubleZigguratTables.normalX0) * computeNextExponential(rng);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   965
	    } while (computeNextExponential(rng) < 0.5*x*x);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   966
	    x += DoubleZigguratTables.normalX0;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   967
	} else if (j < DoubleZigguratTables.normalInflectionIndex) {   // Convex overhang
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   968
	    for (;; U1 = (rng.nextLong() >>> 1)) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   969
		long U2 = (rng.nextLong() >>> 1);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   970
		// Compute the actual x-coordinate of the randomly chosen point.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   971
		x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   972
		// Does the point lie below the curve?
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   973
		long Udiff = U2 - U1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   974
		if (Udiff < 0) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   975
		    // We picked a point in the upper-right triangle.  None of those can be accepted.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   976
		    // So remap the point into the lower-left triangle and try that.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   977
		    // In effect, we swap U1 and U2, and invert the sign of Udiff.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   978
		    Udiff = -Udiff;               
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   979
		    U2 = U1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   980
		    U1 -= Udiff;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   981
		}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   982
		if (Udiff >= DoubleZigguratTables.normalConvexMargin) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   983
		    break;   // The chosen point is way below the curve; accept it.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   984
		}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   985
		// Compute the actual y-coordinate of the randomly chosen point.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   986
		double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   987
		// Now see how that y-coordinate compares to the curve
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   988
		if (y <= Math.exp(-0.5*x*x)) break;                // The chosen point is below the curve; accept it.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   989
		// Otherwise, we reject this sample and have to try again.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   990
	    } 
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   991
	} else {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   992
	    // The overhang includes the inflection point, so the curve is both convex and concave
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   993
	    for (;; U1 = (rng.nextLong() >>> 1)) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   994
		long U2 = (rng.nextLong() >>> 1);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   995
		// Compute the actual x-coordinate of the randomly chosen point.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   996
		x = (X[j] * 0x1.0p63) + ((X[j-1] - X[j]) * (double)U1);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   997
		// Does the point lie below the curve?
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   998
		long Udiff = U2 - U1;
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
   999
		if (Udiff >= DoubleZigguratTables.normalConvexMargin) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1000
		    break;   // The chosen point is way below the curve; accept it.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1001
		}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1002
		if (Udiff <= -DoubleZigguratTables.normalConcaveMargin) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1003
		    continue;   // The chosen point is way above the curve; reject it.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1004
		}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1005
		// Compute the actual y-coordinate of the randomly chosen point.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1006
		double y = (Y[j] * 0x1.0p63) + ((Y[j] - Y[j-1]) * (double)U2);
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1007
		// Now see how that y-coordinate compares to the curve
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1008
		if (y <= Math.exp(-0.5*x*x)) {
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1009
		    break;   // The chosen point is below the curve; accept it.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1010
		}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1011
		// Otherwise, we reject this sample and have to try again.
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1012
	    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1013
	}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1014
	return signBit*x; 
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1015
    }
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1016
    
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1017
}
6d87e9f7a1ec Initial comment in newrandom/
briangoetz
parents:
diff changeset
  1018