Flutter Engine
The Flutter Engine
RandomTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
10#include "src/base/SkRandom.h"
11#include "src/base/SkTSort.h"
12#include "tests/Test.h"
13
14#include <cmath>
15#include <cstring>
16
17static bool anderson_darling_test(double p[32]) {
18 // Min and max Anderson-Darling values allowable for k=32
19 const double kADMin32 = 0.202; // p-value of ~0.1
20 const double kADMax32 = 3.89; // p-value of ~0.99
21
22 // sort p values
23 SkTQSort<double>(p, p + 32);
24
25 // and compute Anderson-Darling statistic to ensure these are uniform
26 double s = 0.0;
27 for(int k = 0; k < 32; k++) {
28 double v = p[k]*(1.0 - p[31-k]);
29 if (v < 1.0e-30) {
30 v = 1.0e-30;
31 }
32 s += (2.0*(k+1)-1.0)*log(v);
33 }
34 double a2 = -32.0 - 0.03125*s;
35
36 return (kADMin32 < a2 && a2 < kADMax32);
37}
38
39static bool chi_square_test(int bins[256], int e) {
40 // Min and max chisquare values allowable
41 const double kChiSqMin256 = 206.3179; // probability of chance = 0.99 with k=256
42 const double kChiSqMax256 = 311.5603; // probability of chance = 0.01 with k=256
43
44 // compute chi-square
45 double chi2 = 0.0;
46 for (int j = 0; j < 256; ++j) {
47 double delta = bins[j] - e;
48 chi2 += delta*delta/e;
49 }
50
51 return (kChiSqMin256 < chi2 && chi2 < kChiSqMax256);
52}
53
54// Approximation to the normal distribution CDF
55// From Waissi and Rossin, 1996
56static double normal_cdf(double z) {
57 double t = ((-0.0004406*z*z* + 0.0418198)*z*z + 0.9)*z;
58 t *= -1.77245385091; // -sqrt(PI)
59 double p = 1.0/(1.0 + exp(t));
60
61 return p;
62}
63
65 int bins[256];
66 memset(bins, 0, sizeof(int)*256);
67
68 SkRandom rand;
69 for (int i = 0; i < 256*10000; ++i) {
70 bins[(rand.nextU() >> shift) & 0xff]++;
71 }
72
74}
75
77 int bins[256];
78 memset(bins, 0, sizeof(int)*256);
79
80 SkRandom rand;
81 for (int i = 0; i < 256*10000; ++i) {
82 float f = rand.nextF();
83 REPORTER_ASSERT(reporter, 0.0f <= f && f < 1.0f);
84 bins[(int)(f*256.f)]++;
85 }
87
88 double p[32];
89 for (int j = 0; j < 32; ++j) {
90 float f = rand.nextF();
91 REPORTER_ASSERT(reporter, 0.0f <= f && f < 1.0f);
92 p[j] = f;
93 }
95}
96
97// This is a test taken from tuftests by Marsaglia and Tsang. The idea here is that
98// we are using the random bit generated from a single shift position to generate
99// "strings" of 16 bits in length, shifting the string and adding a new bit with each
100// iteration. We track the numbers generated. The ones that we don't generate will
101// have a normal distribution with mean ~24108 and standard deviation ~127. By
102// creating a z-score (# of deviations from the mean) for one iteration of this step
103// we can determine its probability.
104//
105// The original test used 26 bit strings, but is somewhat slow. This version uses 16
106// bits which is less rigorous but much faster to generate.
108 const int kWordWidth = 16;
109 const double kMean = 24108.0;
110 const double kStandardDeviation = 127.0;
111 const int kN = (1 << kWordWidth);
112 const int kNumEntries = kN >> 5; // dividing by 32
113 unsigned int entries[kNumEntries];
114
115 SkRandom rand;
116 memset(entries, 0, sizeof(unsigned int)*kNumEntries);
117 // pre-seed our string value
118 int value = 0;
119 for (int i = 0; i < kWordWidth-1; ++i) {
120 value <<= 1;
121 unsigned int rnd = rand.nextU();
122 value |= ((rnd >> shift) & 0x1);
123 }
124
125 // now make some strings and track them
126 for (int i = 0; i < kN; ++i) {
127 value = SkLeftShift(value, 1);
128 unsigned int rnd = rand.nextU();
129 value |= ((rnd >> shift) & 0x1);
130
131 int index = value & (kNumEntries-1);
132 SkASSERT(index < kNumEntries);
133 int entry_shift = (value >> (kWordWidth-5)) & 0x1f;
134 entries[index] |= (0x1 << entry_shift);
135 }
136
137 // count entries
138 int total = 0;
139 for (int i = 0; i < kNumEntries; ++i) {
140 unsigned int entry = entries[i];
141 while (entry) {
142 total += (entry & 0x1);
143 entry >>= 1;
144 }
145 }
146
147 // convert counts to normal distribution z-score
148 double z = ((kN-total)-kMean)/kStandardDeviation;
149
150 // compute probability from normal distibution CDF
151 double p = normal_cdf(z);
152
153 REPORTER_ASSERT(reporter, 0.01 < p && p < 0.99);
154 return p;
155}
156
158
159 double p[32];
160 for (int bit_position = 0; bit_position < 32; ++bit_position) {
161 p[bit_position] = test_single_gorilla(reporter, bit_position);
162 }
163
165}
166
168 SkRandom rand;
169
170 // just to make sure we don't crash in this case
171 (void) rand.nextRangeU(0, 0xffffffff);
172
173 // check a case to see if it's uniform
174 int bins[256];
175 memset(bins, 0, sizeof(int)*256);
176 for (int i = 0; i < 256*10000; ++i) {
177 unsigned int u = rand.nextRangeU(17, 17+255);
178 REPORTER_ASSERT(reporter, 17 <= u && u <= 17+255);
179 bins[u - 17]++;
180 }
181
183}
184
186 // check uniform distributions of each byte in 32-bit word
191
193
195
197}
reporter
Definition: FontMgrTest.cpp:39
DEF_TEST(Random, reporter)
Definition: RandomTest.cpp:185
static double normal_cdf(double z)
Definition: RandomTest.cpp:56
static double test_single_gorilla(skiatest::Reporter *reporter, int shift)
Definition: RandomTest.cpp:107
static void test_random_byte(skiatest::Reporter *reporter, int shift)
Definition: RandomTest.cpp:64
static void test_random_float(skiatest::Reporter *reporter)
Definition: RandomTest.cpp:76
static bool chi_square_test(int bins[256], int e)
Definition: RandomTest.cpp:39
static bool anderson_darling_test(double p[32])
Definition: RandomTest.cpp:17
static void test_range(skiatest::Reporter *reporter)
Definition: RandomTest.cpp:167
static void test_gorilla(skiatest::Reporter *reporter)
Definition: RandomTest.cpp:157
#define SkASSERT(cond)
Definition: SkAssert.h:116
static constexpr int32_t SkLeftShift(int32_t value, int32_t shift)
Definition: SkMath.h:37
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
uint32_t nextU()
Definition: SkRandom.h:42
float nextF()
Definition: SkRandom.h:55
uint32_t nextRangeU(uint32_t min, uint32_t max)
Definition: SkRandom.h:80
struct MyStruct s
uint8_t value