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