Path: blob/master/test/jdk/java/util/Random/RandomTestChiSquared.java
41149 views
/*1* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/22import java.util.ArrayList;23import java.util.List;24import java.util.PrimitiveIterator;2526import java.util.random.*;2728import java.util.Set;29import java.util.concurrent.CompletableFuture;30import java.util.concurrent.ExecutionException;31import java.util.concurrent.ThreadLocalRandom;32import java.util.concurrent.TimeUnit;33import java.util.concurrent.TimeoutException;34import java.util.function.IntSupplier;35import java.util.function.LongSupplier;36import java.util.function.BooleanSupplier;37import java.util.function.Supplier;38import java.util.function.Function;39import java.util.stream.Stream;4041import static java.util.stream.Collectors.toList;42import static java.util.stream.Collectors.toSet;4344/**45* @test46* @summary test bit sequences produced by clases that implement interface RandomGenerator47* @bug 824886248* @run main RandomTestChiSquared49* @key randomness50*/5152public class RandomTestChiSquared {5354static String currentRNG = "";55static int failCount = 0;5657static void exceptionOnFail() {58if (failCount != 0) {59throw new RuntimeException(failCount + " fails detected");60}61}6263static void setRNG(String rng) {64currentRNG = rng;65}6667static void fail(String format, Object... args) {68if (currentRNG.length() != 0) {69System.err.println(currentRNG);70currentRNG = "";71}7273System.err.format(" " + format, args);74failCount++;75}7677// Some simple chi-squared tests similar to that used for the FIPS 140 poker test,78// but intended primarily to test production of random values from ranges.7980private static final int SEQUENCE_SIZE = 20000;8182// Entry k of this table was computed in Microsoft Excel using the formulae83// =CHISQ.INV(0.0000000777517,k) and =CHISQ.INV.RT(0.00000142611,k)84// (except that entry 0 is a dummy and should never be used).85static final double[][] chiSquaredBounds = {86{ 0.0, 0.0 },87{ 9.49598E-15, 23.24513154 },88{ 1.55503E-07, 26.92112020 },89{ 4.40485E-05, 29.93222467 },90{ 0.000788782, 32.62391510 },91{ 0.004636947, 35.11665045 },92{ 0.015541535, 37.46947634 },93{ 0.037678318, 39.71667636 },94{ 0.074471919, 41.88031518 },95{ 0.128297057, 43.97561646 },96{ 0.200566433, 46.01362542 },97{ 0.291944952, 48.00266676 },98{ 0.402564694, 49.94920504 },99{ 0.532199236, 51.85838271 },100{ 0.680392565, 53.73437242 },101{ 0.846549931, 55.58061674 },102{ 1.030000010, 57.39999630 },103{ 1.230036580, 59.19495111 },104{ 1.445945898, 60.96756998 },105{ 1.677024296, 62.71965780 },106{ 1.922589129, 64.45278706 },107{ 2.181985238, 66.16833789 },108{ 2.454588423, 67.86752964 },109{ 2.739806923, 69.55144602 },110{ 3.037081611, 71.22105544 },111{ 3.345885349, 72.87722754 },112{ 3.665721841, 74.52074682 },113{ 3.996124178, 76.15232388 },114{ 4.336653242, 77.77260487 },115{ 4.686896041, 79.38217943 },116{ 5.046464051, 80.98158736 },117{ 5.414991603, 82.57132439 }118};119120121122// N is the number of categories; every element of s ought to be in [0,N).123// N must be in [1,31].124static boolean chiSquaredTest(String id, int N, IntSupplier theSupplier) {125int[] stats = new int[N];126for (int j = 0; j < SEQUENCE_SIZE; j++) {127int v = theSupplier.getAsInt();128// assert((0 <= v) && (v < N));129++stats[v];130}131int z = 0;132for (int k = 0; k < stats.length; k++) {133z += stats[k]*stats[k];134}135double x = ((double)N / (double)SEQUENCE_SIZE) * (double)z - (double)SEQUENCE_SIZE;136double lo = chiSquaredBounds[N][0];137double hi = chiSquaredBounds[N][1];138boolean chiSquaredSuccess = ((lo < x) && (x < hi));139if (!chiSquaredSuccess) fail("chi-squared test failure for %s: x=%g (should be in [%g,%g])\n", id, x, lo, hi);140return chiSquaredSuccess;141}142143static boolean testRngChiSquared(String id, int N, IntSupplier theSupplier) {144if (chiSquaredTest(id, N, theSupplier)) return true;145fail("testRngChiSquared glitch");146return chiSquaredTest(id, N, theSupplier) && chiSquaredTest(id, N, theSupplier);147}148149static void tryIt(RandomGenerator rng, String kind, Function<String,BooleanSupplier> f) {150String id = rng.getClass().getName() + " " + kind;151// System.out.printf("Testing %s\n", id);152boolean success = f.apply(id).getAsBoolean();153if (!success) {154fail("*** Failure of %s\n", id);155}156}157158// To test one instance of an RandomGenerator with the BSI test suite, we test:159// nextInt()160// nextLong()161// nextBoolean()162// ints()163// longs()164// doubles()165// nextDouble()166// nextFloat()167168static final int[] testSizes = { 11, 13, 16, 17, 19, 23, 24 };169170static void testOneRng(RandomGenerator rng, int failureTolerance) {171String name = rng.getClass().getName();172for (int j = 0; j < testSizes.length; j++) {173int N = testSizes[j];174tryIt(rng, "nextInt(" + N + ")", (String id) -> () -> testRngChiSquared(id, N, () -> rng.nextInt(N)));175tryIt(rng, "nextInt(43, " + (N+43) + ")", (String id) -> () -> testRngChiSquared(id, N, () -> rng.nextInt(43, N+43) - 43));176tryIt(rng, "nextInt(-59, " + (N-59) + ")", (String id) -> () -> testRngChiSquared(id, N, () -> rng.nextInt(-59, N-59) + 59));177}178for (int j = 0; j < testSizes.length; j++) {179int N = testSizes[j];180tryIt(rng, "nextLong(" + N + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(rng.nextLong(N))));181tryIt(rng, "nextLong(43, " + (N+43) + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(rng.nextLong(43, N+43) - 43)));182tryIt(rng, "nextLong(-59, " + (N-59) + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(rng.nextLong(-59, N-59) + 59)));183}184for (int j = 0; j < testSizes.length; j++) {185int N = testSizes[j];186tryIt(rng, "nextFloat(" + N + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(rng.nextFloat(N)) % N));187tryIt(rng, "nextFloat(43, " + (N+43) + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(rng.nextFloat(43, N+43) - 43) % N));188tryIt(rng, "nextFloat(-59, " + (N-59) + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(rng.nextFloat(-59, N-59) + 59) % N));189}190for (int j = 0; j < testSizes.length; j++) {191int N = testSizes[j];192tryIt(rng, "nextDouble(" + N + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(rng.nextDouble(N)) % N));193tryIt(rng, "nextDouble(43, " + (N+43) + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(rng.nextDouble(43, N+43) - 43) % N));194tryIt(rng, "nextDouble(-59, " + (N-59) + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(rng.nextDouble(-59, N-59) + 59) % N));195}196for (int j = 0; j < testSizes.length; j++) {197int N = testSizes[j];198PrimitiveIterator.OfInt iter1 = rng.ints(0, N).iterator();199tryIt(rng, "ints(0, " + N + ")", (String id) -> () -> testRngChiSquared(id, N, iter1::next));200PrimitiveIterator.OfInt iter2 = rng.ints(43, N+43).iterator();201tryIt(rng, "ints(43, " + (N+43) + ")", (String id) -> () -> testRngChiSquared(id, N, () -> iter2.next() - 43));202PrimitiveIterator.OfInt iter3 = rng.ints(-59, N-59).iterator();203tryIt(rng, "ints(-59, " + (N-59) + ")", (String id) -> () -> testRngChiSquared(id, N, () -> iter3.next() + 59));204}205for (int j = 0; j < testSizes.length; j++) {206int N = testSizes[j];207PrimitiveIterator.OfLong iter1 = rng.longs(0, N).iterator();208tryIt(rng, "longs(0, " + N + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(iter1.next() + 0)));209PrimitiveIterator.OfLong iter2 = rng.longs(43, N+43).iterator();210tryIt(rng, "longs(43, " + (N+43) + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(iter2.next() - 43)));211PrimitiveIterator.OfLong iter3 = rng.longs(-59, N-59).iterator();212tryIt(rng, "longs(-59, " + (N-59) + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(iter3.next() + 59)));213}214for (int j = 0; j < testSizes.length; j++) {215int N = testSizes[j];216PrimitiveIterator.OfDouble iter1 = rng.doubles(0, N).iterator();217tryIt(rng, "doubles(0, " + N + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(iter1.next() + 0) % N));218PrimitiveIterator.OfDouble iter2 = rng.doubles(43, N+43).iterator();219tryIt(rng, "doubles(43, " + (N+43) + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(iter2.next() - 43) % N));220PrimitiveIterator.OfDouble iter3 = rng.doubles(-59, N-59).iterator();221tryIt(rng, "doubles(-59, " + (N-59) + ")", (String id) -> () -> testRngChiSquared(id, N, () -> (int)(iter3.next() + 59) % N));222}223}224225public static void main(String[] args) {226RandomGeneratorFactory.all().forEach(factory -> {227setRNG(factory.name());228229if (factory.name().equals("Random")) {230testOneRng(factory.create(417), 1);231} else {232testOneRng(factory.create(417), 0);233}234});235236exceptionOnFail();237}238239}240241242243