abseil-cpp/absl/random/bernoulli_distribution_test.cc
Go to the documentation of this file.
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/bernoulli_distribution.h"
16 
17 #include <cmath>
18 #include <cstddef>
19 #include <random>
20 #include <sstream>
21 #include <utility>
22 
23 #include "gtest/gtest.h"
24 #include "absl/random/internal/pcg_engine.h"
25 #include "absl/random/internal/sequence_urbg.h"
26 #include "absl/random/random.h"
27 
28 namespace {
29 
30 class BernoulliTest : public testing::TestWithParam<std::pair<double, size_t>> {
31 };
32 
33 TEST_P(BernoulliTest, Serialize) {
34  const double d = GetParam().first;
36 
37  {
40  EXPECT_EQ(via_param, before);
41  }
42 
43  std::stringstream ss;
44  ss << before;
46 
47  EXPECT_NE(before.p(), after.p());
48  EXPECT_NE(before.param(), after.param());
50 
51  ss >> after;
52 
53  EXPECT_EQ(before.p(), after.p());
54  EXPECT_EQ(before.param(), after.param());
56 }
57 
58 TEST_P(BernoulliTest, Accuracy) {
59  // Sadly, the claim to fame for this implementation is precise accuracy, which
60  // is very, very hard to measure, the improvements come as trials approach the
61  // limit of double accuracy; thus the outcome differs from the
62  // std::bernoulli_distribution with a probability of approximately 1 in 2^-53.
63  const std::pair<double, size_t> para = GetParam();
64  size_t trials = para.second;
65  double p = para.first;
66 
67  // We use a fixed bit generator for distribution accuracy tests. This allows
68  // these tests to be deterministic, while still testing the qualify of the
69  // implementation.
70  absl::random_internal::pcg64_2018_engine rng(0x2B7E151628AED2A6);
71 
72  size_t yes = 0;
74  for (size_t i = 0; i < trials; ++i) {
75  if (dist(rng)) yes++;
76  }
77 
78  // Compute the distribution parameters for a binomial test, using a normal
79  // approximation for the confidence interval, as there are a sufficiently
80  // large number of trials that the central limit theorem applies.
81  const double stddev_p = std::sqrt((p * (1.0 - p)) / trials);
82  const double expected = trials * p;
83  const double stddev = trials * stddev_p;
84 
85  // 5 sigma, approved by Richard Feynman
86  EXPECT_NEAR(yes, expected, 5 * stddev)
87  << "@" << p << ", "
88  << std::abs(static_cast<double>(yes) - expected) / stddev << " stddev";
89 }
90 
91 // There must be many more trials to make the mean approximately normal for `p`
92 // closes to 0 or 1.
94  All, BernoulliTest,
96  // Typical values.
97  std::make_pair(0, 30000), std::make_pair(1e-3, 30000000),
98  std::make_pair(0.1, 3000000), std::make_pair(0.5, 3000000),
99  std::make_pair(0.9, 30000000), std::make_pair(0.999, 30000000),
100  std::make_pair(1, 30000),
101  // Boundary cases.
102  std::make_pair(std::nextafter(1.0, 0.0), 1), // ~1 - epsilon
103  std::make_pair(std::numeric_limits<double>::epsilon(), 1),
104  std::make_pair(std::nextafter(std::numeric_limits<double>::min(),
105  1.0), // min + epsilon
106  1),
107  std::make_pair(std::numeric_limits<double>::min(), // smallest normal
108  1),
109  std::make_pair(
110  std::numeric_limits<double>::denorm_min(), // smallest denorm
111  1),
112  std::make_pair(std::numeric_limits<double>::min() / 2, 1), // denorm
113  std::make_pair(std::nextafter(std::numeric_limits<double>::min(),
114  0.0), // denorm_max
115  1)));
116 
117 // NOTE: absl::bernoulli_distribution is not guaranteed to be stable.
118 TEST(BernoulliTest, StabilityTest) {
119  // absl::bernoulli_distribution stability relies on FastUniformBits and
120  // integer arithmetic.
122  0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
123  0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
124  0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
125  0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull,
126  0x4864f22c059bf29eull, 0x247856d8b862665cull, 0xe46e86e9a1337e10ull,
127  0xd8c8541f3519b133ull, 0xe75b5162c567b9e4ull, 0xf732e5ded7009c5bull,
128  0xb170b98353121eacull, 0x1ec2e8986d2362caull, 0x814c8e35fe9a961aull,
129  0x0c3cd59c9b638a02ull, 0xcb3bb6478a07715cull, 0x1224e62c978bbc7full,
130  0x671ef2cb04e81f6eull, 0x3c1cbd811eaf1808ull, 0x1bbc23cfa8fac721ull,
131  0xa4c2cda65e596a51ull, 0xb77216fad37adf91ull, 0x836d794457c08849ull,
132  0xe083df03475f49d7ull, 0xbc9feb512e6b0d6cull, 0xb12d74fdd718c8c5ull,
133  0x12ff09653bfbe4caull, 0x8dd03a105bc4ee7eull, 0x5738341045ba0d85ull,
134  0xe3fd722dc65ad09eull, 0x5a14fd21ea2a5705ull, 0x14e6ea4d6edb0c73ull,
135  0x275b0dc7e0a18acfull, 0x36cebe0d2653682eull, 0x0361e9b23861596bull,
136  });
137 
138  // Generate a string of '0' and '1' for the distribution output.
139  auto generate = [&urbg](absl::bernoulli_distribution& dist) {
141  output.reserve(36);
142  urbg.reset();
143  for (int i = 0; i < 35; i++) {
144  output.append(dist(urbg) ? "1" : "0");
145  }
146  return output;
147  };
148 
149  const double kP = 0.0331289862362;
150  {
152  auto v = generate(dist);
153  EXPECT_EQ(35, urbg.invocations());
154  EXPECT_EQ(v, "00000000000010000000000010000000000") << dist;
155  }
156  {
157  absl::bernoulli_distribution dist(kP * 10.0);
158  auto v = generate(dist);
159  EXPECT_EQ(35, urbg.invocations());
160  EXPECT_EQ(v, "00000100010010010010000011000011010") << dist;
161  }
162  {
163  absl::bernoulli_distribution dist(kP * 20.0);
164  auto v = generate(dist);
165  EXPECT_EQ(35, urbg.invocations());
166  EXPECT_EQ(v, "00011110010110110011011111110111011") << dist;
167  }
168  {
169  absl::bernoulli_distribution dist(1.0 - kP);
170  auto v = generate(dist);
171  EXPECT_EQ(35, urbg.invocations());
172  EXPECT_EQ(v, "11111111111111111111011111111111111") << dist;
173  }
174 }
175 
176 TEST(BernoulliTest, StabilityTest2) {
178  {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
179  0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
180  0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
181  0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
182 
183  // Generate a string of '0' and '1' for the distribution output.
184  auto generate = [&urbg](absl::bernoulli_distribution& dist) {
186  output.reserve(13);
187  urbg.reset();
188  for (int i = 0; i < 12; i++) {
189  output.append(dist(urbg) ? "1" : "0");
190  }
191  return output;
192  };
193 
194  constexpr double b0 = 1.0 / 13.0 / 0.2;
195  constexpr double b1 = 2.0 / 13.0 / 0.2;
196  constexpr double b3 = (5.0 / 13.0 / 0.2) - ((1 - b0) + (1 - b1) + (1 - b1));
197  {
199  auto v = generate(dist);
200  EXPECT_EQ(12, urbg.invocations());
201  EXPECT_EQ(v, "000011100101") << dist;
202  }
203  {
205  auto v = generate(dist);
206  EXPECT_EQ(12, urbg.invocations());
207  EXPECT_EQ(v, "001111101101") << dist;
208  }
209  {
211  auto v = generate(dist);
212  EXPECT_EQ(12, urbg.invocations());
213  EXPECT_EQ(v, "001111101111") << dist;
214  }
215 }
216 
217 } // namespace
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
absl::bernoulli_distribution
Definition: abseil-cpp/absl/random/bernoulli_distribution.h:35
xds_manager.p
p
Definition: xds_manager.py:60
absl::random_internal::sequence_urbg
Definition: abseil-cpp/absl/random/internal/sequence_urbg.h:33
testing::TestWithParam
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1883
EXPECT_EQ
#define EXPECT_EQ(a, b)
Definition: iomgr/time_averaged_stats_test.cc:27
before
IntBeforeRegisterTypedTestSuiteP before
Definition: googletest/googletest/test/gtest-typed-test_test.cc:376
TEST
#define TEST(name, init_size,...)
Definition: arena_test.cc:75
gmock_output_test.output
output
Definition: bloaty/third_party/googletest/googlemock/test/gmock_output_test.py:175
TEST_P
#define TEST_P(test_suite_name, test_name)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:414
EXPECT_NE
#define EXPECT_NE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2028
setup.v
v
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
absl::bernoulli_distribution::param_type
Definition: abseil-cpp/absl/random/bernoulli_distribution.h:39
min
#define min(a, b)
Definition: qsort.h:83
d
static const fe d
Definition: curve25519_tables.h:19
after
IntAfterTypedTestSuiteP after
Definition: googletest/googletest/test/gtest-typed-test_test.cc:375
b1
T::second_type b1
Definition: abseil-cpp/absl/container/internal/hash_function_defaults_test.cc:306
abseil.generate
def generate(args)
Definition: abseil-cpp/absl/abseil.podspec.gen.py:200
absl::random_internal::pcg_engine
Definition: abseil-cpp/absl/random/internal/pcg_engine.h:41
testing::Values
internal::ValueArray< T... > Values(T... v)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:335
generate
Definition: generate.py:1
EXPECT_NEAR
#define EXPECT_NEAR(val1, val2, abs_error)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2143
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
INSTANTIATE_TEST_SUITE_P
#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name,...)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:460


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:46