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