• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 poisson_distribution
15 
16 // template<class _URNG> result_type operator()(_URNG& g);
17 
18 #include <random>
19 #include <cassert>
20 #include <vector>
21 #include <numeric>
22 
23 #include "test_macros.h"
24 
25 template <class T>
26 inline
27 T
sqr(T x)28 sqr(T x)
29 {
30     return x * x;
31 }
32 
test_bad_ranges()33 void test_bad_ranges() {
34   // Test cases where the mean is around the largest representable integer for
35   // `result_type`. These cases don't generate valid poisson distributions, but
36   // at least they don't blow up.
37   std::mt19937 eng;
38 
39   {
40     std::poisson_distribution<std::int16_t> distribution(32710.9);
41     for (int i=0; i < 1000; ++i) {
42       volatile std::int16_t res = distribution(eng);
43       ((void)res);
44     }
45   }
46   {
47     std::poisson_distribution<std::int16_t> distribution(std::numeric_limits<std::int16_t>::max());
48     for (int i=0; i < 1000; ++i) {
49       volatile std::int16_t res = distribution(eng);
50       ((void)res);
51     }
52   }
53   {
54     std::poisson_distribution<std::int16_t> distribution(
55     static_cast<double>(std::numeric_limits<std::int16_t>::max()) + 10);
56     for (int i=0; i < 1000; ++i) {
57       volatile std::int16_t res = distribution(eng);
58       ((void)res);
59     }
60   }
61   {
62     std::poisson_distribution<std::int16_t> distribution(
63       static_cast<double>(std::numeric_limits<std::int16_t>::max()) * 2);
64       for (int i=0; i < 1000; ++i) {
65         volatile std::int16_t res = distribution(eng);
66         ((void)res);
67       }
68   }
69   {
70     // We convert `INF` to `DBL_MAX` otherwise the distribution will hang.
71     std::poisson_distribution<std::int16_t> distribution(std::numeric_limits<double>::infinity());
72     for (int i=0; i < 1000; ++i) {
73       volatile std::int16_t res = distribution(eng);
74       ((void)res);
75     }
76   }
77   {
78     std::poisson_distribution<std::int16_t> distribution(0);
79     for (int i=0; i < 1000; ++i) {
80       volatile std::int16_t res = distribution(eng);
81       ((void)res);
82     }
83   }
84   {
85     // We convert `INF` to `DBL_MAX` otherwise the distribution will hang.
86     std::poisson_distribution<std::int16_t> distribution(-100);
87     for (int i=0; i < 1000; ++i) {
88       volatile std::int16_t res = distribution(eng);
89       ((void)res);
90     }
91   }
92 }
93 
main(int,char **)94 int main(int, char**)
95 {
96     {
97         typedef std::poisson_distribution<> D;
98         typedef std::minstd_rand G;
99         G g;
100         D d(2);
101         const int N = 100000;
102         std::vector<double> u;
103         for (int i = 0; i < N; ++i)
104         {
105             D::result_type v = d(g);
106             assert(d.min() <= v && v <= d.max());
107             u.push_back(v);
108         }
109         double mean = std::accumulate(u.begin(), u.end(), 0.0) / u.size();
110         double var = 0;
111         double skew = 0;
112         double kurtosis = 0;
113         for (unsigned i = 0; i < u.size(); ++i)
114         {
115             double dbl = (u[i] - mean);
116             double d2 = sqr(dbl);
117             var += d2;
118             skew += dbl * d2;
119             kurtosis += d2 * d2;
120         }
121         var /= u.size();
122         double dev = std::sqrt(var);
123         skew /= u.size() * dev * var;
124         kurtosis /= u.size() * var * var;
125         kurtosis -= 3;
126         double x_mean = d.mean();
127         double x_var = d.mean();
128         double x_skew = 1 / std::sqrt(x_var);
129         double x_kurtosis = 1 / x_var;
130         assert(std::abs((mean - x_mean) / x_mean) < 0.01);
131         assert(std::abs((var - x_var) / x_var) < 0.01);
132         assert(std::abs((skew - x_skew) / x_skew) < 0.01);
133         assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.03);
134     }
135     {
136         typedef std::poisson_distribution<> D;
137         typedef std::minstd_rand G;
138         G g;
139         D d(0.75);
140         const int N = 100000;
141         std::vector<double> u;
142         for (int i = 0; i < N; ++i)
143         {
144             D::result_type v = d(g);
145             assert(d.min() <= v && v <= d.max());
146             u.push_back(v);
147         }
148         double mean = std::accumulate(u.begin(), u.end(), 0.0) / u.size();
149         double var = 0;
150         double skew = 0;
151         double kurtosis = 0;
152         for (unsigned i = 0; i < u.size(); ++i)
153         {
154             double dbl = (u[i] - mean);
155             double d2 = sqr(dbl);
156             var += d2;
157             skew += dbl * d2;
158             kurtosis += d2 * d2;
159         }
160         var /= u.size();
161         double dev = std::sqrt(var);
162         skew /= u.size() * dev * var;
163         kurtosis /= u.size() * var * var;
164         kurtosis -= 3;
165         double x_mean = d.mean();
166         double x_var = d.mean();
167         double x_skew = 1 / std::sqrt(x_var);
168         double x_kurtosis = 1 / x_var;
169         assert(std::abs((mean - x_mean) / x_mean) < 0.01);
170         assert(std::abs((var - x_var) / x_var) < 0.01);
171         assert(std::abs((skew - x_skew) / x_skew) < 0.01);
172         assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.04);
173     }
174     {
175         typedef std::poisson_distribution<> D;
176         typedef std::mt19937 G;
177         G g;
178         D d(20);
179         const int N = 1000000;
180         std::vector<double> u;
181         for (int i = 0; i < N; ++i)
182         {
183             D::result_type v = d(g);
184             assert(d.min() <= v && v <= d.max());
185             u.push_back(v);
186         }
187         double mean = std::accumulate(u.begin(), u.end(), 0.0) / u.size();
188         double var = 0;
189         double skew = 0;
190         double kurtosis = 0;
191         for (unsigned i = 0; i < u.size(); ++i)
192         {
193             double dbl = (u[i] - mean);
194             double d2 = sqr(dbl);
195             var += d2;
196             skew += dbl * d2;
197             kurtosis += d2 * d2;
198         }
199         var /= u.size();
200         double dev = std::sqrt(var);
201         skew /= u.size() * dev * var;
202         kurtosis /= u.size() * var * var;
203         kurtosis -= 3;
204         double x_mean = d.mean();
205         double x_var = d.mean();
206         double x_skew = 1 / std::sqrt(x_var);
207         double x_kurtosis = 1 / x_var;
208         assert(std::abs((mean - x_mean) / x_mean) < 0.01);
209         assert(std::abs((var - x_var) / x_var) < 0.01);
210         assert(std::abs((skew - x_skew) / x_skew) < 0.01);
211         assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.01);
212     }
213 
214     test_bad_ranges();
215     return 0;
216 }
217