xref: /llvm-project/libcxx/test/std/numerics/rand/rand.dist/rand.dist.bern/rand.dist.bern.negbin/eval.pass.cpp (revision 09e3a360581dc36d0820d3fb6da9bd7cfed87b5d)
1eb1c5037SNikolas Klauser //===----------------------------------------------------------------------===//
2eb1c5037SNikolas Klauser //
3eb1c5037SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4eb1c5037SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
5eb1c5037SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6eb1c5037SNikolas Klauser //
7eb1c5037SNikolas Klauser //===----------------------------------------------------------------------===//
8eb1c5037SNikolas Klauser //
9eb1c5037SNikolas Klauser // REQUIRES: long_tests
10eb1c5037SNikolas Klauser 
11f376a3bbSEric // This test is super slow, in particular with msan or tsan. In order to avoid timeouts and to
12f376a3bbSEric // spend less time waiting for this particular test to complete we compile with optimizations.
13f376a3bbSEric // ADDITIONAL_COMPILE_FLAGS(msan): -O1
14f376a3bbSEric // ADDITIONAL_COMPILE_FLAGS(tsan): -O1
15f376a3bbSEric 
16f376a3bbSEric // FIXME: This and other tests fail under GCC with optimizations enabled.
17f376a3bbSEric // More investigation is needed, but it appears that  GCC is performing more constant folding.
18f376a3bbSEric 
19eb1c5037SNikolas Klauser // <random>
20eb1c5037SNikolas Klauser 
21eb1c5037SNikolas Klauser // template<class IntType = int>
22eb1c5037SNikolas Klauser // class negative_binomial_distribution
23eb1c5037SNikolas Klauser 
24eb1c5037SNikolas Klauser // template<class _URNG> result_type operator()(_URNG& g);
25eb1c5037SNikolas Klauser 
26eb1c5037SNikolas Klauser #include <random>
27*09e3a360SLouis Dionne #include <cassert>
28*09e3a360SLouis Dionne #include <cmath>
29eb1c5037SNikolas Klauser #include <numeric>
30eb1c5037SNikolas Klauser #include <vector>
31eb1c5037SNikolas Klauser 
3207e984bcSLouis Dionne #include "test_macros.h"
3307e984bcSLouis Dionne 
34eb1c5037SNikolas Klauser template <class T>
3507e984bcSLouis Dionne T sqr(T x) {
36eb1c5037SNikolas Klauser     return x * x;
37eb1c5037SNikolas Klauser }
38eb1c5037SNikolas Klauser 
3907e984bcSLouis Dionne template <class T>
4007e984bcSLouis Dionne void test1() {
4107e984bcSLouis Dionne     typedef std::negative_binomial_distribution<T> D;
42eb1c5037SNikolas Klauser     typedef std::minstd_rand G;
43eb1c5037SNikolas Klauser     G g;
44eb1c5037SNikolas Klauser     D d(5, .25);
45eb1c5037SNikolas Klauser     const int N = 1000000;
4607e984bcSLouis Dionne     std::vector<typename D::result_type> u;
47eb1c5037SNikolas Klauser     for (int i = 0; i < N; ++i)
48eb1c5037SNikolas Klauser     {
4907e984bcSLouis Dionne         typename D::result_type v = d(g);
50eb1c5037SNikolas Klauser         assert(d.min() <= v && v <= d.max());
51eb1c5037SNikolas Klauser         u.push_back(v);
52eb1c5037SNikolas Klauser     }
53eb1c5037SNikolas Klauser     double mean = std::accumulate(u.begin(), u.end(),
54eb1c5037SNikolas Klauser                                           double(0)) / u.size();
55eb1c5037SNikolas Klauser     double var = 0;
56eb1c5037SNikolas Klauser     double skew = 0;
57eb1c5037SNikolas Klauser     double kurtosis = 0;
58eb1c5037SNikolas Klauser     for (unsigned i = 0; i < u.size(); ++i)
59eb1c5037SNikolas Klauser     {
60eb1c5037SNikolas Klauser         double dbl = (u[i] - mean);
61eb1c5037SNikolas Klauser         double d2 = sqr(dbl);
62eb1c5037SNikolas Klauser         var += d2;
63eb1c5037SNikolas Klauser         skew += dbl * d2;
64eb1c5037SNikolas Klauser         kurtosis += d2 * d2;
65eb1c5037SNikolas Klauser     }
66eb1c5037SNikolas Klauser     var /= u.size();
67eb1c5037SNikolas Klauser     double dev = std::sqrt(var);
68eb1c5037SNikolas Klauser     skew /= u.size() * dev * var;
69eb1c5037SNikolas Klauser     kurtosis /= u.size() * var * var;
70eb1c5037SNikolas Klauser     kurtosis -= 3;
71eb1c5037SNikolas Klauser     double x_mean = d.k() * (1 - d.p()) / d.p();
72eb1c5037SNikolas Klauser     double x_var = x_mean / d.p();
73eb1c5037SNikolas Klauser     double x_skew = (2 - d.p()) / std::sqrt(d.k() * (1 - d.p()));
74eb1c5037SNikolas Klauser     double x_kurtosis = 6. / d.k() + sqr(d.p()) / (d.k() * (1 - d.p()));
75eb1c5037SNikolas Klauser     assert(std::abs((mean - x_mean) / x_mean) < 0.01);
76eb1c5037SNikolas Klauser     assert(std::abs((var - x_var) / x_var) < 0.01);
77eb1c5037SNikolas Klauser     assert(std::abs((skew - x_skew) / x_skew) < 0.01);
7876aa042dSMatt Stephanson     assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.03);
79eb1c5037SNikolas Klauser }
80eb1c5037SNikolas Klauser 
8107e984bcSLouis Dionne template <class T>
8207e984bcSLouis Dionne void test2() {
8307e984bcSLouis Dionne     typedef std::negative_binomial_distribution<T> D;
84eb1c5037SNikolas Klauser     typedef std::mt19937 G;
85eb1c5037SNikolas Klauser     G g;
86eb1c5037SNikolas Klauser     D d(30, .03125);
87eb1c5037SNikolas Klauser     const int N = 1000000;
8807e984bcSLouis Dionne     std::vector<typename D::result_type> u;
89eb1c5037SNikolas Klauser     for (int i = 0; i < N; ++i)
90eb1c5037SNikolas Klauser     {
9107e984bcSLouis Dionne         typename D::result_type v = d(g);
92eb1c5037SNikolas Klauser         assert(d.min() <= v && v <= d.max());
93eb1c5037SNikolas Klauser         u.push_back(v);
94eb1c5037SNikolas Klauser     }
95eb1c5037SNikolas Klauser     double mean = std::accumulate(u.begin(), u.end(),
96eb1c5037SNikolas Klauser                                           double(0)) / u.size();
97eb1c5037SNikolas Klauser     double var = 0;
98eb1c5037SNikolas Klauser     double skew = 0;
99eb1c5037SNikolas Klauser     double kurtosis = 0;
100eb1c5037SNikolas Klauser     for (unsigned i = 0; i < u.size(); ++i)
101eb1c5037SNikolas Klauser     {
102eb1c5037SNikolas Klauser         double dbl = (u[i] - mean);
103eb1c5037SNikolas Klauser         double d2 = sqr(dbl);
104eb1c5037SNikolas Klauser         var += d2;
105eb1c5037SNikolas Klauser         skew += dbl * d2;
106eb1c5037SNikolas Klauser         kurtosis += d2 * d2;
107eb1c5037SNikolas Klauser     }
108eb1c5037SNikolas Klauser     var /= u.size();
109eb1c5037SNikolas Klauser     double dev = std::sqrt(var);
110eb1c5037SNikolas Klauser     skew /= u.size() * dev * var;
111eb1c5037SNikolas Klauser     kurtosis /= u.size() * var * var;
112eb1c5037SNikolas Klauser     kurtosis -= 3;
113eb1c5037SNikolas Klauser     double x_mean = d.k() * (1 - d.p()) / d.p();
114eb1c5037SNikolas Klauser     double x_var = x_mean / d.p();
115eb1c5037SNikolas Klauser     double x_skew = (2 - d.p()) / std::sqrt(d.k() * (1 - d.p()));
116eb1c5037SNikolas Klauser     double x_kurtosis = 6. / d.k() + sqr(d.p()) / (d.k() * (1 - d.p()));
117eb1c5037SNikolas Klauser     assert(std::abs((mean - x_mean) / x_mean) < 0.01);
118eb1c5037SNikolas Klauser     assert(std::abs((var - x_var) / x_var) < 0.01);
11976aa042dSMatt Stephanson     assert(std::abs((skew - x_skew) / x_skew) < 0.02);
12076aa042dSMatt Stephanson     assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.1);
121eb1c5037SNikolas Klauser }
122eb1c5037SNikolas Klauser 
12307e984bcSLouis Dionne template <class T>
12407e984bcSLouis Dionne void test3() {
12507e984bcSLouis Dionne     typedef std::negative_binomial_distribution<T> D;
126eb1c5037SNikolas Klauser     typedef std::mt19937 G;
127eb1c5037SNikolas Klauser     G g;
128eb1c5037SNikolas Klauser     D d(40, .25);
129eb1c5037SNikolas Klauser     const int N = 1000000;
13007e984bcSLouis Dionne     std::vector<typename D::result_type> u;
131eb1c5037SNikolas Klauser     for (int i = 0; i < N; ++i)
132eb1c5037SNikolas Klauser     {
13307e984bcSLouis Dionne         typename D::result_type v = d(g);
134eb1c5037SNikolas Klauser         assert(d.min() <= v && v <= d.max());
135eb1c5037SNikolas Klauser         u.push_back(v);
136eb1c5037SNikolas Klauser     }
137eb1c5037SNikolas Klauser     double mean = std::accumulate(u.begin(), u.end(),
138eb1c5037SNikolas Klauser                                           double(0)) / u.size();
139eb1c5037SNikolas Klauser     double var = 0;
140eb1c5037SNikolas Klauser     double skew = 0;
141eb1c5037SNikolas Klauser     double kurtosis = 0;
142eb1c5037SNikolas Klauser     for (unsigned i = 0; i < u.size(); ++i)
143eb1c5037SNikolas Klauser     {
144eb1c5037SNikolas Klauser         double dbl = (u[i] - mean);
145eb1c5037SNikolas Klauser         double d2 = sqr(dbl);
146eb1c5037SNikolas Klauser         var += d2;
147eb1c5037SNikolas Klauser         skew += dbl * d2;
148eb1c5037SNikolas Klauser         kurtosis += d2 * d2;
149eb1c5037SNikolas Klauser     }
150eb1c5037SNikolas Klauser     var /= u.size();
151eb1c5037SNikolas Klauser     double dev = std::sqrt(var);
152eb1c5037SNikolas Klauser     skew /= u.size() * dev * var;
153eb1c5037SNikolas Klauser     kurtosis /= u.size() * var * var;
154eb1c5037SNikolas Klauser     kurtosis -= 3;
155eb1c5037SNikolas Klauser     double x_mean = d.k() * (1 - d.p()) / d.p();
156eb1c5037SNikolas Klauser     double x_var = x_mean / d.p();
157eb1c5037SNikolas Klauser     double x_skew = (2 - d.p()) / std::sqrt(d.k() * (1 - d.p()));
158eb1c5037SNikolas Klauser     double x_kurtosis = 6. / d.k() + sqr(d.p()) / (d.k() * (1 - d.p()));
159eb1c5037SNikolas Klauser     assert(std::abs((mean - x_mean) / x_mean) < 0.01);
160eb1c5037SNikolas Klauser     assert(std::abs((var - x_var) / x_var) < 0.01);
16176aa042dSMatt Stephanson     assert(std::abs((skew - x_skew) / x_skew) < 0.02);
16276aa042dSMatt Stephanson     assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.08);
163eb1c5037SNikolas Klauser }
164eb1c5037SNikolas Klauser 
16507e984bcSLouis Dionne template <class T>
16607e984bcSLouis Dionne void test4() {
16707e984bcSLouis Dionne     typedef std::negative_binomial_distribution<T> D;
168eb1c5037SNikolas Klauser     typedef std::mt19937 G;
169eb1c5037SNikolas Klauser     G g;
170eb1c5037SNikolas Klauser     D d(40, 1);
171eb1c5037SNikolas Klauser     const int N = 1000;
17207e984bcSLouis Dionne     std::vector<typename D::result_type> u;
173eb1c5037SNikolas Klauser     for (int i = 0; i < N; ++i)
174eb1c5037SNikolas Klauser     {
17507e984bcSLouis Dionne         typename D::result_type v = d(g);
176eb1c5037SNikolas Klauser         assert(d.min() <= v && v <= d.max());
177eb1c5037SNikolas Klauser         u.push_back(v);
178eb1c5037SNikolas Klauser     }
179eb1c5037SNikolas Klauser     double mean = std::accumulate(u.begin(), u.end(),
180eb1c5037SNikolas Klauser                                           double(0)) / u.size();
181eb1c5037SNikolas Klauser     double var = 0;
182eb1c5037SNikolas Klauser     double skew = 0;
183eb1c5037SNikolas Klauser     double kurtosis = 0;
184eb1c5037SNikolas Klauser     for (unsigned i = 0; i < u.size(); ++i)
185eb1c5037SNikolas Klauser     {
186eb1c5037SNikolas Klauser         double dbl = (u[i] - mean);
187eb1c5037SNikolas Klauser         double d2 = sqr(dbl);
188eb1c5037SNikolas Klauser         var += d2;
189eb1c5037SNikolas Klauser         skew += dbl * d2;
190eb1c5037SNikolas Klauser         kurtosis += d2 * d2;
191eb1c5037SNikolas Klauser     }
192eb1c5037SNikolas Klauser     var /= u.size();
193eb1c5037SNikolas Klauser     double dev = std::sqrt(var);
194eb1c5037SNikolas Klauser     skew /= u.size() * dev * var;
195eb1c5037SNikolas Klauser     kurtosis /= u.size() * var * var;
196eb1c5037SNikolas Klauser     kurtosis -= 3;
197eb1c5037SNikolas Klauser     double x_mean = d.k() * (1 - d.p()) / d.p();
198eb1c5037SNikolas Klauser     double x_var = x_mean / d.p();
199eb1c5037SNikolas Klauser     double x_skew = (2 - d.p()) / std::sqrt(d.k() * (1 - d.p()));
200eb1c5037SNikolas Klauser     double x_kurtosis = 6. / d.k() + sqr(d.p()) / (d.k() * (1 - d.p()));
201eb1c5037SNikolas Klauser     assert(mean == x_mean);
202eb1c5037SNikolas Klauser     assert(var == x_var);
203eb1c5037SNikolas Klauser     // assert(skew == x_skew);
204eb1c5037SNikolas Klauser     (void)skew; (void)x_skew;
205eb1c5037SNikolas Klauser     // assert(kurtosis == x_kurtosis);
206eb1c5037SNikolas Klauser     (void)kurtosis; (void)x_kurtosis;
207eb1c5037SNikolas Klauser }
208eb1c5037SNikolas Klauser 
20907e984bcSLouis Dionne template <class T>
21007e984bcSLouis Dionne void test5() {
21107e984bcSLouis Dionne     typedef std::negative_binomial_distribution<T> D;
212eb1c5037SNikolas Klauser     typedef std::mt19937 G;
213eb1c5037SNikolas Klauser     G g;
21407e984bcSLouis Dionne     D d(127, 0.5);
215eb1c5037SNikolas Klauser     const int N = 1000000;
21607e984bcSLouis Dionne     std::vector<typename D::result_type> u;
217eb1c5037SNikolas Klauser     for (int i = 0; i < N; ++i)
218eb1c5037SNikolas Klauser     {
21907e984bcSLouis Dionne         typename D::result_type v = d(g);
220eb1c5037SNikolas Klauser         assert(d.min() <= v && v <= d.max());
221eb1c5037SNikolas Klauser         u.push_back(v);
222eb1c5037SNikolas Klauser     }
223eb1c5037SNikolas Klauser     double mean = std::accumulate(u.begin(), u.end(),
224eb1c5037SNikolas Klauser                                           double(0)) / u.size();
225eb1c5037SNikolas Klauser     double var = 0;
226eb1c5037SNikolas Klauser     double skew = 0;
227eb1c5037SNikolas Klauser     double kurtosis = 0;
228eb1c5037SNikolas Klauser     for (unsigned i = 0; i < u.size(); ++i)
229eb1c5037SNikolas Klauser     {
230eb1c5037SNikolas Klauser         double dbl = (u[i] - mean);
231eb1c5037SNikolas Klauser         double d2 = sqr(dbl);
232eb1c5037SNikolas Klauser         var += d2;
233eb1c5037SNikolas Klauser         skew += dbl * d2;
234eb1c5037SNikolas Klauser         kurtosis += d2 * d2;
235eb1c5037SNikolas Klauser     }
236eb1c5037SNikolas Klauser     var /= u.size();
237eb1c5037SNikolas Klauser     double dev = std::sqrt(var);
238eb1c5037SNikolas Klauser     skew /= u.size() * dev * var;
239eb1c5037SNikolas Klauser     kurtosis /= u.size() * var * var;
240eb1c5037SNikolas Klauser     kurtosis -= 3;
241eb1c5037SNikolas Klauser     double x_mean = d.k() * (1 - d.p()) / d.p();
242eb1c5037SNikolas Klauser     double x_var = x_mean / d.p();
243eb1c5037SNikolas Klauser     double x_skew = (2 - d.p()) / std::sqrt(d.k() * (1 - d.p()));
244eb1c5037SNikolas Klauser     double x_kurtosis = 6. / d.k() + sqr(d.p()) / (d.k() * (1 - d.p()));
245eb1c5037SNikolas Klauser     assert(std::abs((mean - x_mean) / x_mean) < 0.01);
246eb1c5037SNikolas Klauser     assert(std::abs((var - x_var) / x_var) < 0.01);
24776aa042dSMatt Stephanson     assert(std::abs((skew - x_skew) / x_skew) < 0.02);
24876aa042dSMatt Stephanson     assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.3);
249eb1c5037SNikolas Klauser }
250eb1c5037SNikolas Klauser 
25107e984bcSLouis Dionne template <class T>
25207e984bcSLouis Dionne void test6() {
25307e984bcSLouis Dionne     typedef std::negative_binomial_distribution<T> D;
254eb1c5037SNikolas Klauser     typedef std::mt19937 G;
255eb1c5037SNikolas Klauser     G g;
256eb1c5037SNikolas Klauser     D d(1, 0.05);
257eb1c5037SNikolas Klauser     const int N = 1000000;
25807e984bcSLouis Dionne     std::vector<typename D::result_type> u;
259eb1c5037SNikolas Klauser     for (int i = 0; i < N; ++i)
260eb1c5037SNikolas Klauser     {
26107e984bcSLouis Dionne         typename D::result_type v = d(g);
262eb1c5037SNikolas Klauser         assert(d.min() <= v && v <= d.max());
263eb1c5037SNikolas Klauser         u.push_back(v);
264eb1c5037SNikolas Klauser     }
265eb1c5037SNikolas Klauser     double mean = std::accumulate(u.begin(), u.end(),
266eb1c5037SNikolas Klauser                                           double(0)) / u.size();
267eb1c5037SNikolas Klauser     double var = 0;
268eb1c5037SNikolas Klauser     double skew = 0;
269eb1c5037SNikolas Klauser     double kurtosis = 0;
270eb1c5037SNikolas Klauser     for (unsigned i = 0; i < u.size(); ++i)
271eb1c5037SNikolas Klauser     {
272eb1c5037SNikolas Klauser         double dbl = (u[i] - mean);
273eb1c5037SNikolas Klauser         double d2 = sqr(dbl);
274eb1c5037SNikolas Klauser         var += d2;
275eb1c5037SNikolas Klauser         skew += dbl * d2;
276eb1c5037SNikolas Klauser         kurtosis += d2 * d2;
277eb1c5037SNikolas Klauser     }
278eb1c5037SNikolas Klauser     var /= u.size();
279eb1c5037SNikolas Klauser     double dev = std::sqrt(var);
280eb1c5037SNikolas Klauser     skew /= u.size() * dev * var;
281eb1c5037SNikolas Klauser     kurtosis /= u.size() * var * var;
282eb1c5037SNikolas Klauser     kurtosis -= 3;
283eb1c5037SNikolas Klauser     double x_mean = d.k() * (1 - d.p()) / d.p();
284eb1c5037SNikolas Klauser     double x_var = x_mean / d.p();
285eb1c5037SNikolas Klauser     double x_skew = (2 - d.p()) / std::sqrt(d.k() * (1 - d.p()));
286eb1c5037SNikolas Klauser     double x_kurtosis = 6. / d.k() + sqr(d.p()) / (d.k() * (1 - d.p()));
287eb1c5037SNikolas Klauser     assert(std::abs((mean - x_mean) / x_mean) < 0.01);
288eb1c5037SNikolas Klauser     assert(std::abs((var - x_var) / x_var) < 0.01);
289eb1c5037SNikolas Klauser     assert(std::abs((skew - x_skew) / x_skew) < 0.01);
290eb1c5037SNikolas Klauser     assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.03);
291eb1c5037SNikolas Klauser }
292eb1c5037SNikolas Klauser 
29307e984bcSLouis Dionne template <class T>
29407e984bcSLouis Dionne void tests() {
29507e984bcSLouis Dionne     test1<T>();
29607e984bcSLouis Dionne     test2<T>();
29707e984bcSLouis Dionne     test3<T>();
29807e984bcSLouis Dionne     test4<T>();
29907e984bcSLouis Dionne     test5<T>();
30007e984bcSLouis Dionne     test6<T>();
30107e984bcSLouis Dionne }
30207e984bcSLouis Dionne 
30307e984bcSLouis Dionne int main(int, char**) {
30407e984bcSLouis Dionne     tests<short>();
30507e984bcSLouis Dionne     tests<int>();
30607e984bcSLouis Dionne     tests<long>();
30707e984bcSLouis Dionne     tests<long long>();
30807e984bcSLouis Dionne 
30907e984bcSLouis Dionne     tests<unsigned short>();
31007e984bcSLouis Dionne     tests<unsigned int>();
31107e984bcSLouis Dionne     tests<unsigned long>();
31207e984bcSLouis Dionne     tests<unsigned long long>();
31307e984bcSLouis Dionne 
31407e984bcSLouis Dionne #if defined(_LIBCPP_VERSION) // extension
31507e984bcSLouis Dionne     // TODO: std::negative_binomial_distribution currently doesn't work reliably with small types.
31607e984bcSLouis Dionne     // tests<int8_t>();
31707e984bcSLouis Dionne     // tests<uint8_t>();
31807e984bcSLouis Dionne #if !defined(TEST_HAS_NO_INT128)
31907e984bcSLouis Dionne     tests<__int128_t>();
32007e984bcSLouis Dionne     tests<__uint128_t>();
32107e984bcSLouis Dionne #endif
32207e984bcSLouis Dionne #endif
323eb1c5037SNikolas Klauser 
324eb1c5037SNikolas Klauser     return 0;
325eb1c5037SNikolas Klauser }
326