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