• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "absl/random/poisson_distribution.h"
16 
17 #include <algorithm>
18 #include <cstddef>
19 #include <cstdint>
20 #include <iterator>
21 #include <random>
22 #include <sstream>
23 #include <string>
24 #include <vector>
25 
26 #include "gmock/gmock.h"
27 #include "gtest/gtest.h"
28 #include "absl/base/internal/raw_logging.h"
29 #include "absl/base/macros.h"
30 #include "absl/container/flat_hash_map.h"
31 #include "absl/random/internal/chi_square.h"
32 #include "absl/random/internal/distribution_test_util.h"
33 #include "absl/random/internal/pcg_engine.h"
34 #include "absl/random/internal/sequence_urbg.h"
35 #include "absl/random/random.h"
36 #include "absl/strings/str_cat.h"
37 #include "absl/strings/str_format.h"
38 #include "absl/strings/str_replace.h"
39 #include "absl/strings/strip.h"
40 
41 // Notes about generating poisson variates:
42 //
43 // It is unlikely that any implementation of std::poisson_distribution
44 // will be stable over time and across library implementations. For instance
45 // the three different poisson variate generators listed below all differ:
46 //
47 // https://github.com/ampl/gsl/tree/master/randist/poisson.c
48 // * GSL uses a gamma + binomial + knuth method to compute poisson variates.
49 //
50 // https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/random.tcc
51 // * GCC uses the Devroye rejection algorithm, based on
52 // Devroye, L. Non-Uniform Random Variates Generation. Springer-Verlag,
53 // New York, 1986, Ch. X, Sects. 3.3 & 3.4 (+ Errata!), ~p.511
54 //   http://www.nrbook.com/devroye/
55 //
56 // https://github.com/llvm-mirror/libcxx/blob/master/include/random
57 // * CLANG uses a different rejection method, which appears to include a
58 // normal-distribution approximation and an exponential distribution to
59 // compute the threshold, including a similar factorial approximation to this
60 // one, but it is unclear where the algorithm comes from, exactly.
61 //
62 
63 namespace {
64 
65 using absl::random_internal::kChiSquared;
66 
67 // The PoissonDistributionInterfaceTest provides a basic test that
68 // absl::poisson_distribution conforms to the interface and serialization
69 // requirements imposed by [rand.req.dist] for the common integer types.
70 
71 template <typename IntType>
72 class PoissonDistributionInterfaceTest : public ::testing::Test {};
73 
74 using IntTypes = ::testing::Types<int, int8_t, int16_t, int32_t, int64_t,
75                                   uint8_t, uint16_t, uint32_t, uint64_t>;
76 TYPED_TEST_CASE(PoissonDistributionInterfaceTest, IntTypes);
77 
TYPED_TEST(PoissonDistributionInterfaceTest,SerializeTest)78 TYPED_TEST(PoissonDistributionInterfaceTest, SerializeTest) {
79   using param_type = typename absl::poisson_distribution<TypeParam>::param_type;
80   const double kMax =
81       std::min(1e10 /* assertion limit */,
82                static_cast<double>(std::numeric_limits<TypeParam>::max()));
83 
84   const double kParams[] = {
85       // Cases around 1.
86       1,                         //
87       std::nextafter(1.0, 0.0),  // 1 - epsilon
88       std::nextafter(1.0, 2.0),  // 1 + epsilon
89       // Arbitrary values.
90       1e-8, 1e-4,
91       0.0000005,  // ~7.2e-7
92       0.2,        // ~0.2x
93       0.5,        // 0.72
94       2,          // ~2.8
95       20,         // 3x ~9.6
96       100, 1e4, 1e8, 1.5e9, 1e20,
97       // Boundary cases.
98       std::numeric_limits<double>::max(),
99       std::numeric_limits<double>::epsilon(),
100       std::nextafter(std::numeric_limits<double>::min(),
101                      1.0),                        // min + epsilon
102       std::numeric_limits<double>::min(),         // smallest normal
103       std::numeric_limits<double>::denorm_min(),  // smallest denorm
104       std::numeric_limits<double>::min() / 2,     // denorm
105       std::nextafter(std::numeric_limits<double>::min(),
106                      0.0),  // denorm_max
107   };
108 
109 
110   constexpr int kCount = 1000;
111   absl::InsecureBitGen gen;
112   for (const double m : kParams) {
113     const double mean = std::min(kMax, m);
114     const param_type param(mean);
115 
116     // Validate parameters.
117     absl::poisson_distribution<TypeParam> before(mean);
118     EXPECT_EQ(before.mean(), param.mean());
119 
120     {
121       absl::poisson_distribution<TypeParam> via_param(param);
122       EXPECT_EQ(via_param, before);
123       EXPECT_EQ(via_param.param(), before.param());
124     }
125 
126     // Smoke test.
127     auto sample_min = before.max();
128     auto sample_max = before.min();
129     for (int i = 0; i < kCount; i++) {
130       auto sample = before(gen);
131       EXPECT_GE(sample, before.min());
132       EXPECT_LE(sample, before.max());
133       if (sample > sample_max) sample_max = sample;
134       if (sample < sample_min) sample_min = sample;
135     }
136 
137     ABSL_INTERNAL_LOG(INFO, absl::StrCat("Range {", param.mean(), "}: ",
138                                          +sample_min, ", ", +sample_max));
139 
140     // Validate stream serialization.
141     std::stringstream ss;
142     ss << before;
143 
144     absl::poisson_distribution<TypeParam> after(3.8);
145 
146     EXPECT_NE(before.mean(), after.mean());
147     EXPECT_NE(before.param(), after.param());
148     EXPECT_NE(before, after);
149 
150     ss >> after;
151 
152     EXPECT_EQ(before.mean(), after.mean())  //
153         << ss.str() << " "                  //
154         << (ss.good() ? "good " : "")       //
155         << (ss.bad() ? "bad " : "")         //
156         << (ss.eof() ? "eof " : "")         //
157         << (ss.fail() ? "fail " : "");
158   }
159 }
160 
161 // See http://www.itl.nist.gov/div898/handbook/eda/section3/eda366j.htm
162 
163 class PoissonModel {
164  public:
PoissonModel(double mean)165   explicit PoissonModel(double mean) : mean_(mean) {}
166 
mean() const167   double mean() const { return mean_; }
variance() const168   double variance() const { return mean_; }
stddev() const169   double stddev() const { return std::sqrt(variance()); }
skew() const170   double skew() const { return 1.0 / mean_; }
kurtosis() const171   double kurtosis() const { return 3.0 + 1.0 / mean_; }
172 
173   // InitCDF() initializes the CDF for the distribution parameters.
174   void InitCDF();
175 
176   // The InverseCDF, or the Percent-point function returns x, P(x) < v.
177   struct CDF {
178     size_t index;
179     double pmf;
180     double cdf;
181   };
InverseCDF(double p)182   CDF InverseCDF(double p) {
183     CDF target{0, 0, p};
184     auto it = std::upper_bound(
185         std::begin(cdf_), std::end(cdf_), target,
186         [](const CDF& a, const CDF& b) { return a.cdf < b.cdf; });
187     return *it;
188   }
189 
LogCDF()190   void LogCDF() {
191     ABSL_INTERNAL_LOG(INFO, absl::StrCat("CDF (mean = ", mean_, ")"));
192     for (const auto c : cdf_) {
193       ABSL_INTERNAL_LOG(INFO,
194                         absl::StrCat(c.index, ": pmf=", c.pmf, " cdf=", c.cdf));
195     }
196   }
197 
198  private:
199   const double mean_;
200 
201   std::vector<CDF> cdf_;
202 };
203 
204 // The goal is to compute an InverseCDF function, or percent point function for
205 // the poisson distribution, and use that to partition our output into equal
206 // range buckets.  However there is no closed form solution for the inverse cdf
207 // for poisson distributions (the closest is the incomplete gamma function).
208 // Instead, `InitCDF` iteratively computes the PMF and the CDF. This enables
209 // searching for the bucket points.
InitCDF()210 void PoissonModel::InitCDF() {
211   if (!cdf_.empty()) {
212     // State already initialized.
213     return;
214   }
215   ABSL_ASSERT(mean_ < 201.0);
216 
217   const size_t max_i = 50 * stddev() + mean();
218   const double e_neg_mean = std::exp(-mean());
219   ABSL_ASSERT(e_neg_mean > 0);
220 
221   double d = 1;
222   double last_result = e_neg_mean;
223   double cumulative = e_neg_mean;
224   if (e_neg_mean > 1e-10) {
225     cdf_.push_back({0, e_neg_mean, cumulative});
226   }
227   for (size_t i = 1; i < max_i; i++) {
228     d *= (mean() / i);
229     double result = e_neg_mean * d;
230     cumulative += result;
231     if (result < 1e-10 && result < last_result && cumulative > 0.999999) {
232       break;
233     }
234     if (result > 1e-7) {
235       cdf_.push_back({i, result, cumulative});
236     }
237     last_result = result;
238   }
239   ABSL_ASSERT(!cdf_.empty());
240 }
241 
242 // PoissonDistributionZTest implements a z-test for the poisson distribution.
243 
244 struct ZParam {
245   double mean;
246   double p_fail;   // Z-Test probability of failure.
247   int trials;      // Z-Test trials.
248   size_t samples;  // Z-Test samples.
249 };
250 
251 class PoissonDistributionZTest : public testing::TestWithParam<ZParam>,
252                                  public PoissonModel {
253  public:
PoissonDistributionZTest()254   PoissonDistributionZTest() : PoissonModel(GetParam().mean) {}
255 
256   // ZTestImpl provides a basic z-squared test of the mean vs. expected
257   // mean for data generated by the poisson distribution.
258   template <typename D>
259   bool SingleZTest(const double p, const size_t samples);
260 
261   // We use a fixed bit generator for distribution accuracy tests.  This allows
262   // these tests to be deterministic, while still testing the qualify of the
263   // implementation.
264   absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
265 };
266 
267 template <typename D>
SingleZTest(const double p,const size_t samples)268 bool PoissonDistributionZTest::SingleZTest(const double p,
269                                            const size_t samples) {
270   D dis(mean());
271 
272   absl::flat_hash_map<int32_t, int> buckets;
273   std::vector<double> data;
274   data.reserve(samples);
275   for (int j = 0; j < samples; j++) {
276     const auto x = dis(rng_);
277     buckets[x]++;
278     data.push_back(x);
279   }
280 
281   // The null-hypothesis is that the distribution is a poisson distribution with
282   // the provided mean (not estimated from the data).
283   const auto m = absl::random_internal::ComputeDistributionMoments(data);
284   const double max_err = absl::random_internal::MaxErrorTolerance(p);
285   const double z = absl::random_internal::ZScore(mean(), m);
286   const bool pass = absl::random_internal::Near("z", z, 0.0, max_err);
287 
288   if (!pass) {
289     ABSL_INTERNAL_LOG(
290         INFO, absl::StrFormat("p=%f max_err=%f\n"
291                               " mean=%f vs. %f\n"
292                               " stddev=%f vs. %f\n"
293                               " skewness=%f vs. %f\n"
294                               " kurtosis=%f vs. %f\n"
295                               " z=%f",
296                               p, max_err, m.mean, mean(), std::sqrt(m.variance),
297                               stddev(), m.skewness, skew(), m.kurtosis,
298                               kurtosis(), z));
299   }
300   return pass;
301 }
302 
TEST_P(PoissonDistributionZTest,AbslPoissonDistribution)303 TEST_P(PoissonDistributionZTest, AbslPoissonDistribution) {
304   const auto& param = GetParam();
305   const int expected_failures =
306       std::max(1, static_cast<int>(std::ceil(param.trials * param.p_fail)));
307   const double p = absl::random_internal::RequiredSuccessProbability(
308       param.p_fail, param.trials);
309 
310   int failures = 0;
311   for (int i = 0; i < param.trials; i++) {
312     failures +=
313         SingleZTest<absl::poisson_distribution<int32_t>>(p, param.samples) ? 0
314                                                                            : 1;
315   }
316   EXPECT_LE(failures, expected_failures);
317 }
318 
GetZParams()319 std::vector<ZParam> GetZParams() {
320   // These values have been adjusted from the "exact" computed values to reduce
321   // failure rates.
322   //
323   // It turns out that the actual values are not as close to the expected values
324   // as would be ideal.
325   return std::vector<ZParam>({
326       // Knuth method.
327       ZParam{0.5, 0.01, 100, 1000},
328       ZParam{1.0, 0.01, 100, 1000},
329       ZParam{10.0, 0.01, 100, 5000},
330       // Split-knuth method.
331       ZParam{20.0, 0.01, 100, 10000},
332       ZParam{50.0, 0.01, 100, 10000},
333       // Ratio of gaussians method.
334       ZParam{51.0, 0.01, 100, 10000},
335       ZParam{200.0, 0.05, 10, 100000},
336       ZParam{100000.0, 0.05, 10, 1000000},
337   });
338 }
339 
ZParamName(const::testing::TestParamInfo<ZParam> & info)340 std::string ZParamName(const ::testing::TestParamInfo<ZParam>& info) {
341   const auto& p = info.param;
342   std::string name = absl::StrCat("mean_", absl::SixDigits(p.mean));
343   return absl::StrReplaceAll(name, {{"+", "_"}, {"-", "_"}, {".", "_"}});
344 }
345 
346 INSTANTIATE_TEST_SUITE_P(All, PoissonDistributionZTest,
347                          ::testing::ValuesIn(GetZParams()), ZParamName);
348 
349 // The PoissonDistributionChiSquaredTest class provides a basic test framework
350 // for variates generated by a conforming poisson_distribution.
351 class PoissonDistributionChiSquaredTest : public testing::TestWithParam<double>,
352                                           public PoissonModel {
353  public:
PoissonDistributionChiSquaredTest()354   PoissonDistributionChiSquaredTest() : PoissonModel(GetParam()) {}
355 
356   // The ChiSquaredTestImpl provides a chi-squared goodness of fit test for data
357   // generated by the poisson distribution.
358   template <typename D>
359   double ChiSquaredTestImpl();
360 
361  private:
362   void InitChiSquaredTest(const double buckets);
363 
364   std::vector<size_t> cutoffs_;
365   std::vector<double> expected_;
366 
367   // We use a fixed bit generator for distribution accuracy tests.  This allows
368   // these tests to be deterministic, while still testing the qualify of the
369   // implementation.
370   absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
371 };
372 
InitChiSquaredTest(const double buckets)373 void PoissonDistributionChiSquaredTest::InitChiSquaredTest(
374     const double buckets) {
375   if (!cutoffs_.empty() && !expected_.empty()) {
376     return;
377   }
378   InitCDF();
379 
380   // The code below finds cuttoffs that yield approximately equally-sized
381   // buckets to the extent that it is possible. However for poisson
382   // distributions this is particularly challenging for small mean parameters.
383   // Track the expected proportion of items in each bucket.
384   double last_cdf = 0;
385   const double inc = 1.0 / buckets;
386   for (double p = inc; p <= 1.0; p += inc) {
387     auto result = InverseCDF(p);
388     if (!cutoffs_.empty() && cutoffs_.back() == result.index) {
389       continue;
390     }
391     double d = result.cdf - last_cdf;
392     cutoffs_.push_back(result.index);
393     expected_.push_back(d);
394     last_cdf = result.cdf;
395   }
396   cutoffs_.push_back(std::numeric_limits<size_t>::max());
397   expected_.push_back(std::max(0.0, 1.0 - last_cdf));
398 }
399 
400 template <typename D>
ChiSquaredTestImpl()401 double PoissonDistributionChiSquaredTest::ChiSquaredTestImpl() {
402   const int kSamples = 2000;
403   const int kBuckets = 50;
404 
405   // The poisson CDF fails for large mean values, since e^-mean exceeds the
406   // machine precision. For these cases, using a normal approximation would be
407   // appropriate.
408   ABSL_ASSERT(mean() <= 200);
409   InitChiSquaredTest(kBuckets);
410 
411   D dis(mean());
412 
413   std::vector<int32_t> counts(cutoffs_.size(), 0);
414   for (int j = 0; j < kSamples; j++) {
415     const size_t x = dis(rng_);
416     auto it = std::lower_bound(std::begin(cutoffs_), std::end(cutoffs_), x);
417     counts[std::distance(cutoffs_.begin(), it)]++;
418   }
419 
420   // Normalize the counts.
421   std::vector<int32_t> e(expected_.size(), 0);
422   for (int i = 0; i < e.size(); i++) {
423     e[i] = kSamples * expected_[i];
424   }
425 
426   // The null-hypothesis is that the distribution is a poisson distribution with
427   // the provided mean (not estimated from the data).
428   const int dof = static_cast<int>(counts.size()) - 1;
429 
430   // The threshold for logging is 1-in-50.
431   const double threshold = absl::random_internal::ChiSquareValue(dof, 0.98);
432 
433   const double chi_square = absl::random_internal::ChiSquare(
434       std::begin(counts), std::end(counts), std::begin(e), std::end(e));
435 
436   const double p = absl::random_internal::ChiSquarePValue(chi_square, dof);
437 
438   // Log if the chi_squared value is above the threshold.
439   if (chi_square > threshold) {
440     LogCDF();
441 
442     ABSL_INTERNAL_LOG(INFO, absl::StrCat("VALUES  buckets=", counts.size(),
443                                          "  samples=", kSamples));
444     for (size_t i = 0; i < counts.size(); i++) {
445       ABSL_INTERNAL_LOG(
446           INFO, absl::StrCat(cutoffs_[i], ": ", counts[i], " vs. E=", e[i]));
447     }
448 
449     ABSL_INTERNAL_LOG(
450         INFO,
451         absl::StrCat(kChiSquared, "(data, dof=", dof, ") = ", chi_square, " (",
452                      p, ")\n", " vs.\n", kChiSquared, " @ 0.98 = ", threshold));
453   }
454   return p;
455 }
456 
TEST_P(PoissonDistributionChiSquaredTest,AbslPoissonDistribution)457 TEST_P(PoissonDistributionChiSquaredTest, AbslPoissonDistribution) {
458   const int kTrials = 20;
459 
460   // Large values are not yet supported -- this requires estimating the cdf
461   // using the normal distribution instead of the poisson in this case.
462   ASSERT_LE(mean(), 200.0);
463   if (mean() > 200.0) {
464     return;
465   }
466 
467   int failures = 0;
468   for (int i = 0; i < kTrials; i++) {
469     double p_value = ChiSquaredTestImpl<absl::poisson_distribution<int32_t>>();
470     if (p_value < 0.005) {
471       failures++;
472     }
473   }
474   // There is a 0.10% chance of producing at least one failure, so raise the
475   // failure threshold high enough to allow for a flake rate < 10,000.
476   EXPECT_LE(failures, 4);
477 }
478 
479 INSTANTIATE_TEST_SUITE_P(All, PoissonDistributionChiSquaredTest,
480                          ::testing::Values(0.5, 1.0, 2.0, 10.0, 50.0, 51.0,
481                                            200.0));
482 
483 // NOTE: absl::poisson_distribution is not guaranteed to be stable.
TEST(PoissonDistributionTest,StabilityTest)484 TEST(PoissonDistributionTest, StabilityTest) {
485   using testing::ElementsAre;
486   // absl::poisson_distribution stability relies on stability of
487   // std::exp, std::log, std::sqrt, std::ceil, std::floor, and
488   // absl::FastUniformBits, absl::StirlingLogFactorial, absl::RandU64ToDouble.
489   absl::random_internal::sequence_urbg urbg({
490       0x035b0dc7e0a18acfull, 0x06cebe0d2653682eull, 0x0061e9b23861596bull,
491       0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
492       0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
493       0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
494       0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull,
495       0x4864f22c059bf29eull, 0x247856d8b862665cull, 0xe46e86e9a1337e10ull,
496       0xd8c8541f3519b133ull, 0xe75b5162c567b9e4ull, 0xf732e5ded7009c5bull,
497       0xb170b98353121eacull, 0x1ec2e8986d2362caull, 0x814c8e35fe9a961aull,
498       0x0c3cd59c9b638a02ull, 0xcb3bb6478a07715cull, 0x1224e62c978bbc7full,
499       0x671ef2cb04e81f6eull, 0x3c1cbd811eaf1808ull, 0x1bbc23cfa8fac721ull,
500       0xa4c2cda65e596a51ull, 0xb77216fad37adf91ull, 0x836d794457c08849ull,
501       0xe083df03475f49d7ull, 0xbc9feb512e6b0d6cull, 0xb12d74fdd718c8c5ull,
502       0x12ff09653bfbe4caull, 0x8dd03a105bc4ee7eull, 0x5738341045ba0d85ull,
503       0xf3fd722dc65ad09eull, 0xfa14fd21ea2a5705ull, 0xffe6ea4d6edb0c73ull,
504       0xD07E9EFE2BF11FB4ull, 0x95DBDA4DAE909198ull, 0xEAAD8E716B93D5A0ull,
505       0xD08ED1D0AFC725E0ull, 0x8E3C5B2F8E7594B7ull, 0x8FF6E2FBF2122B64ull,
506       0x8888B812900DF01Cull, 0x4FAD5EA0688FC31Cull, 0xD1CFF191B3A8C1ADull,
507       0x2F2F2218BE0E1777ull, 0xEA752DFE8B021FA1ull, 0xE5A0CC0FB56F74E8ull,
508       0x18ACF3D6CE89E299ull, 0xB4A84FE0FD13E0B7ull, 0x7CC43B81D2ADA8D9ull,
509       0x165FA26680957705ull, 0x93CC7314211A1477ull, 0xE6AD206577B5FA86ull,
510       0xC75442F5FB9D35CFull, 0xEBCDAF0C7B3E89A0ull, 0xD6411BD3AE1E7E49ull,
511       0x00250E2D2071B35Eull, 0x226800BB57B8E0AFull, 0x2464369BF009B91Eull,
512       0x5563911D59DFA6AAull, 0x78C14389D95A537Full, 0x207D5BA202E5B9C5ull,
513       0x832603766295CFA9ull, 0x11C819684E734A41ull, 0xB3472DCA7B14A94Aull,
514   });
515 
516   std::vector<int> output(10);
517 
518   // Method 1.
519   {
520     absl::poisson_distribution<int> dist(5);
521     std::generate(std::begin(output), std::end(output),
522                   [&] { return dist(urbg); });
523   }
524   EXPECT_THAT(output,  // mean = 4.2
525               ElementsAre(1, 0, 0, 4, 2, 10, 3, 3, 7, 12));
526 
527   // Method 2.
528   {
529     urbg.reset();
530     absl::poisson_distribution<int> dist(25);
531     std::generate(std::begin(output), std::end(output),
532                   [&] { return dist(urbg); });
533   }
534   EXPECT_THAT(output,  // mean = 19.8
535               ElementsAre(9, 35, 18, 10, 35, 18, 10, 35, 18, 10));
536 
537   // Method 3.
538   {
539     urbg.reset();
540     absl::poisson_distribution<int> dist(121);
541     std::generate(std::begin(output), std::end(output),
542                   [&] { return dist(urbg); });
543   }
544   EXPECT_THAT(output,  // mean = 124.1
545               ElementsAre(161, 122, 129, 124, 112, 112, 117, 120, 130, 114));
546 }
547 
TEST(PoissonDistributionTest,AlgorithmExpectedValue_1)548 TEST(PoissonDistributionTest, AlgorithmExpectedValue_1) {
549   // This tests small values of the Knuth method.
550   // The underlying uniform distribution will generate exactly 0.5.
551   absl::random_internal::sequence_urbg urbg({0x8000000000000001ull});
552   absl::poisson_distribution<int> dist(5);
553   EXPECT_EQ(7, dist(urbg));
554 }
555 
TEST(PoissonDistributionTest,AlgorithmExpectedValue_2)556 TEST(PoissonDistributionTest, AlgorithmExpectedValue_2) {
557   // This tests larger values of the Knuth method.
558   // The underlying uniform distribution will generate exactly 0.5.
559   absl::random_internal::sequence_urbg urbg({0x8000000000000001ull});
560   absl::poisson_distribution<int> dist(25);
561   EXPECT_EQ(36, dist(urbg));
562 }
563 
TEST(PoissonDistributionTest,AlgorithmExpectedValue_3)564 TEST(PoissonDistributionTest, AlgorithmExpectedValue_3) {
565   // This variant uses the ratio of uniforms method.
566   absl::random_internal::sequence_urbg urbg(
567       {0x7fffffffffffffffull, 0x8000000000000000ull});
568 
569   absl::poisson_distribution<int> dist(121);
570   EXPECT_EQ(121, dist(urbg));
571 }
572 
573 }  // namespace
574