1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// REQUIRES: long_tests
// <random>
// template<class _IntType = int>
// class uniform_int_distribution
// template<class _URNG> result_type operator()(_URNG& g);
#include <random>
#include <cassert>
#include <climits>
#include <cstddef>
#include <limits>
#include <numeric>
#include <vector>
#include "test_macros.h"
// The __int128 conversions to/from floating point crash on MinGW on x86_64.
// This is fixed in Clang 14 by https://reviews.llvm.org/D110413.
#if defined(__x86_64__) && defined(__MINGW32__) && defined(__clang_major__) && __clang_major__ < 14
#define TEST_BUGGY_I128_FP
#endif
template <class T>
T sqr(T x) {
return x * x;
}
template <class ResultType, class EngineType>
void test_statistics(ResultType a, ResultType b) {
ASSERT_SAME_TYPE(typename std::uniform_int_distribution<ResultType>::result_type, ResultType);
EngineType g;
std::uniform_int_distribution<ResultType> dist(a, b);
assert(dist.a() == a);
assert(dist.b() == b);
std::vector<ResultType> u;
for (int i = 0; i < 10000; ++i) {
ResultType v = dist(g);
assert(a <= v && v <= b);
u.push_back(v);
}
// Quick check: The chance of getting *no* hits in any given tenth of the range
// is (0.9)^10000, or "ultra-astronomically low."
bool bottom_tenth = false;
bool top_tenth = false;
for (std::size_t i = 0; i < u.size(); ++i) {
bottom_tenth = bottom_tenth || (u[i] <= (a + (b / 10) - (a / 10)));
top_tenth = top_tenth || (u[i] >= (b - (b / 10) + (a / 10)));
}
assert(bottom_tenth); // ...is populated
assert(top_tenth); // ...is populated
// Now do some more involved statistical math.
double mean = std::accumulate(u.begin(), u.end(), 0.0) / u.size();
double var = 0;
double skew = 0;
double kurtosis = 0;
for (std::size_t i = 0; i < u.size(); ++i) {
double dbl = (u[i] - mean);
double d2 = dbl * dbl;
var += d2;
skew += dbl * d2;
kurtosis += d2 * d2;
}
var /= u.size();
double dev = std::sqrt(var);
skew /= u.size() * dev * var;
kurtosis /= u.size() * var * var;
double expected_mean = double(a) + double(b)/2 - double(a)/2;
double expected_var = (sqr(double(b) - double(a) + 1) - 1) / 12;
double range = double(b) - double(a) + 1.0;
assert(range > range / 10); // i.e., it's not infinity
assert(std::abs(mean - expected_mean) < range / 100);
assert(std::abs(var - expected_var) < expected_var / 50);
assert(-0.1 < skew && skew < 0.1);
assert(1.6 < kurtosis && kurtosis < 2.0);
}
template <class ResultType, class EngineType>
void test_statistics() {
test_statistics<ResultType, EngineType>(0, std::numeric_limits<ResultType>::max());
}
int main(int, char**)
{
test_statistics<int, std::minstd_rand0>();
test_statistics<int, std::minstd_rand>();
test_statistics<int, std::mt19937>();
test_statistics<int, std::mt19937_64>();
test_statistics<int, std::ranlux24_base>();
test_statistics<int, std::ranlux48_base>();
test_statistics<int, std::ranlux24>();
test_statistics<int, std::ranlux48>();
test_statistics<int, std::knuth_b>();
test_statistics<int, std::minstd_rand0>(-6, 106);
test_statistics<int, std::minstd_rand>(5, 100);
test_statistics<short, std::minstd_rand0>();
test_statistics<int, std::minstd_rand0>();
test_statistics<long, std::minstd_rand0>();
test_statistics<long long, std::minstd_rand0>();
test_statistics<unsigned short, std::minstd_rand0>();
test_statistics<unsigned int, std::minstd_rand0>();
test_statistics<unsigned long, std::minstd_rand0>();
test_statistics<unsigned long long, std::minstd_rand0>();
test_statistics<short, std::minstd_rand0>(SHRT_MIN, SHRT_MAX);
#if defined(_LIBCPP_VERSION) // extension
test_statistics<int8_t, std::minstd_rand0>();
test_statistics<uint8_t, std::minstd_rand0>();
#if !defined(TEST_HAS_NO_INT128) && !defined(TEST_BUGGY_I128_FP)
test_statistics<__int128_t, std::minstd_rand0>();
test_statistics<__uint128_t, std::minstd_rand0>();
test_statistics<__int128_t, std::minstd_rand0>(-100, 900);
test_statistics<__int128_t, std::minstd_rand0>(0, UINT64_MAX);
test_statistics<__int128_t, std::minstd_rand0>(std::numeric_limits<__int128_t>::min(), std::numeric_limits<__int128_t>::max());
test_statistics<__uint128_t, std::minstd_rand0>(0, UINT64_MAX);
#endif
#endif
return 0;
}
|