| /* | |
| * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| import java.util.random.*; | |
| import java.util.Set; | |
| import java.util.concurrent.CompletableFuture; | |
| import java.util.concurrent.ExecutionException; | |
| import java.util.concurrent.ThreadLocalRandom; | |
| import java.util.concurrent.TimeUnit; | |
| import java.util.concurrent.TimeoutException; | |
| import java.util.function.DoubleSupplier; | |
| import java.util.stream.Stream; | |
| import static java.util.stream.Collectors.toList; | |
| import static java.util.stream.Collectors.toSet; | |
| /** | |
| * @test | |
| * @summary test bit sequences produced by clases that implement interface RandomGenerator | |
| * @bug 8248862 | |
| * @run main RandomTestMoments | |
| * @author Guy Steele | |
| * @key randomness | |
| */ | |
| public class RandomTestMoments { | |
| static String currentRNG = ""; | |
| static int failCount = 0; | |
| static void exceptionOnFail() { | |
| if (failCount != 0) { | |
| throw new RuntimeException(failCount + " fails detected"); | |
| } | |
| } | |
| static void setRNG(String rng) { | |
| currentRNG = rng; | |
| } | |
| static void fail(String format, Object... args) { | |
| if (currentRNG.length() != 0) { | |
| System.err.println(currentRNG); | |
| currentRNG = ""; | |
| } | |
| System.err.format(" " + format, args); | |
| failCount++; | |
| } | |
| static final int SEQUENCE_SIZE = 50000; | |
| // Moment k of uniform distribution over [0.0,1.0) is 1.0/(1+k). | |
| static double[][] momentsUniform = { | |
| { 1.00000, 1.00000, 0.01000 }, | |
| { 0.500000, 0.500000, 0.0266265 }, | |
| { 0.333333, 0.333333, 0.0391128 }, | |
| { 0.250000, 0.250000, 0.0477151 }, | |
| { 0.200000, 0.200000, 0.0540496 }, | |
| { 0.166667, 0.166667, 0.0589355 }, | |
| { 0.142857, 0.142857, 0.0628462 }, | |
| { 0.125000, 0.125000, 0.0660693 }, | |
| { 0.111111, 0.111111, 0.0688036 }, | |
| { 0.100000, 0.100000, 0.0712002 }, | |
| { 0.0909091, 0.0909091, 0.0733755 }, | |
| { 0.0833333, 0.0833333, 0.0754172 }, | |
| { 0.0769231, 0.0769231, 0.0773868 }, | |
| { 0.0714286, 0.0714286, 0.0793244 }, | |
| { 0.0666667, 0.0666667, 0.0812526 }, | |
| { 0.0625000, 0.0625000, 0.0831806 }, | |
| }; | |
| // Moment k of exponential distribution with mean 1 is k!. | |
| static double[][] momentsExponential = { | |
| { 1.00000, 1.00000, 0.01000 }, | |
| { 1.00000, 1.00000, 0.0718997 }, | |
| { 2.00000, 2.00000, 0.153241 }, | |
| { 6.00000, 6.00000, 0.282813 }, | |
| { 24.0000, 24.0000, 0.503707 }, | |
| }; | |
| // Absolute moment k of Gaussian distribution with mean 0 and stddev 1 is | |
| // pow(2.0,k/2.0)*gamma((k+1)/2.0)/sqrt(PI) | |
| // https://arxiv.org/pdf/1209.4340.pdf, equation (18) | |
| static double[][] absoluteMomentsGaussian = { | |
| { 1.00000, 1.00000, 0.01 }, | |
| { 0.797885, 0.797885, 0.1 }, | |
| { 1.00000, 1.00000, 0.1 }, | |
| { 1.59577, 1.59577, 0.2 }, | |
| { 3.00000, 3.00000, 0.2 }, | |
| { 6.38308, 6.38308, 0.2 }, | |
| { 15.0000, 15.0000, 0.2 }, | |
| { 38.2985, 38.2985, 0.2 }, | |
| { 105.000, 105.000, 0.4 }, | |
| }; | |
| static void checkMoments(String test, double[] measurements, double[][] standard) { | |
| for (int j = 0; j < measurements.length; j++) { | |
| double actual = measurements[j]; | |
| double expected = standard[j][0]; | |
| double basis = standard[j][1]; | |
| double tolerance = standard[j][2]; | |
| if (!(Math.abs(actual - expected)/basis < tolerance)) { | |
| fail("%s fail: actual=%f, expected=%f, basis=%f, tolerance=%f\n", | |
| test, actual, expected, basis, tolerance); | |
| } | |
| } | |
| } | |
| static void testMomentsGaussian(DoubleSupplier theSupplier) { | |
| int m = absoluteMomentsGaussian.length; | |
| double[] absoluteMoments = new double[m]; | |
| for (int j = 0; j < SEQUENCE_SIZE; j++) { | |
| double v = theSupplier.getAsDouble(); | |
| double z = 1.0; | |
| for (int k = 0; k < m; k++) { | |
| absoluteMoments[k] += Math.abs(z); | |
| z *= v; | |
| } | |
| } | |
| for (int k = 0; k < m; k++) { | |
| absoluteMoments[k] /= SEQUENCE_SIZE; | |
| } | |
| checkMoments("Gaussian", absoluteMoments, absoluteMomentsGaussian); | |
| } | |
| static void testMomentsExponential(DoubleSupplier theSupplier) { | |
| int m = momentsExponential.length; | |
| double[] moments = new double[m]; | |
| for (int j = 0; j < SEQUENCE_SIZE; j++) { | |
| double v = theSupplier.getAsDouble(); | |
| double z = 1.0; | |
| for (int k = 0; k < m; k++) { | |
| moments[k] += z; | |
| z *= v; | |
| } | |
| } | |
| for (int k = 0; k < m; k++) { | |
| moments[k] /= SEQUENCE_SIZE; | |
| } | |
| checkMoments("Exponential", moments, momentsExponential); | |
| } | |
| static void testMomentsUniform(DoubleSupplier theSupplier) { | |
| int m = momentsUniform.length; | |
| double[] moments = new double[m]; | |
| for (int j = 0; j < SEQUENCE_SIZE; j++) { | |
| double v = theSupplier.getAsDouble(); | |
| double z = 1.0; | |
| for (int k = 0; k < m; k++) { | |
| moments[k] += z; | |
| z *= v; | |
| } | |
| } | |
| for (int k = 0; k < m; k++) { | |
| moments[k] /= SEQUENCE_SIZE; | |
| } | |
| checkMoments("Uniform", moments, momentsUniform); | |
| } | |
| static void testOneRng(RandomGenerator rng) { | |
| testMomentsGaussian(rng::nextGaussian); | |
| testMomentsExponential(rng::nextExponential); | |
| testMomentsUniform(rng::nextDouble); | |
| testMomentsUniform(rng.doubles().iterator()::next); | |
| } | |
| public static void main(String[] args) { | |
| RandomGeneratorFactory.all() | |
| .filter(f -> !f.name().equals("SecureRandom")) | |
| .forEach(factory -> { | |
| setRNG(factory.name()); | |
| testOneRng(factory.create(325) ); | |
| }); | |
| exceptionOnFail(); | |
| } | |
| } |