summaryrefslogtreecommitdiff
path: root/absl/random/distributions_test.cc
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2020-08-02 14:23:26 -0700
committerGravatar Derek Mauro <dmauro@google.com>2020-08-03 13:24:24 -0400
commit1995c6a3c2f9080160d9d8716504dc004e5e1ec0 (patch)
tree0b1e861b0d2c16f78d0f2e861a94a2bccf38965a /absl/random/distributions_test.cc
parent184cf2524101310a0ba315c743e82cf45fccccf8 (diff)
Export of internal Abseil changes
-- 790f9061df340cd900e8da70e66c363f7af3c2eb by Abseil Team <absl-team@google.com>: Add support for rvalue reference to function types. PiperOrigin-RevId: 324508531 -- 51fe201dbb41a3ebc3d49ff65250b5f464279d43 by Abseil Team <absl-team@google.com>: Cleaning up function comment style; no substantive change. PiperOrigin-RevId: 324497401 -- da8595d5266577d0c170528d12f6de17b8affcc2 by Abseil Team <absl-team@google.com>: Add support for demangling GNU vector types. PiperOrigin-RevId: 324494559 -- 0cb0acf88c1750f6963c9cb85249f9b4f0bd5104 by Abseil Team <absl-team@google.com>: Add support for thread-local types. PiperOrigin-RevId: 324491183 -- c676bc8380560599cd26f7f231e04e6be532e904 by Abseil Team <absl-team@google.com>: Add support for demangling "Du" (char8_t). PiperOrigin-RevId: 324441607 -- b218bf6467bc62b327214782c881e8224ad91509 by Abseil Team <absl-team@google.com>: Update doc comments in header of `any.h` to reflect that `absl::variant` has been released. PiperOrigin-RevId: 324431690 -- e5b579f3f1aa598c1f62e71dba7103b98811de59 by Laramie Leavitt <lar@google.com>: Bugfix: Fix bounds in absl::Uniform where one of the bounds is min/max. When absl::Uniform(rng, tag, a, b) is called, the tag is used in conjunction with the type to determine whether or not to manipulate the bounds to make them inclusive or exclusive through the uniform_*_bound functions. Unfortunately, at limits of the interval the function was not well behaved. The previous implementation used wrapping arithmetic. This causes incorrect bounds computation at the extremes (numeric_limits::min / numeric_limits::max) the bound would wrap. Improve this situation by: 1/ Changing the uniform_*_bound functions to use saturating arithmetic instead of wrapping, thus in the unsigned case, the upper_bound of IntervalOpenOpen for 0 is now 0, rather than numeric_limits::max, likewise for the lower bound. 2/ Adjusting the hi/lo checks in the distributions. When the interval is empty, such as for absl::Uniform(absl::IntervalOpenOpen, gen, 1, 0), the return value is somewhat nonsensical. Now absl::Uniform more consistently returns the low input rather than any adjusted input. In the above case, that means that 1 is returned rather than 2. NOTE: Calls to absl::Uniform where the resolved upper bound is < the lower bound are still ill-formed and should be avoided. 3/ Adding better tests. The underlying uniform_*_distribution classes are not affected. PiperOrigin-RevId: 324240873 GitOrigin-RevId: 790f9061df340cd900e8da70e66c363f7af3c2eb Change-Id: I2a2208650ea3135c575e200b868ce1d275069fc8
Diffstat (limited to 'absl/random/distributions_test.cc')
-rw-r--r--absl/random/distributions_test.cc142
1 files changed, 54 insertions, 88 deletions
diff --git a/absl/random/distributions_test.cc b/absl/random/distributions_test.cc
index 2d92723a..5866a072 100644
--- a/absl/random/distributions_test.cc
+++ b/absl/random/distributions_test.cc
@@ -29,94 +29,6 @@ constexpr int kSize = 400000;
class RandomDistributionsTest : public testing::Test {};
-TEST_F(RandomDistributionsTest, UniformBoundFunctions) {
- using absl::IntervalClosedClosed;
- using absl::IntervalClosedOpen;
- using absl::IntervalOpenClosed;
- using absl::IntervalOpenOpen;
- using absl::random_internal::uniform_lower_bound;
- using absl::random_internal::uniform_upper_bound;
-
- // absl::uniform_int_distribution natively assumes IntervalClosedClosed
- // absl::uniform_real_distribution natively assumes IntervalClosedOpen
-
- EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, 0, 100), 1);
- EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, 0, 100), 1);
- EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, 0, 1.0), 0);
- EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, 0, 1.0), 0);
- EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, 0, 1.0), 0);
- EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, 0, 1.0), 0);
-
- EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, 0, 100), 0);
- EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, 0, 100), 0);
- EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, 0, 1.0), 0);
- EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, 0, 1.0), 0);
- EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, 0, 1.0), 0);
- EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, 0, 1.0), 0);
-
- EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, 0, 100), 99);
- EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, 0, 100), 99);
- EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, 0, 1.0), 1.0);
- EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, 0, 1.0), 1.0);
- EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, 0, 1.0), 1.0);
- EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, 0, 1.0), 1.0);
-
- EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, 0, 100), 100);
- EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0, 100), 100);
- EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, 0, 1.0), 1.0);
- EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, 0, 1.0), 1.0);
- EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, 0, 1.0), 1.0);
- EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, 0, 1.0), 1.0);
-
- // Negative value tests
- EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, -100, -1), -99);
- EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, -100, -1), -99);
- EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, -2.0, -1.0), -2.0);
- EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, -2.0, -1.0), -2.0);
- EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, -2.0, -1.0), -2.0);
- EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, -2.0, -1.0), -2.0);
-
- EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, -100, -1), -100);
- EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, -100, -1), -100);
- EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, -2.0, -1.0), -2.0);
- EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, -2.0, -1.0), -2.0);
- EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, -2.0, -1.0),
- -2.0);
- EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, -2.0, -1.0), -2.0);
-
- EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, -100, -1), -2);
- EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, -100, -1), -2);
- EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, -2.0, -1.0), -1.0);
- EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, -2.0, -1.0), -1.0);
- EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, -2.0, -1.0), -1.0);
- EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, -2.0, -1.0), -1.0);
-
- EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, -100, -1), -1);
- EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, -100, -1), -1);
- EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, -2.0, -1.0), -1.0);
- EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, -2.0, -1.0), -1.0);
- EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, -2.0, -1.0), -1.0);
- EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, -2.0, -1.0),
- -1.0);
-
- // Edge cases: the next value toward itself is itself.
- const double d = 1.0;
- const float f = 1.0;
- EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, d, d), d);
- EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, f, f), f);
-
- EXPECT_GT(uniform_lower_bound(IntervalOpenClosed, 1.0, 2.0), 1.0);
- EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, +0.0), 1.0);
- EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -0.0), 1.0);
- EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -1.0), 1.0);
-
- EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0.0f,
- std::numeric_limits<float>::max()),
- std::numeric_limits<float>::max());
- EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0.0,
- std::numeric_limits<double>::max()),
- std::numeric_limits<double>::max());
-}
struct Invalid {};
@@ -284,7 +196,9 @@ TEST_F(RandomDistributionsTest, UniformTypeInference) {
// Properly promotes float.
CheckArgsInferType<float, double, double>();
+}
+TEST_F(RandomDistributionsTest, UniformExamples) {
// Examples.
absl::InsecureBitGen gen;
EXPECT_NE(1, absl::Uniform(gen, static_cast<uint16_t>(0), 1.0f));
@@ -307,6 +221,58 @@ TEST_F(RandomDistributionsTest, UniformNoBounds) {
absl::Uniform<uint64_t>(gen);
}
+TEST_F(RandomDistributionsTest, UniformNonsenseRanges) {
+ // The ranges used in this test are undefined behavior.
+ // The results are arbitrary and subject to future changes.
+ absl::InsecureBitGen gen;
+
+ // <uint>
+ EXPECT_EQ(0, absl::Uniform<uint64_t>(gen, 0, 0));
+ EXPECT_EQ(1, absl::Uniform<uint64_t>(gen, 1, 0));
+ EXPECT_EQ(0, absl::Uniform<uint64_t>(absl::IntervalOpenOpen, gen, 0, 0));
+ EXPECT_EQ(1, absl::Uniform<uint64_t>(absl::IntervalOpenOpen, gen, 1, 0));
+
+ constexpr auto m = (std::numeric_limits<uint64_t>::max)();
+
+ EXPECT_EQ(m, absl::Uniform(gen, m, m));
+ EXPECT_EQ(m, absl::Uniform(gen, m, m - 1));
+ EXPECT_EQ(m - 1, absl::Uniform(gen, m - 1, m));
+ EXPECT_EQ(m, absl::Uniform(absl::IntervalOpenOpen, gen, m, m));
+ EXPECT_EQ(m, absl::Uniform(absl::IntervalOpenOpen, gen, m, m - 1));
+ EXPECT_EQ(m - 1, absl::Uniform(absl::IntervalOpenOpen, gen, m - 1, m));
+
+ // <int>
+ EXPECT_EQ(0, absl::Uniform<int64_t>(gen, 0, 0));
+ EXPECT_EQ(1, absl::Uniform<int64_t>(gen, 1, 0));
+ EXPECT_EQ(0, absl::Uniform<int64_t>(absl::IntervalOpenOpen, gen, 0, 0));
+ EXPECT_EQ(1, absl::Uniform<int64_t>(absl::IntervalOpenOpen, gen, 1, 0));
+
+ constexpr auto l = (std::numeric_limits<int64_t>::min)();
+ constexpr auto r = (std::numeric_limits<int64_t>::max)();
+
+ EXPECT_EQ(l, absl::Uniform(gen, l, l));
+ EXPECT_EQ(r, absl::Uniform(gen, r, r));
+ EXPECT_EQ(r, absl::Uniform(gen, r, r - 1));
+ EXPECT_EQ(r - 1, absl::Uniform(gen, r - 1, r));
+ EXPECT_EQ(l, absl::Uniform(absl::IntervalOpenOpen, gen, l, l));
+ EXPECT_EQ(r, absl::Uniform(absl::IntervalOpenOpen, gen, r, r));
+ EXPECT_EQ(r, absl::Uniform(absl::IntervalOpenOpen, gen, r, r - 1));
+ EXPECT_EQ(r - 1, absl::Uniform(absl::IntervalOpenOpen, gen, r - 1, r));
+
+ // <double>
+ const double e = std::nextafter(1.0, 2.0); // 1 + epsilon
+ const double f = std::nextafter(1.0, 0.0); // 1 - epsilon
+ const double g = std::numeric_limits<double>::denorm_min();
+
+ EXPECT_EQ(1.0, absl::Uniform(gen, 1.0, e));
+ EXPECT_EQ(1.0, absl::Uniform(gen, 1.0, f));
+ EXPECT_EQ(0.0, absl::Uniform(gen, 0.0, g));
+
+ EXPECT_EQ(e, absl::Uniform(absl::IntervalOpenOpen, gen, 1.0, e));
+ EXPECT_EQ(f, absl::Uniform(absl::IntervalOpenOpen, gen, 1.0, f));
+ EXPECT_EQ(g, absl::Uniform(absl::IntervalOpenOpen, gen, 0.0, g));
+}
+
// TODO(lar): Validate properties of non-default interval-semantics.
TEST_F(RandomDistributionsTest, UniformReal) {
std::vector<double> values(kSize);