Add chi-squared test statistic calculator to random.c

Change-Id: I0a0f8c9aad1530d18c70c962e729e84948a074ee
Signed-off-by: Dave Barach <dave@barachs.net>
This commit is contained in:
Dave Barach
2017-12-12 10:22:27 -05:00
parent 4112e389ea
commit 0c332a3585
3 changed files with 108 additions and 1 deletions

View File

@ -37,11 +37,56 @@
#include <vppinfra/random.h> #include <vppinfra/random.h>
/* Default random seed for standalone version of library. /** \file Random number support
*/
/** \brief Default random seed for standalone version of library.
Value can be overridden by platform code from e.g. Value can be overridden by platform code from e.g.
machine's clock count register. */ machine's clock count register. */
u32 standalone_random_default_seed = 1; u32 standalone_random_default_seed = 1;
/**
* \brief Compute the X2 test statistic for a vector of counts.
* Each value element corresponds to a histogram bucket.
*
* Typical use-case: test the hypothesis that a set of octets
* are uniformly distributed (aka random).
*
* In a 1-dimensional use-case, the result should be compared
* with the critical value from chi square tables with
* vec_len(values) - 1 degrees of freedom.
*
* @param[in] values vector of histogram bucket values
* @return d - Pearson's X2 test statistic
*/
f64
clib_chisquare (u64 * values)
{
int i;
f64 d, delta_d, actual_frequency, expected_frequency;
u64 n_observations = 0;
ASSERT (vec_len (values));
for (i = 0; i < vec_len (values); i++)
n_observations += values[i];
expected_frequency = (1.0 / (f64) vec_len (values)) * (f64) n_observations;
d = 0.0;
for (i = 0; i < vec_len (values); i++)
{
actual_frequency = ((f64) values[i]);
delta_d = ((actual_frequency - expected_frequency)
* (actual_frequency - expected_frequency))
/ expected_frequency;
d += delta_d;
}
return d;
}
/* /*
* fd.io coding-style-patch-verification: ON * fd.io coding-style-patch-verification: ON
* *

View File

@ -167,6 +167,8 @@ random_string (u32 * seed, uword len)
return s; return s;
} }
f64 clib_chisquare (u64 * values);
#endif /* included_random_h */ #endif /* included_random_h */
/* /*

View File

@ -38,6 +38,42 @@
#include <vppinfra/format.h> #include <vppinfra/format.h>
#include <vppinfra/bitmap.h> #include <vppinfra/bitmap.h>
static u32 outcome_frequencies[] = {
8, 5, 9, 2, 7, 5,
};
int
test_chisquare (void)
{
u64 *values = 0;
int i;
f64 d, delta_d;
vec_validate (values, 5);
for (i = 0; i < 6; i++)
values[i] = (u64) outcome_frequencies[i];
d = clib_chisquare (values);
delta_d = d - 5.333;
if (delta_d < 0.0)
delta_d = -delta_d;
if (delta_d < 0.001)
{
fformat (stdout, "chisquare OK...\n");
return 0;
}
else
{
fformat (stdout, "chisquare BAD, d = %.3f\n", d);
return -1;
}
}
static u32 known_random_sequence[] = { static u32 known_random_sequence[] = {
0x00000000, 0x3c6ef35f, 0x47502932, 0xd1ccf6e9, 0x00000000, 0x3c6ef35f, 0x47502932, 0xd1ccf6e9,
0xaaf95334, 0x6252e503, 0x9f2ec686, 0x57fe6c2d, 0xaaf95334, 0x6252e503, 0x9f2ec686, 0x57fe6c2d,
@ -54,6 +90,8 @@ test_random_main (unformat_input_t * input)
uword print; uword print;
u32 seed; u32 seed;
u32 *seedp = &seed; u32 *seedp = &seed;
u64 *counts = 0;
f64 d;
/* first, check known sequence from Numerical Recipes in C, 2nd ed. /* first, check known sequence from Numerical Recipes in C, 2nd ed.
page 284 */ page 284 */
@ -118,6 +156,28 @@ test_random_main (unformat_input_t * input)
continue; continue;
} }
if (test_chisquare ())
return (-1);
/* Simple randomness tests based on X2 stats */
vec_validate (counts, 255);
for (i = 0; i < 1000000; i++)
{
u32 random_index;
u32 r = random_u32 (&seed);
random_index = r & 0xFF;
counts[random_index]++;
}
d = clib_chisquare (counts);
fformat (stdout, "%d random octets, chisquare stat d = %.3f\n", i, d);
vec_free (counts);
return 0; return 0;
} }