using System; using System.Collections.Generic; namespace Amphora.RandomComparisons { /// /// Counts how often each of the 64 bits is set. /// public static class BitBalance { public static Outcome Run(WordStream stream, long words) { var ones = new long[64]; for (long i = 0; i < words; i++) { ulong word = stream.Next(); for (int bit = 0; bit < 64; bit++) { ones[bit] += (long)((word >> bit) & 1); } } double standardDeviation = Math.Sqrt(words) / 2; double worstP = 1; int worstBit = 0; for (int bit = 0; bit < 64; bit++) { double p = Stats.NormalTwoSided((ones[bit] - words / 2.0) / standardDeviation); if (p < worstP) { worstP = p; worstBit = bit; } } // The worst of 64 bits is the one to report, so it is judged against 64 chances to look bad. return new Outcome(Stats.WorstOf(worstP, 64), "worst is bit " + worstBit + ", set in " + (100.0 * ones[worstBit] / words).ToString("0.000") + "% of " + words + " words"); } } /// /// Counts how often each combination of consecutive draws shows up. Planes and lattices in the output leave most /// combinations empty, which shows as a chi-square that is far too big. /// public static class SerialTest { /// /// The bits kept of each draw for tuples of 1 to 8 draws, chosen so the cells number from 2^14 to 2^18. /// public static readonly int[] BitsPerCoordinate = { 0, 16, 8, 6, 4, 3, 3, 2, 2 }; public const int MaximumDimensions = 8; public static Outcome Run(WordStream stream, Window window, int dimensions, int bitsPerCoordinate, long tuples) { int cells = 1 << (dimensions * bitsPerCoordinate); var counts = new int[cells]; for (long tuple = 0; tuple < tuples; tuple++) { int index = 0; for (int dimension = 0; dimension < dimensions; dimension++) { index = (index << bitsPerCoordinate) | (int)Windows.Take(stream.Next(), window, bitsPerCoordinate); } counts[index]++; } double expected = (double)tuples / cells; double statistic = 0; for (int cell = 0; cell < cells; cell++) { double difference = counts[cell] - expected; statistic += difference * difference; } statistic /= expected; return new Outcome(Stats.ChiSquareTwoSided(statistic, cells - 1), dimensions + " draws of " + bitsPerCoordinate + " bits, chi-square " + statistic.ToString("0.0") + " on " + (cells - 1) + " df"); } /// /// Runs the test for every tuple size and returns the worst. /// public static Outcome Series(WordStream stream, Window window, long tuples) { var outcomes = new List(); for (int dimensions = 1; dimensions <= MaximumDimensions; dimensions++) { outcomes.Add(Run(stream, window, dimensions, BitsPerCoordinate[dimensions], tuples)); } Outcome worst = Outcome.Worst(outcomes); return new Outcome(Stats.WorstOf(worst.P, MaximumDimensions), "worst of 1 to 8 draws: " + worst.Detail); } } }