uniform_helper_test.cc (12329B)
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/internal/uniform_helper.h" 16 17 #include <cmath> 18 #include <cstdint> 19 #include <random> 20 21 #include "gtest/gtest.h" 22 23 namespace { 24 25 using absl::IntervalClosedClosedTag; 26 using absl::IntervalClosedOpenTag; 27 using absl::IntervalOpenClosedTag; 28 using absl::IntervalOpenOpenTag; 29 using absl::random_internal::uniform_inferred_return_t; 30 using absl::random_internal::uniform_lower_bound; 31 using absl::random_internal::uniform_upper_bound; 32 33 class UniformHelperTest : public testing::Test {}; 34 35 TEST_F(UniformHelperTest, UniformBoundFunctionsGeneral) { 36 constexpr IntervalClosedClosedTag IntervalClosedClosed; 37 constexpr IntervalClosedOpenTag IntervalClosedOpen; 38 constexpr IntervalOpenClosedTag IntervalOpenClosed; 39 constexpr IntervalOpenOpenTag IntervalOpenOpen; 40 41 // absl::uniform_int_distribution natively assumes IntervalClosedClosed 42 // absl::uniform_real_distribution natively assumes IntervalClosedOpen 43 44 EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, 0, 100), 1); 45 EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, 0, 100), 1); 46 EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, 0, 1.0), 0); 47 EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, 0, 1.0), 0); 48 EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, 0, 1.0), 0); 49 EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, 0, 1.0), 0); 50 51 EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, 0, 100), 0); 52 EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, 0, 100), 0); 53 EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, 0, 1.0), 0); 54 EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, 0, 1.0), 0); 55 EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, 0, 1.0), 0); 56 EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, 0, 1.0), 0); 57 58 EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, 0, 100), 99); 59 EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, 0, 100), 99); 60 EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, 0, 1.0), 1.0); 61 EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, 0, 1.0), 1.0); 62 EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, 0, 1.0), 1.0); 63 EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, 0, 1.0), 1.0); 64 65 EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, 0, 100), 100); 66 EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0, 100), 100); 67 EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, 0, 1.0), 1.0); 68 EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, 0, 1.0), 1.0); 69 EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, 0, 1.0), 1.0); 70 EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, 0, 1.0), 1.0); 71 72 // Negative value tests 73 EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, -100, -1), -99); 74 EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, -100, -1), -99); 75 EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, -2.0, -1.0), -2.0); 76 EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, -2.0, -1.0), -2.0); 77 EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, -2.0, -1.0), -2.0); 78 EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, -2.0, -1.0), -2.0); 79 80 EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, -100, -1), -100); 81 EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, -100, -1), -100); 82 EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, -2.0, -1.0), -2.0); 83 EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, -2.0, -1.0), -2.0); 84 EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, -2.0, -1.0), 85 -2.0); 86 EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, -2.0, -1.0), -2.0); 87 88 EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, -100, -1), -2); 89 EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, -100, -1), -2); 90 EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, -2.0, -1.0), -1.0); 91 EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, -2.0, -1.0), -1.0); 92 EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, -2.0, -1.0), -1.0); 93 EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, -2.0, -1.0), -1.0); 94 95 EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, -100, -1), -1); 96 EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, -100, -1), -1); 97 EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, -2.0, -1.0), -1.0); 98 EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, -2.0, -1.0), -1.0); 99 EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, -2.0, -1.0), -1.0); 100 EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, -2.0, -1.0), 101 -1.0); 102 103 EXPECT_GT(uniform_lower_bound(IntervalOpenClosed, 1.0, 2.0), 1.0); 104 EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, +0.0), 1.0); 105 EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -0.0), 1.0); 106 EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -1.0), 1.0); 107 } 108 109 TEST_F(UniformHelperTest, UniformBoundFunctionsIntBounds) { 110 // Verifies the saturating nature of uniform_lower_bound and 111 // uniform_upper_bound 112 constexpr IntervalOpenOpenTag IntervalOpenOpen; 113 114 // uint max. 115 constexpr auto m = (std::numeric_limits<uint64_t>::max)(); 116 117 EXPECT_EQ(1, uniform_lower_bound(IntervalOpenOpen, 0u, 0u)); 118 EXPECT_EQ(m, uniform_lower_bound(IntervalOpenOpen, m, m)); 119 EXPECT_EQ(m, uniform_lower_bound(IntervalOpenOpen, m - 1, m - 1)); 120 EXPECT_EQ(0, uniform_upper_bound(IntervalOpenOpen, 0u, 0u)); 121 EXPECT_EQ(m - 1, uniform_upper_bound(IntervalOpenOpen, m, m)); 122 123 // int min/max 124 constexpr auto l = (std::numeric_limits<int64_t>::min)(); 125 constexpr auto r = (std::numeric_limits<int64_t>::max)(); 126 EXPECT_EQ(1, uniform_lower_bound(IntervalOpenOpen, 0, 0)); 127 EXPECT_EQ(l + 1, uniform_lower_bound(IntervalOpenOpen, l, l)); 128 EXPECT_EQ(r, uniform_lower_bound(IntervalOpenOpen, r - 1, r - 1)); 129 EXPECT_EQ(r, uniform_lower_bound(IntervalOpenOpen, r, r)); 130 EXPECT_EQ(-1, uniform_upper_bound(IntervalOpenOpen, 0, 0)); 131 EXPECT_EQ(l, uniform_upper_bound(IntervalOpenOpen, l, l)); 132 EXPECT_EQ(r - 1, uniform_upper_bound(IntervalOpenOpen, r, r)); 133 } 134 135 TEST_F(UniformHelperTest, UniformBoundFunctionsRealBounds) { 136 // absl::uniform_real_distribution natively assumes IntervalClosedOpen; 137 // use the inverse here so each bound has to change. 138 constexpr IntervalOpenClosedTag IntervalOpenClosed; 139 140 // Edge cases: the next value toward itself is itself. 141 EXPECT_EQ(1.0, uniform_lower_bound(IntervalOpenClosed, 1.0, 1.0)); 142 EXPECT_EQ(1.0f, uniform_lower_bound(IntervalOpenClosed, 1.0f, 1.0f)); 143 144 // rightmost and leftmost finite values. 145 constexpr auto r = (std::numeric_limits<double>::max)(); 146 const auto re = std::nexttoward(r, 0.0); 147 constexpr auto l = -r; 148 const auto le = std::nexttoward(l, 0.0); 149 150 EXPECT_EQ(l, uniform_lower_bound(IntervalOpenClosed, l, l)); // (l,l) 151 EXPECT_EQ(r, uniform_lower_bound(IntervalOpenClosed, r, r)); // (r,r) 152 EXPECT_EQ(le, uniform_lower_bound(IntervalOpenClosed, l, r)); // (l,r) 153 EXPECT_EQ(le, uniform_lower_bound(IntervalOpenClosed, l, 0.0)); // (l, 0) 154 EXPECT_EQ(le, uniform_lower_bound(IntervalOpenClosed, l, le)); // (l, le) 155 EXPECT_EQ(r, uniform_lower_bound(IntervalOpenClosed, re, r)); // (re, r) 156 157 EXPECT_EQ(le, uniform_upper_bound(IntervalOpenClosed, l, l)); // (l,l) 158 EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, r, r)); // (r,r) 159 EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, l, r)); // (l,r) 160 EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, l, re)); // (l,re) 161 EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, 0.0, r)); // (0, r) 162 EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, re, r)); // (re, r) 163 EXPECT_EQ(r, uniform_upper_bound(IntervalOpenClosed, le, re)); // (le, re) 164 165 const double e = std::nextafter(1.0, 2.0); // 1 + epsilon 166 const double f = std::nextafter(1.0, 0.0); // 1 - epsilon 167 168 // (1.0, 1.0 + epsilon) 169 EXPECT_EQ(e, uniform_lower_bound(IntervalOpenClosed, 1.0, e)); 170 EXPECT_EQ(std::nextafter(e, 2.0), 171 uniform_upper_bound(IntervalOpenClosed, 1.0, e)); 172 173 // (1.0-epsilon, 1.0) 174 EXPECT_EQ(1.0, uniform_lower_bound(IntervalOpenClosed, f, 1.0)); 175 EXPECT_EQ(e, uniform_upper_bound(IntervalOpenClosed, f, 1.0)); 176 177 // denorm cases. 178 const double g = std::numeric_limits<double>::denorm_min(); 179 const double h = std::nextafter(g, 1.0); 180 181 // (0, denorm_min) 182 EXPECT_EQ(g, uniform_lower_bound(IntervalOpenClosed, 0.0, g)); 183 EXPECT_EQ(h, uniform_upper_bound(IntervalOpenClosed, 0.0, g)); 184 185 // (denorm_min, 1.0) 186 EXPECT_EQ(h, uniform_lower_bound(IntervalOpenClosed, g, 1.0)); 187 EXPECT_EQ(e, uniform_upper_bound(IntervalOpenClosed, g, 1.0)); 188 189 // Edge cases: invalid bounds. 190 EXPECT_EQ(f, uniform_lower_bound(IntervalOpenClosed, 1.0, -1.0)); 191 } 192 193 struct Invalid {}; 194 195 template <typename A, typename B> 196 auto InferredUniformReturnT(int) -> uniform_inferred_return_t<A, B>; 197 198 template <typename, typename> 199 Invalid InferredUniformReturnT(...); 200 201 // Given types <A, B, Expect>, CheckArgsInferType() verifies that 202 // 203 // uniform_inferred_return_t<A, B> and 204 // uniform_inferred_return_t<B, A> 205 // 206 // returns the type "Expect". 207 // 208 // This interface can also be used to assert that a given inferred return types 209 // are invalid. Writing: 210 // 211 // CheckArgsInferType<float, int, Invalid>() 212 // 213 // will assert that this overload does not exist. 214 template <typename A, typename B, typename Expect> 215 void CheckArgsInferType() { 216 static_assert( 217 absl::conjunction< 218 std::is_same<Expect, decltype(InferredUniformReturnT<A, B>(0))>, 219 std::is_same<Expect, 220 decltype(InferredUniformReturnT<B, A>(0))>>::value, 221 ""); 222 } 223 224 TEST_F(UniformHelperTest, UniformTypeInference) { 225 // Infers common types. 226 CheckArgsInferType<uint16_t, uint16_t, uint16_t>(); 227 CheckArgsInferType<uint32_t, uint32_t, uint32_t>(); 228 CheckArgsInferType<uint64_t, uint64_t, uint64_t>(); 229 CheckArgsInferType<int16_t, int16_t, int16_t>(); 230 CheckArgsInferType<int32_t, int32_t, int32_t>(); 231 CheckArgsInferType<int64_t, int64_t, int64_t>(); 232 CheckArgsInferType<float, float, float>(); 233 CheckArgsInferType<double, double, double>(); 234 235 // Properly promotes uint16_t. 236 CheckArgsInferType<uint16_t, uint32_t, uint32_t>(); 237 CheckArgsInferType<uint16_t, uint64_t, uint64_t>(); 238 CheckArgsInferType<uint16_t, int32_t, int32_t>(); 239 CheckArgsInferType<uint16_t, int64_t, int64_t>(); 240 CheckArgsInferType<uint16_t, float, float>(); 241 CheckArgsInferType<uint16_t, double, double>(); 242 243 // Properly promotes int16_t. 244 CheckArgsInferType<int16_t, int32_t, int32_t>(); 245 CheckArgsInferType<int16_t, int64_t, int64_t>(); 246 CheckArgsInferType<int16_t, float, float>(); 247 CheckArgsInferType<int16_t, double, double>(); 248 249 // Invalid (u)int16_t-pairings do not compile. 250 // See "CheckArgsInferType" comments above, for how this is achieved. 251 CheckArgsInferType<uint16_t, int16_t, Invalid>(); 252 CheckArgsInferType<int16_t, uint32_t, Invalid>(); 253 CheckArgsInferType<int16_t, uint64_t, Invalid>(); 254 255 // Properly promotes uint32_t. 256 CheckArgsInferType<uint32_t, uint64_t, uint64_t>(); 257 CheckArgsInferType<uint32_t, int64_t, int64_t>(); 258 CheckArgsInferType<uint32_t, double, double>(); 259 260 // Properly promotes int32_t. 261 CheckArgsInferType<int32_t, int64_t, int64_t>(); 262 CheckArgsInferType<int32_t, double, double>(); 263 264 // Invalid (u)int32_t-pairings do not compile. 265 CheckArgsInferType<uint32_t, int32_t, Invalid>(); 266 CheckArgsInferType<int32_t, uint64_t, Invalid>(); 267 CheckArgsInferType<int32_t, float, Invalid>(); 268 CheckArgsInferType<uint32_t, float, Invalid>(); 269 270 // Invalid (u)int64_t-pairings do not compile. 271 CheckArgsInferType<uint64_t, int64_t, Invalid>(); 272 CheckArgsInferType<int64_t, float, Invalid>(); 273 CheckArgsInferType<int64_t, double, Invalid>(); 274 275 // Properly promotes float. 276 CheckArgsInferType<float, double, double>(); 277 } 278 279 } // namespace