tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

gaussian_distribution_test.cc (20105B)


      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/gaussian_distribution.h"
     16 
     17 #include <algorithm>
     18 #include <cmath>
     19 #include <cstddef>
     20 #include <ios>
     21 #include <iterator>
     22 #include <random>
     23 #include <string>
     24 #include <type_traits>
     25 #include <vector>
     26 
     27 #include "gmock/gmock.h"
     28 #include "gtest/gtest.h"
     29 #include "absl/base/macros.h"
     30 #include "absl/log/log.h"
     31 #include "absl/numeric/internal/representation.h"
     32 #include "absl/random/internal/chi_square.h"
     33 #include "absl/random/internal/distribution_test_util.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 namespace {
     42 
     43 using absl::random_internal::kChiSquared;
     44 
     45 template <typename RealType>
     46 class GaussianDistributionInterfaceTest : public ::testing::Test {};
     47 
     48 // double-double arithmetic is not supported well by either GCC or Clang; see
     49 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99048,
     50 // https://bugs.llvm.org/show_bug.cgi?id=49131, and
     51 // https://bugs.llvm.org/show_bug.cgi?id=49132. Don't bother running these tests
     52 // with double doubles until compiler support is better.
     53 using RealTypes =
     54    std::conditional<absl::numeric_internal::IsDoubleDouble(),
     55                     ::testing::Types<float, double>,
     56                     ::testing::Types<float, double, long double>>::type;
     57 TYPED_TEST_SUITE(GaussianDistributionInterfaceTest, RealTypes);
     58 
     59 TYPED_TEST(GaussianDistributionInterfaceTest, SerializeTest) {
     60  using param_type =
     61      typename absl::gaussian_distribution<TypeParam>::param_type;
     62 
     63  const TypeParam kParams[] = {
     64      // Cases around 1.
     65      1,                                           //
     66      std::nextafter(TypeParam(1), TypeParam(0)),  // 1 - epsilon
     67      std::nextafter(TypeParam(1), TypeParam(2)),  // 1 + epsilon
     68      // Arbitrary values.
     69      TypeParam(1e-8), TypeParam(1e-4), TypeParam(2), TypeParam(1e4),
     70      TypeParam(1e8), TypeParam(1e20), TypeParam(2.5),
     71      // Boundary cases.
     72      std::numeric_limits<TypeParam>::infinity(),
     73      std::numeric_limits<TypeParam>::max(),
     74      std::numeric_limits<TypeParam>::epsilon(),
     75      std::nextafter(std::numeric_limits<TypeParam>::min(),
     76                     TypeParam(1)),           // min + epsilon
     77      std::numeric_limits<TypeParam>::min(),  // smallest normal
     78      // There are some errors dealing with denorms on apple platforms.
     79      std::numeric_limits<TypeParam>::denorm_min(),  // smallest denorm
     80      std::numeric_limits<TypeParam>::min() / 2,
     81      std::nextafter(std::numeric_limits<TypeParam>::min(),
     82                     TypeParam(0)),  // denorm_max
     83  };
     84 
     85  constexpr int kCount = 1000;
     86  absl::InsecureBitGen gen;
     87 
     88  // Use a loop to generate the combinations of {+/-x, +/-y}, and assign x, y to
     89  // all values in kParams,
     90  for (const auto mod : {0, 1, 2, 3}) {
     91    for (const auto x : kParams) {
     92      if (!std::isfinite(x)) continue;
     93      for (const auto y : kParams) {
     94        const TypeParam mean = (mod & 0x1) ? -x : x;
     95        const TypeParam stddev = (mod & 0x2) ? -y : y;
     96        const param_type param(mean, stddev);
     97 
     98        absl::gaussian_distribution<TypeParam> before(mean, stddev);
     99        EXPECT_EQ(before.mean(), param.mean());
    100        EXPECT_EQ(before.stddev(), param.stddev());
    101 
    102        {
    103          absl::gaussian_distribution<TypeParam> via_param(param);
    104          EXPECT_EQ(via_param, before);
    105          EXPECT_EQ(via_param.param(), before.param());
    106        }
    107 
    108        // Smoke test.
    109        auto sample_min = before.max();
    110        auto sample_max = before.min();
    111        for (int i = 0; i < kCount; i++) {
    112          auto sample = before(gen);
    113          if (sample > sample_max) sample_max = sample;
    114          if (sample < sample_min) sample_min = sample;
    115          EXPECT_GE(sample, before.min()) << before;
    116          EXPECT_LE(sample, before.max()) << before;
    117        }
    118        if (!std::is_same<TypeParam, long double>::value) {
    119          LOG(INFO) << "Range{" << mean << ", " << stddev << "}: " << sample_min
    120                    << ", " << sample_max;
    121        }
    122 
    123        std::stringstream ss;
    124        ss << before;
    125 
    126        if (!std::isfinite(mean) || !std::isfinite(stddev)) {
    127          // Streams do not parse inf/nan.
    128          continue;
    129        }
    130 
    131        // Validate stream serialization.
    132        absl::gaussian_distribution<TypeParam> after(-0.53f, 2.3456f);
    133 
    134        EXPECT_NE(before.mean(), after.mean());
    135        EXPECT_NE(before.stddev(), after.stddev());
    136        EXPECT_NE(before.param(), after.param());
    137        EXPECT_NE(before, after);
    138 
    139        ss >> after;
    140 
    141        EXPECT_EQ(before.mean(), after.mean());
    142        EXPECT_EQ(before.stddev(), after.stddev())  //
    143            << ss.str() << " "                      //
    144            << (ss.good() ? "good " : "")           //
    145            << (ss.bad() ? "bad " : "")             //
    146            << (ss.eof() ? "eof " : "")             //
    147            << (ss.fail() ? "fail " : "");
    148      }
    149    }
    150  }
    151 }
    152 
    153 // http://www.itl.nist.gov/div898/handbook/eda/section3/eda3661.htm
    154 
    155 class GaussianModel {
    156 public:
    157  GaussianModel(double mean, double stddev) : mean_(mean), stddev_(stddev) {}
    158 
    159  double mean() const { return mean_; }
    160  double variance() const { return stddev() * stddev(); }
    161  double stddev() const { return stddev_; }
    162  double skew() const { return 0; }
    163  double kurtosis() const { return 3.0; }
    164 
    165  // The inverse CDF, or PercentPoint function.
    166  double InverseCDF(double p) {
    167    ABSL_ASSERT(p >= 0.0);
    168    ABSL_ASSERT(p < 1.0);
    169    return mean() + stddev() * -absl::random_internal::InverseNormalSurvival(p);
    170  }
    171 
    172 private:
    173  const double mean_;
    174  const double stddev_;
    175 };
    176 
    177 struct Param {
    178  double mean;
    179  double stddev;
    180  double p_fail;  // Z-Test probability of failure.
    181  int trials;     // Z-Test trials.
    182 };
    183 
    184 // GaussianDistributionTests implements a z-test for the gaussian
    185 // distribution.
    186 class GaussianDistributionTests : public testing::TestWithParam<Param>,
    187                                  public GaussianModel {
    188 public:
    189  GaussianDistributionTests()
    190      : GaussianModel(GetParam().mean, GetParam().stddev) {}
    191 
    192  // SingleZTest provides a basic z-squared test of the mean vs. expected
    193  // mean for data generated by the poisson distribution.
    194  template <typename D>
    195  bool SingleZTest(const double p, const size_t samples);
    196 
    197  // SingleChiSquaredTest provides a basic chi-squared test of the normal
    198  // distribution.
    199  template <typename D>
    200  double SingleChiSquaredTest();
    201 
    202  // We use a fixed bit generator for distribution accuracy tests.  This allows
    203  // these tests to be deterministic, while still testing the qualify of the
    204  // implementation.
    205  absl::random_internal::pcg64_2018_engine rng_{0x2B7E151628AED2A6};
    206 };
    207 
    208 template <typename D>
    209 bool GaussianDistributionTests::SingleZTest(const double p,
    210                                            const size_t samples) {
    211  D dis(mean(), stddev());
    212 
    213  std::vector<double> data;
    214  data.reserve(samples);
    215  for (size_t i = 0; i < samples; i++) {
    216    const double x = dis(rng_);
    217    data.push_back(x);
    218  }
    219 
    220  const double max_err = absl::random_internal::MaxErrorTolerance(p);
    221  const auto m = absl::random_internal::ComputeDistributionMoments(data);
    222  const double z = absl::random_internal::ZScore(mean(), m);
    223  const bool pass = absl::random_internal::Near("z", z, 0.0, max_err);
    224 
    225  // NOTE: Informational statistical test:
    226  //
    227  // Compute the Jarque-Bera test statistic given the excess skewness
    228  // and kurtosis. The statistic is drawn from a chi-square(2) distribution.
    229  // https://en.wikipedia.org/wiki/Jarque%E2%80%93Bera_test
    230  //
    231  // The null-hypothesis (normal distribution) is rejected when
    232  // (p = 0.05 => jb > 5.99)
    233  // (p = 0.01 => jb > 9.21)
    234  // NOTE: JB has a large type-I error rate, so it will reject the
    235  // null-hypothesis even when it is true more often than the z-test.
    236  //
    237  const double jb =
    238      static_cast<double>(m.n) / 6.0 *
    239      (std::pow(m.skewness, 2.0) + std::pow(m.kurtosis - 3.0, 2.0) / 4.0);
    240 
    241  if (!pass || jb > 9.21) {
    242    // clang-format off
    243    LOG(INFO)
    244        << "p=" << p << " max_err=" << max_err << "\n"
    245           " mean=" << m.mean << " vs. " << mean() << "\n"
    246           " stddev=" << std::sqrt(m.variance) << " vs. " << stddev() << "\n"
    247           " skewness=" << m.skewness << " vs. " << skew() << "\n"
    248           " kurtosis=" << m.kurtosis << " vs. " << kurtosis() << "\n"
    249           " z=" << z << " vs. 0\n"
    250           " jb=" << jb << " vs. 9.21";
    251    // clang-format on
    252  }
    253  return pass;
    254 }
    255 
    256 template <typename D>
    257 double GaussianDistributionTests::SingleChiSquaredTest() {
    258  const size_t kSamples = 10000;
    259  const int kBuckets = 50;
    260 
    261  // The InverseCDF is the percent point function of the
    262  // distribution, and can be used to assign buckets
    263  // roughly uniformly.
    264  std::vector<double> cutoffs;
    265  const double kInc = 1.0 / static_cast<double>(kBuckets);
    266  for (double p = kInc; p < 1.0; p += kInc) {
    267    cutoffs.push_back(InverseCDF(p));
    268  }
    269  if (cutoffs.back() != std::numeric_limits<double>::infinity()) {
    270    cutoffs.push_back(std::numeric_limits<double>::infinity());
    271  }
    272 
    273  D dis(mean(), stddev());
    274 
    275  std::vector<int32_t> counts(cutoffs.size(), 0);
    276  for (int j = 0; j < kSamples; j++) {
    277    const double x = dis(rng_);
    278    auto it = std::upper_bound(cutoffs.begin(), cutoffs.end(), x);
    279    counts[std::distance(cutoffs.begin(), it)]++;
    280  }
    281 
    282  // Null-hypothesis is that the distribution is a gaussian distribution
    283  // with the provided mean and stddev (not estimated from the data).
    284  const int dof = static_cast<int>(counts.size()) - 1;
    285 
    286  // Our threshold for logging is 1-in-50.
    287  const double threshold = absl::random_internal::ChiSquareValue(dof, 0.98);
    288 
    289  const double expected =
    290      static_cast<double>(kSamples) / static_cast<double>(counts.size());
    291 
    292  double chi_square = absl::random_internal::ChiSquareWithExpected(
    293      std::begin(counts), std::end(counts), expected);
    294  double p = absl::random_internal::ChiSquarePValue(chi_square, dof);
    295 
    296  // Log if the chi_square value is above the threshold.
    297  if (chi_square > threshold) {
    298    for (size_t i = 0; i < cutoffs.size(); i++) {
    299      LOG(INFO) << i << " : (" << cutoffs[i] << ") = " << counts[i];
    300    }
    301 
    302    // clang-format off
    303    LOG(INFO) << "mean=" << mean() << " stddev=" << stddev() << "\n"
    304                 " expected " << expected << "\n"
    305              << kChiSquared << " " << chi_square << " (" << p << ")\n"
    306              << kChiSquared << " @ 0.98 = " << threshold;
    307    // clang-format on
    308  }
    309  return p;
    310 }
    311 
    312 TEST_P(GaussianDistributionTests, ZTest) {
    313  // TODO(absl-team): Run these tests against std::normal_distribution<double>
    314  // to validate outcomes are similar.
    315  const size_t kSamples = 10000;
    316  const auto& param = GetParam();
    317  const int expected_failures =
    318      std::max(1, static_cast<int>(std::ceil(param.trials * param.p_fail)));
    319  const double p = absl::random_internal::RequiredSuccessProbability(
    320      param.p_fail, param.trials);
    321 
    322  int failures = 0;
    323  for (int i = 0; i < param.trials; i++) {
    324    failures +=
    325        SingleZTest<absl::gaussian_distribution<double>>(p, kSamples) ? 0 : 1;
    326  }
    327  EXPECT_LE(failures, expected_failures);
    328 }
    329 
    330 TEST_P(GaussianDistributionTests, ChiSquaredTest) {
    331  const int kTrials = 20;
    332  int failures = 0;
    333 
    334  for (int i = 0; i < kTrials; i++) {
    335    double p_value =
    336        SingleChiSquaredTest<absl::gaussian_distribution<double>>();
    337    if (p_value < 0.0025) {  // 1/400
    338      failures++;
    339    }
    340  }
    341  // There is a 0.05% chance of producing at least one failure, so raise the
    342  // failure threshold high enough to allow for a flake rate of less than one in
    343  // 10,000.
    344  EXPECT_LE(failures, 4);
    345 }
    346 
    347 std::vector<Param> GenParams() {
    348  return {
    349      // Mean around 0.
    350      Param{0.0, 1.0, 0.01, 100},
    351      Param{0.0, 1e2, 0.01, 100},
    352      Param{0.0, 1e4, 0.01, 100},
    353      Param{0.0, 1e8, 0.01, 100},
    354      Param{0.0, 1e16, 0.01, 100},
    355      Param{0.0, 1e-3, 0.01, 100},
    356      Param{0.0, 1e-5, 0.01, 100},
    357      Param{0.0, 1e-9, 0.01, 100},
    358      Param{0.0, 1e-17, 0.01, 100},
    359 
    360      // Mean around 1.
    361      Param{1.0, 1.0, 0.01, 100},
    362      Param{1.0, 1e2, 0.01, 100},
    363      Param{1.0, 1e-2, 0.01, 100},
    364 
    365      // Mean around 100 / -100
    366      Param{1e2, 1.0, 0.01, 100},
    367      Param{-1e2, 1.0, 0.01, 100},
    368      Param{1e2, 1e6, 0.01, 100},
    369      Param{-1e2, 1e6, 0.01, 100},
    370 
    371      // More extreme
    372      Param{1e4, 1e4, 0.01, 100},
    373      Param{1e8, 1e4, 0.01, 100},
    374      Param{1e12, 1e4, 0.01, 100},
    375  };
    376 }
    377 
    378 std::string ParamName(const ::testing::TestParamInfo<Param>& info) {
    379  const auto& p = info.param;
    380  std::string name = absl::StrCat("mean_", absl::SixDigits(p.mean), "__stddev_",
    381                                  absl::SixDigits(p.stddev));
    382  return absl::StrReplaceAll(name, {{"+", "_"}, {"-", "_"}, {".", "_"}});
    383 }
    384 
    385 INSTANTIATE_TEST_SUITE_P(All, GaussianDistributionTests,
    386                         ::testing::ValuesIn(GenParams()), ParamName);
    387 
    388 // NOTE: absl::gaussian_distribution is not guaranteed to be stable.
    389 TEST(GaussianDistributionTest, StabilityTest) {
    390  // absl::gaussian_distribution stability relies on the underlying zignor
    391  // data, absl::random_interna::RandU64ToDouble, std::exp, std::log, and
    392  // std::abs.
    393  absl::random_internal::sequence_urbg urbg(
    394      {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
    395       0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
    396       0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
    397       0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
    398 
    399  std::vector<int> output(11);
    400 
    401  {
    402    absl::gaussian_distribution<double> dist;
    403    std::generate(std::begin(output), std::end(output),
    404                  [&] { return static_cast<int>(10000000.0 * dist(urbg)); });
    405 
    406    EXPECT_EQ(13, urbg.invocations());
    407    EXPECT_THAT(output,  //
    408                testing::ElementsAre(1494, 25518841, 9991550, 1351856,
    409                                     -20373238, 3456682, 333530, -6804981,
    410                                     -15279580, -16459654, 1494));
    411  }
    412 
    413  urbg.reset();
    414  {
    415    absl::gaussian_distribution<float> dist;
    416    std::generate(std::begin(output), std::end(output),
    417                  [&] { return static_cast<int>(1000000.0f * dist(urbg)); });
    418 
    419    EXPECT_EQ(13, urbg.invocations());
    420    EXPECT_THAT(
    421        output,  //
    422        testing::ElementsAre(149, 2551884, 999155, 135185, -2037323, 345668,
    423                             33353, -680498, -1527958, -1645965, 149));
    424  }
    425 }
    426 
    427 // This is an implementation-specific test. If any part of the implementation
    428 // changes, then it is likely that this test will change as well.
    429 // Also, if dependencies of the distribution change, such as RandU64ToDouble,
    430 // then this is also likely to change.
    431 TEST(GaussianDistributionTest, AlgorithmBounds) {
    432  absl::gaussian_distribution<double> dist;
    433 
    434  // In ~95% of cases, a single value is used to generate the output.
    435  // for all inputs where |x| < 0.750461021389 this should be the case.
    436  //
    437  // The exact constraints are based on the ziggurat tables, and any
    438  // changes to the ziggurat tables may require adjusting these bounds.
    439  //
    440  // for i in range(0, len(X)-1):
    441  //   print i, X[i+1]/X[i], (X[i+1]/X[i] > 0.984375)
    442  //
    443  // 0.125 <= |values| <= 0.75
    444  const uint64_t kValues[] = {
    445      0x1000000000000100ull, 0x2000000000000100ull, 0x3000000000000100ull,
    446      0x4000000000000100ull, 0x5000000000000100ull, 0x6000000000000100ull,
    447      // negative values
    448      0x9000000000000100ull, 0xa000000000000100ull, 0xb000000000000100ull,
    449      0xc000000000000100ull, 0xd000000000000100ull, 0xe000000000000100ull};
    450 
    451  // 0.875 <= |values| <= 0.984375
    452  const uint64_t kExtraValues[] = {
    453      0x7000000000000100ull, 0x7800000000000100ull,  //
    454      0x7c00000000000100ull, 0x7e00000000000100ull,  //
    455      // negative values
    456      0xf000000000000100ull, 0xf800000000000100ull,  //
    457      0xfc00000000000100ull, 0xfe00000000000100ull};
    458 
    459  auto make_box = [](uint64_t v, uint64_t box) {
    460    return (v & 0xffffffffffffff80ull) | box;
    461  };
    462 
    463  // The box is the lower 7 bits of the value. When the box == 0, then
    464  // the algorithm uses an escape hatch to select the result for large
    465  // outputs.
    466  for (uint64_t box = 0; box < 0x7f; box++) {
    467    for (const uint64_t v : kValues) {
    468      // Extra values are added to the sequence to attempt to avoid
    469      // infinite loops from rejection sampling on bugs/errors.
    470      absl::random_internal::sequence_urbg urbg(
    471          {make_box(v, box), 0x0003eb76f6f7f755ull, 0x5FCEA50FDB2F953Bull});
    472 
    473      auto a = dist(urbg);
    474      EXPECT_EQ(1, urbg.invocations()) << box << " " << std::hex << v;
    475      if (v & 0x8000000000000000ull) {
    476        EXPECT_LT(a, 0.0) << box << " " << std::hex << v;
    477      } else {
    478        EXPECT_GT(a, 0.0) << box << " " << std::hex << v;
    479      }
    480    }
    481    if (box > 10 && box < 100) {
    482      // The center boxes use the fast algorithm for more
    483      // than 98.4375% of values.
    484      for (const uint64_t v : kExtraValues) {
    485        absl::random_internal::sequence_urbg urbg(
    486            {make_box(v, box), 0x0003eb76f6f7f755ull, 0x5FCEA50FDB2F953Bull});
    487 
    488        auto a = dist(urbg);
    489        EXPECT_EQ(1, urbg.invocations()) << box << " " << std::hex << v;
    490        if (v & 0x8000000000000000ull) {
    491          EXPECT_LT(a, 0.0) << box << " " << std::hex << v;
    492        } else {
    493          EXPECT_GT(a, 0.0) << box << " " << std::hex << v;
    494        }
    495      }
    496    }
    497  }
    498 
    499  // When the box == 0, the fallback algorithm uses a ratio of uniforms,
    500  // which consumes 2 additional values from the urbg.
    501  // Fallback also requires that the initial value be > 0.9271586026096681.
    502  auto make_fallback = [](uint64_t v) { return (v & 0xffffffffffffff80ull); };
    503 
    504  double tail[2];
    505  {
    506    // 0.9375
    507    absl::random_internal::sequence_urbg urbg(
    508        {make_fallback(0x7800000000000000ull), 0x13CCA830EB61BD96ull,
    509         0x00000076f6f7f755ull});
    510    tail[0] = dist(urbg);
    511    EXPECT_EQ(3, urbg.invocations());
    512    EXPECT_GT(tail[0], 0);
    513  }
    514  {
    515    // -0.9375
    516    absl::random_internal::sequence_urbg urbg(
    517        {make_fallback(0xf800000000000000ull), 0x13CCA830EB61BD96ull,
    518         0x00000076f6f7f755ull});
    519    tail[1] = dist(urbg);
    520    EXPECT_EQ(3, urbg.invocations());
    521    EXPECT_LT(tail[1], 0);
    522  }
    523  EXPECT_EQ(tail[0], -tail[1]);
    524  EXPECT_EQ(418610, static_cast<int64_t>(tail[0] * 100000.0));
    525 
    526  // When the box != 0, the fallback algorithm computes a wedge function.
    527  // Depending on the box, the threshold for varies as high as
    528  // 0.991522480228.
    529  {
    530    // 0.9921875, 0.875
    531    absl::random_internal::sequence_urbg urbg(
    532        {make_box(0x7f00000000000000ull, 120), 0xe000000000000001ull,
    533         0x13CCA830EB61BD96ull});
    534    tail[0] = dist(urbg);
    535    EXPECT_EQ(2, urbg.invocations());
    536    EXPECT_GT(tail[0], 0);
    537  }
    538  {
    539    // -0.9921875, 0.875
    540    absl::random_internal::sequence_urbg urbg(
    541        {make_box(0xff00000000000000ull, 120), 0xe000000000000001ull,
    542         0x13CCA830EB61BD96ull});
    543    tail[1] = dist(urbg);
    544    EXPECT_EQ(2, urbg.invocations());
    545    EXPECT_LT(tail[1], 0);
    546  }
    547  EXPECT_EQ(tail[0], -tail[1]);
    548  EXPECT_EQ(61948, static_cast<int64_t>(tail[0] * 100000.0));
    549 
    550  // Fallback rejected, try again.
    551  {
    552    // -0.9921875, 0.0625
    553    absl::random_internal::sequence_urbg urbg(
    554        {make_box(0xff00000000000000ull, 120), 0x1000000000000001,
    555         make_box(0x1000000000000100ull, 50), 0x13CCA830EB61BD96ull});
    556    dist(urbg);
    557    EXPECT_EQ(3, urbg.invocations());
    558  }
    559 }
    560 
    561 }  // namespace