1 /* 2 * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package test.java.util.Random; 24 25 import java.util.ArrayList; 26 import java.util.List; 27 28 import java.util.random.*; 29 30 import java.util.Set; 31 import java.util.concurrent.CompletableFuture; 32 import java.util.concurrent.ExecutionException; 33 import java.util.concurrent.ThreadLocalRandom; 34 import java.util.concurrent.TimeUnit; 35 import java.util.concurrent.TimeoutException; 36 import java.util.function.DoubleSupplier; 37 import java.util.stream.Stream; 38 39 import static java.util.stream.Collectors.toList; 40 import static java.util.stream.Collectors.toSet; 41 42 /** 43 * @test 44 * @summary test bit sequences produced by clases that implement interface RandomGenerator 45 * @bug 8248862 46 * @run main RandomTestMoments 47 * @author Guy Steele 48 * @key randomness 49 */ 50 51 public class RandomTestMoments { 52 53 static String currentRNG = ""; 54 static int failCount = 0; 55 exceptionOnFail()56 static void exceptionOnFail() { 57 if (failCount != 0) { 58 throw new RuntimeException(failCount + " fails detected"); 59 } 60 } 61 setRNG(String rng)62 static void setRNG(String rng) { 63 currentRNG = rng; 64 } 65 fail(String format, Object... args)66 static void fail(String format, Object... args) { 67 if (currentRNG.length() != 0) { 68 System.err.println(currentRNG); 69 currentRNG = ""; 70 } 71 72 System.err.format(" " + format, args); 73 failCount++; 74 } 75 76 static final int SEQUENCE_SIZE = 50000; 77 78 // Moment k of uniform distribution over [0.0,1.0) is 1.0/(1+k). 79 80 static double[][] momentsUniform = { 81 { 1.00000, 1.00000, 0.01000 }, 82 { 0.500000, 0.500000, 0.0266265 }, 83 { 0.333333, 0.333333, 0.0391128 }, 84 { 0.250000, 0.250000, 0.0477151 }, 85 { 0.200000, 0.200000, 0.0540496 }, 86 { 0.166667, 0.166667, 0.0589355 }, 87 { 0.142857, 0.142857, 0.0628462 }, 88 { 0.125000, 0.125000, 0.0660693 }, 89 { 0.111111, 0.111111, 0.0688036 }, 90 { 0.100000, 0.100000, 0.0712002 }, 91 { 0.0909091, 0.0909091, 0.0733755 }, 92 { 0.0833333, 0.0833333, 0.0754172 }, 93 { 0.0769231, 0.0769231, 0.0773868 }, 94 { 0.0714286, 0.0714286, 0.0793244 }, 95 { 0.0666667, 0.0666667, 0.0812526 }, 96 { 0.0625000, 0.0625000, 0.0831806 }, 97 }; 98 99 // Moment k of exponential distribution with mean 1 is k!. 100 101 static double[][] momentsExponential = { 102 { 1.00000, 1.00000, 0.01000 }, 103 { 1.00000, 1.00000, 0.0718997 }, 104 { 2.00000, 2.00000, 0.153241 }, 105 { 6.00000, 6.00000, 0.282813 }, 106 { 24.0000, 24.0000, 0.503707 }, 107 }; 108 109 110 // Absolute moment k of Gaussian distribution with mean 0 and stddev 1 is 111 // pow(2.0,k/2.0)*gamma((k+1)/2.0)/sqrt(PI) 112 // https://arxiv.org/pdf/1209.4340.pdf, equation (18) 113 114 static double[][] absoluteMomentsGaussian = { 115 { 1.00000, 1.00000, 0.01 }, 116 { 0.797885, 0.797885, 0.1 }, 117 { 1.00000, 1.00000, 0.1 }, 118 { 1.59577, 1.59577, 0.2 }, 119 { 3.00000, 3.00000, 0.2 }, 120 { 6.38308, 6.38308, 0.2 }, 121 { 15.0000, 15.0000, 0.2 }, 122 { 38.2985, 38.2985, 0.2 }, 123 { 105.000, 105.000, 0.4 }, 124 }; 125 checkMoments(String test, double[] measurements, double[][] standard)126 static void checkMoments(String test, double[] measurements, double[][] standard) { 127 for (int j = 0; j < measurements.length; j++) { 128 double actual = measurements[j]; 129 double expected = standard[j][0]; 130 double basis = standard[j][1]; 131 double tolerance = standard[j][2]; 132 if (!(Math.abs(actual - expected)/basis < tolerance)) { 133 fail("%s fail: actual=%f, expected=%f, basis=%f, tolerance=%f\n", 134 test, actual, expected, basis, tolerance); 135 } 136 } 137 } 138 testMomentsGaussian(DoubleSupplier theSupplier)139 static void testMomentsGaussian(DoubleSupplier theSupplier) { 140 int m = absoluteMomentsGaussian.length; 141 double[] absoluteMoments = new double[m]; 142 for (int j = 0; j < SEQUENCE_SIZE; j++) { 143 double v = theSupplier.getAsDouble(); 144 double z = 1.0; 145 for (int k = 0; k < m; k++) { 146 absoluteMoments[k] += Math.abs(z); 147 z *= v; 148 } 149 } 150 for (int k = 0; k < m; k++) { 151 absoluteMoments[k] /= SEQUENCE_SIZE; 152 } 153 checkMoments("Gaussian", absoluteMoments, absoluteMomentsGaussian); 154 } 155 testMomentsExponential(DoubleSupplier theSupplier)156 static void testMomentsExponential(DoubleSupplier theSupplier) { 157 int m = momentsExponential.length; 158 double[] moments = new double[m]; 159 for (int j = 0; j < SEQUENCE_SIZE; j++) { 160 double v = theSupplier.getAsDouble(); 161 double z = 1.0; 162 for (int k = 0; k < m; k++) { 163 moments[k] += z; 164 z *= v; 165 } 166 } 167 for (int k = 0; k < m; k++) { 168 moments[k] /= SEQUENCE_SIZE; 169 } 170 checkMoments("Exponential", moments, momentsExponential); 171 } 172 testMomentsUniform(DoubleSupplier theSupplier)173 static void testMomentsUniform(DoubleSupplier theSupplier) { 174 int m = momentsUniform.length; 175 double[] moments = new double[m]; 176 for (int j = 0; j < SEQUENCE_SIZE; j++) { 177 double v = theSupplier.getAsDouble(); 178 double z = 1.0; 179 for (int k = 0; k < m; k++) { 180 moments[k] += z; 181 z *= v; 182 } 183 } 184 for (int k = 0; k < m; k++) { 185 moments[k] /= SEQUENCE_SIZE; 186 } 187 checkMoments("Uniform", moments, momentsUniform); 188 } 189 testOneRng(RandomGenerator rng)190 static void testOneRng(RandomGenerator rng) { 191 testMomentsGaussian(rng::nextGaussian); 192 testMomentsExponential(rng::nextExponential); 193 testMomentsUniform(rng::nextDouble); 194 testMomentsUniform(rng.doubles().iterator()::next); 195 } 196 main(String[] args)197 public static void main(String[] args) { 198 RandomGeneratorFactory.all() 199 .filter(f -> !f.name().equals("SecureRandom")) 200 .forEach(factory -> { 201 setRNG(factory.name()); 202 testOneRng(factory.create(325) ); 203 }); 204 205 exceptionOnFail(); 206 } 207 208 } 209