diff options
author | 2020-08-02 14:23:26 -0700 | |
---|---|---|
committer | 2020-08-03 13:24:24 -0400 | |
commit | 1995c6a3c2f9080160d9d8716504dc004e5e1ec0 (patch) | |
tree | 0b1e861b0d2c16f78d0f2e861a94a2bccf38965a /absl/random/distributions_test.cc | |
parent | 184cf2524101310a0ba315c743e82cf45fccccf8 (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.cc | 142 |
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); |