xref: /aosp_15_r20/external/abseil-cpp/absl/random/poisson_distribution_test.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
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/macros.h"
29 #include "absl/container/flat_hash_map.h"
30 #include "absl/log/log.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_SUITE(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     LOG(INFO) << "Range {" << param.mean() << "}: " << sample_min << ", "
138               << 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     LOG(INFO) << "CDF (mean = " << mean_ << ")";
192     for (const auto c : cdf_) {
193       LOG(INFO) << 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   // We use a fixed bit generator for distribution accuracy tests.  This allows
261   // these tests to be deterministic, while still testing the qualify of the
262   // implementation.
263   absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
264 };
265 
266 template <typename D>
SingleZTest(const double p,const size_t samples)267 bool PoissonDistributionZTest::SingleZTest(const double p,
268                                            const size_t samples) {
269   D dis(mean());
270 
271   absl::flat_hash_map<int32_t, int> buckets;
272   std::vector<double> data;
273   data.reserve(samples);
274   for (int j = 0; j < samples; j++) {
275     const auto x = dis(rng_);
276     buckets[x]++;
277     data.push_back(x);
278   }
279 
280   // The null-hypothesis is that the distribution is a poisson distribution with
281   // the provided mean (not estimated from the data).
282   const auto m = absl::random_internal::ComputeDistributionMoments(data);
283   const double max_err = absl::random_internal::MaxErrorTolerance(p);
284   const double z = absl::random_internal::ZScore(mean(), m);
285   const bool pass = absl::random_internal::Near("z", z, 0.0, max_err);
286 
287   if (!pass) {
288     // clang-format off
289     LOG(INFO)
290         << "p=" << p << " max_err=" << max_err << "\n"
291            " mean=" << m.mean << " vs. " << mean() << "\n"
292            " stddev=" << std::sqrt(m.variance) << " vs. " << stddev() << "\n"
293            " skewness=" << m.skewness << " vs. " << skew() << "\n"
294            " kurtosis=" << m.kurtosis << " vs. " << kurtosis() << "\n"
295            " z=" << z;
296     // clang-format on
297   }
298   return pass;
299 }
300 
TEST_P(PoissonDistributionZTest,AbslPoissonDistribution)301 TEST_P(PoissonDistributionZTest, AbslPoissonDistribution) {
302   const auto& param = GetParam();
303   const int expected_failures =
304       std::max(1, static_cast<int>(std::ceil(param.trials * param.p_fail)));
305   const double p = absl::random_internal::RequiredSuccessProbability(
306       param.p_fail, param.trials);
307 
308   int failures = 0;
309   for (int i = 0; i < param.trials; i++) {
310     failures +=
311         SingleZTest<absl::poisson_distribution<int32_t>>(p, param.samples) ? 0
312                                                                            : 1;
313   }
314   EXPECT_LE(failures, expected_failures);
315 }
316 
GetZParams()317 std::vector<ZParam> GetZParams() {
318   // These values have been adjusted from the "exact" computed values to reduce
319   // failure rates.
320   //
321   // It turns out that the actual values are not as close to the expected values
322   // as would be ideal.
323   return std::vector<ZParam>({
324       // Knuth method.
325       ZParam{0.5, 0.01, 100, 1000},
326       ZParam{1.0, 0.01, 100, 1000},
327       ZParam{10.0, 0.01, 100, 5000},
328       // Split-knuth method.
329       ZParam{20.0, 0.01, 100, 10000},
330       ZParam{50.0, 0.01, 100, 10000},
331       // Ratio of gaussians method.
332       ZParam{51.0, 0.01, 100, 10000},
333       ZParam{200.0, 0.05, 10, 100000},
334       ZParam{100000.0, 0.05, 10, 1000000},
335   });
336 }
337 
ZParamName(const::testing::TestParamInfo<ZParam> & info)338 std::string ZParamName(const ::testing::TestParamInfo<ZParam>& info) {
339   const auto& p = info.param;
340   std::string name = absl::StrCat("mean_", absl::SixDigits(p.mean));
341   return absl::StrReplaceAll(name, {{"+", "_"}, {"-", "_"}, {".", "_"}});
342 }
343 
344 INSTANTIATE_TEST_SUITE_P(All, PoissonDistributionZTest,
345                          ::testing::ValuesIn(GetZParams()), ZParamName);
346 
347 // The PoissonDistributionChiSquaredTest class provides a basic test framework
348 // for variates generated by a conforming poisson_distribution.
349 class PoissonDistributionChiSquaredTest : public testing::TestWithParam<double>,
350                                           public PoissonModel {
351  public:
PoissonDistributionChiSquaredTest()352   PoissonDistributionChiSquaredTest() : PoissonModel(GetParam()) {}
353 
354   // The ChiSquaredTestImpl provides a chi-squared goodness of fit test for data
355   // generated by the poisson distribution.
356   template <typename D>
357   double ChiSquaredTestImpl();
358 
359  private:
360   void InitChiSquaredTest(const double buckets);
361 
362   std::vector<size_t> cutoffs_;
363   std::vector<double> expected_;
364 
365   // We use a fixed bit generator for distribution accuracy tests.  This allows
366   // these tests to be deterministic, while still testing the qualify of the
367   // implementation.
368   absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
369 };
370 
InitChiSquaredTest(const double buckets)371 void PoissonDistributionChiSquaredTest::InitChiSquaredTest(
372     const double buckets) {
373   if (!cutoffs_.empty() && !expected_.empty()) {
374     return;
375   }
376   InitCDF();
377 
378   // The code below finds cuttoffs that yield approximately equally-sized
379   // buckets to the extent that it is possible. However for poisson
380   // distributions this is particularly challenging for small mean parameters.
381   // Track the expected proportion of items in each bucket.
382   double last_cdf = 0;
383   const double inc = 1.0 / buckets;
384   for (double p = inc; p <= 1.0; p += inc) {
385     auto result = InverseCDF(p);
386     if (!cutoffs_.empty() && cutoffs_.back() == result.index) {
387       continue;
388     }
389     double d = result.cdf - last_cdf;
390     cutoffs_.push_back(result.index);
391     expected_.push_back(d);
392     last_cdf = result.cdf;
393   }
394   cutoffs_.push_back(std::numeric_limits<size_t>::max());
395   expected_.push_back(std::max(0.0, 1.0 - last_cdf));
396 }
397 
398 template <typename D>
ChiSquaredTestImpl()399 double PoissonDistributionChiSquaredTest::ChiSquaredTestImpl() {
400   const int kSamples = 2000;
401   const int kBuckets = 50;
402 
403   // The poisson CDF fails for large mean values, since e^-mean exceeds the
404   // machine precision. For these cases, using a normal approximation would be
405   // appropriate.
406   ABSL_ASSERT(mean() <= 200);
407   InitChiSquaredTest(kBuckets);
408 
409   D dis(mean());
410 
411   std::vector<int32_t> counts(cutoffs_.size(), 0);
412   for (int j = 0; j < kSamples; j++) {
413     const size_t x = dis(rng_);
414     auto it = std::lower_bound(std::begin(cutoffs_), std::end(cutoffs_), x);
415     counts[std::distance(cutoffs_.begin(), it)]++;
416   }
417 
418   // Normalize the counts.
419   std::vector<int32_t> e(expected_.size(), 0);
420   for (int i = 0; i < e.size(); i++) {
421     e[i] = kSamples * expected_[i];
422   }
423 
424   // The null-hypothesis is that the distribution is a poisson distribution with
425   // the provided mean (not estimated from the data).
426   const int dof = static_cast<int>(counts.size()) - 1;
427 
428   // The threshold for logging is 1-in-50.
429   const double threshold = absl::random_internal::ChiSquareValue(dof, 0.98);
430 
431   const double chi_square = absl::random_internal::ChiSquare(
432       std::begin(counts), std::end(counts), std::begin(e), std::end(e));
433 
434   const double p = absl::random_internal::ChiSquarePValue(chi_square, dof);
435 
436   // Log if the chi_squared value is above the threshold.
437   if (chi_square > threshold) {
438     LogCDF();
439 
440     LOG(INFO) << "VALUES  buckets=" << counts.size()
441               << "  samples=" << kSamples;
442     for (size_t i = 0; i < counts.size(); i++) {
443       LOG(INFO) << cutoffs_[i] << ": " << counts[i] << " vs. E=" << e[i];
444     }
445 
446     LOG(INFO) << kChiSquared << "(data, dof=" << dof << ") = " << chi_square
447               << " (" << p << ")\n"
448               << " vs.\n"
449               << kChiSquared << " @ 0.98 = " << threshold;
450   }
451   return p;
452 }
453 
TEST_P(PoissonDistributionChiSquaredTest,AbslPoissonDistribution)454 TEST_P(PoissonDistributionChiSquaredTest, AbslPoissonDistribution) {
455   const int kTrials = 20;
456 
457   // Large values are not yet supported -- this requires estimating the cdf
458   // using the normal distribution instead of the poisson in this case.
459   ASSERT_LE(mean(), 200.0);
460   if (mean() > 200.0) {
461     return;
462   }
463 
464   int failures = 0;
465   for (int i = 0; i < kTrials; i++) {
466     double p_value = ChiSquaredTestImpl<absl::poisson_distribution<int32_t>>();
467     if (p_value < 0.005) {
468       failures++;
469     }
470   }
471   // There is a 0.10% chance of producing at least one failure, so raise the
472   // failure threshold high enough to allow for a flake rate < 10,000.
473   EXPECT_LE(failures, 4);
474 }
475 
476 INSTANTIATE_TEST_SUITE_P(All, PoissonDistributionChiSquaredTest,
477                          ::testing::Values(0.5, 1.0, 2.0, 10.0, 50.0, 51.0,
478                                            200.0));
479 
480 // NOTE: absl::poisson_distribution is not guaranteed to be stable.
TEST(PoissonDistributionTest,StabilityTest)481 TEST(PoissonDistributionTest, StabilityTest) {
482   using testing::ElementsAre;
483   // absl::poisson_distribution stability relies on stability of
484   // std::exp, std::log, std::sqrt, std::ceil, std::floor, and
485   // absl::FastUniformBits, absl::StirlingLogFactorial, absl::RandU64ToDouble.
486   absl::random_internal::sequence_urbg urbg({
487       0x035b0dc7e0a18acfull, 0x06cebe0d2653682eull, 0x0061e9b23861596bull,
488       0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
489       0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
490       0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
491       0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull,
492       0x4864f22c059bf29eull, 0x247856d8b862665cull, 0xe46e86e9a1337e10ull,
493       0xd8c8541f3519b133ull, 0xe75b5162c567b9e4ull, 0xf732e5ded7009c5bull,
494       0xb170b98353121eacull, 0x1ec2e8986d2362caull, 0x814c8e35fe9a961aull,
495       0x0c3cd59c9b638a02ull, 0xcb3bb6478a07715cull, 0x1224e62c978bbc7full,
496       0x671ef2cb04e81f6eull, 0x3c1cbd811eaf1808ull, 0x1bbc23cfa8fac721ull,
497       0xa4c2cda65e596a51ull, 0xb77216fad37adf91ull, 0x836d794457c08849ull,
498       0xe083df03475f49d7ull, 0xbc9feb512e6b0d6cull, 0xb12d74fdd718c8c5ull,
499       0x12ff09653bfbe4caull, 0x8dd03a105bc4ee7eull, 0x5738341045ba0d85ull,
500       0xf3fd722dc65ad09eull, 0xfa14fd21ea2a5705ull, 0xffe6ea4d6edb0c73ull,
501       0xD07E9EFE2BF11FB4ull, 0x95DBDA4DAE909198ull, 0xEAAD8E716B93D5A0ull,
502       0xD08ED1D0AFC725E0ull, 0x8E3C5B2F8E7594B7ull, 0x8FF6E2FBF2122B64ull,
503       0x8888B812900DF01Cull, 0x4FAD5EA0688FC31Cull, 0xD1CFF191B3A8C1ADull,
504       0x2F2F2218BE0E1777ull, 0xEA752DFE8B021FA1ull, 0xE5A0CC0FB56F74E8ull,
505       0x18ACF3D6CE89E299ull, 0xB4A84FE0FD13E0B7ull, 0x7CC43B81D2ADA8D9ull,
506       0x165FA26680957705ull, 0x93CC7314211A1477ull, 0xE6AD206577B5FA86ull,
507       0xC75442F5FB9D35CFull, 0xEBCDAF0C7B3E89A0ull, 0xD6411BD3AE1E7E49ull,
508       0x00250E2D2071B35Eull, 0x226800BB57B8E0AFull, 0x2464369BF009B91Eull,
509       0x5563911D59DFA6AAull, 0x78C14389D95A537Full, 0x207D5BA202E5B9C5ull,
510       0x832603766295CFA9ull, 0x11C819684E734A41ull, 0xB3472DCA7B14A94Aull,
511   });
512 
513   std::vector<int> output(10);
514 
515   // Method 1.
516   {
517     absl::poisson_distribution<int> dist(5);
518     std::generate(std::begin(output), std::end(output),
519                   [&] { return dist(urbg); });
520   }
521   EXPECT_THAT(output,  // mean = 4.2
522               ElementsAre(1, 0, 0, 4, 2, 10, 3, 3, 7, 12));
523 
524   // Method 2.
525   {
526     urbg.reset();
527     absl::poisson_distribution<int> dist(25);
528     std::generate(std::begin(output), std::end(output),
529                   [&] { return dist(urbg); });
530   }
531   EXPECT_THAT(output,  // mean = 19.8
532               ElementsAre(9, 35, 18, 10, 35, 18, 10, 35, 18, 10));
533 
534   // Method 3.
535   {
536     urbg.reset();
537     absl::poisson_distribution<int> dist(121);
538     std::generate(std::begin(output), std::end(output),
539                   [&] { return dist(urbg); });
540   }
541   EXPECT_THAT(output,  // mean = 124.1
542               ElementsAre(161, 122, 129, 124, 112, 112, 117, 120, 130, 114));
543 }
544 
TEST(PoissonDistributionTest,AlgorithmExpectedValue_1)545 TEST(PoissonDistributionTest, AlgorithmExpectedValue_1) {
546   // This tests small values of the Knuth method.
547   // The underlying uniform distribution will generate exactly 0.5.
548   absl::random_internal::sequence_urbg urbg({0x8000000000000001ull});
549   absl::poisson_distribution<int> dist(5);
550   EXPECT_EQ(7, dist(urbg));
551 }
552 
TEST(PoissonDistributionTest,AlgorithmExpectedValue_2)553 TEST(PoissonDistributionTest, AlgorithmExpectedValue_2) {
554   // This tests larger values of the Knuth method.
555   // The underlying uniform distribution will generate exactly 0.5.
556   absl::random_internal::sequence_urbg urbg({0x8000000000000001ull});
557   absl::poisson_distribution<int> dist(25);
558   EXPECT_EQ(36, dist(urbg));
559 }
560 
TEST(PoissonDistributionTest,AlgorithmExpectedValue_3)561 TEST(PoissonDistributionTest, AlgorithmExpectedValue_3) {
562   // This variant uses the ratio of uniforms method.
563   absl::random_internal::sequence_urbg urbg(
564       {0x7fffffffffffffffull, 0x8000000000000000ull});
565 
566   absl::poisson_distribution<int> dist(121);
567   EXPECT_EQ(121, dist(urbg));
568 }
569 
570 }  // namespace
571