tor-browser

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

uniform_real_distribution.h (7348B)


      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 // -----------------------------------------------------------------------------
     16 // File: uniform_real_distribution.h
     17 // -----------------------------------------------------------------------------
     18 //
     19 // This header defines a class for representing a uniform floating-point
     20 // distribution over a half-open interval [a,b). You use this distribution in
     21 // combination with an Abseil random bit generator to produce random values
     22 // according to the rules of the distribution.
     23 //
     24 // `absl::uniform_real_distribution` is a drop-in replacement for the C++11
     25 // `std::uniform_real_distribution` [rand.dist.uni.real] but is considerably
     26 // faster than the libstdc++ implementation.
     27 //
     28 // Note: the standard-library version may occasionally return `1.0` when
     29 // default-initialized. See https://bugs.llvm.org//show_bug.cgi?id=18767
     30 // `absl::uniform_real_distribution` does not exhibit this behavior.
     31 
     32 #ifndef ABSL_RANDOM_UNIFORM_REAL_DISTRIBUTION_H_
     33 #define ABSL_RANDOM_UNIFORM_REAL_DISTRIBUTION_H_
     34 
     35 #include <cassert>
     36 #include <cmath>
     37 #include <cstdint>
     38 #include <istream>
     39 #include <limits>
     40 #include <ostream>
     41 #include <type_traits>
     42 
     43 #include "absl/base/config.h"
     44 #include "absl/meta/type_traits.h"
     45 #include "absl/random/internal/fast_uniform_bits.h"
     46 #include "absl/random/internal/generate_real.h"
     47 #include "absl/random/internal/iostream_state_saver.h"
     48 
     49 namespace absl {
     50 ABSL_NAMESPACE_BEGIN
     51 
     52 // absl::uniform_real_distribution<T>
     53 //
     54 // This distribution produces random floating-point values uniformly distributed
     55 // over the half-open interval [a, b).
     56 //
     57 // Example:
     58 //
     59 //   absl::BitGen gen;
     60 //
     61 //   // Use the distribution to produce a value between 0.0 (inclusive)
     62 //   // and 1.0 (exclusive).
     63 //   double value = absl::uniform_real_distribution<double>(0, 1)(gen);
     64 //
     65 template <typename RealType = double>
     66 class uniform_real_distribution {
     67 public:
     68  using result_type = RealType;
     69 
     70  class param_type {
     71   public:
     72    using distribution_type = uniform_real_distribution;
     73 
     74    explicit param_type(result_type lo = 0, result_type hi = 1)
     75        : lo_(lo), hi_(hi), range_(hi - lo) {
     76      // [rand.dist.uni.real] preconditions 2 & 3
     77      assert(lo <= hi);
     78 
     79      // NOTE: For integral types, we can promote the range to an unsigned type,
     80      // which gives full width of the range. However for real (fp) types, this
     81      // is not possible, so value generation cannot use the full range of the
     82      // real type.
     83      assert(range_ <= (std::numeric_limits<result_type>::max)());
     84    }
     85 
     86    result_type a() const { return lo_; }
     87    result_type b() const { return hi_; }
     88 
     89    friend bool operator==(const param_type& a, const param_type& b) {
     90      return a.lo_ == b.lo_ && a.hi_ == b.hi_;
     91    }
     92 
     93    friend bool operator!=(const param_type& a, const param_type& b) {
     94      return !(a == b);
     95    }
     96 
     97   private:
     98    friend class uniform_real_distribution;
     99    result_type lo_, hi_, range_;
    100 
    101    static_assert(std::is_floating_point<RealType>::value,
    102                  "Class-template absl::uniform_real_distribution<> must be "
    103                  "parameterized using a floating-point type.");
    104  };
    105 
    106  uniform_real_distribution() : uniform_real_distribution(0) {}
    107 
    108  explicit uniform_real_distribution(result_type lo, result_type hi = 1)
    109      : param_(lo, hi) {}
    110 
    111  explicit uniform_real_distribution(const param_type& param) : param_(param) {}
    112 
    113  // uniform_real_distribution<T>::reset()
    114  //
    115  // Resets the uniform real distribution. Note that this function has no effect
    116  // because the distribution already produces independent values.
    117  void reset() {}
    118 
    119  template <typename URBG>
    120  result_type operator()(URBG& gen) {  // NOLINT(runtime/references)
    121    return operator()(gen, param_);
    122  }
    123 
    124  template <typename URBG>
    125  result_type operator()(URBG& gen,  // NOLINT(runtime/references)
    126                         const param_type& p);
    127 
    128  result_type a() const { return param_.a(); }
    129  result_type b() const { return param_.b(); }
    130 
    131  param_type param() const { return param_; }
    132  void param(const param_type& params) { param_ = params; }
    133 
    134  result_type(min)() const { return a(); }
    135  result_type(max)() const { return b(); }
    136 
    137  friend bool operator==(const uniform_real_distribution& a,
    138                         const uniform_real_distribution& b) {
    139    return a.param_ == b.param_;
    140  }
    141  friend bool operator!=(const uniform_real_distribution& a,
    142                         const uniform_real_distribution& b) {
    143    return a.param_ != b.param_;
    144  }
    145 
    146 private:
    147  param_type param_;
    148  random_internal::FastUniformBits<uint64_t> fast_u64_;
    149 };
    150 
    151 // -----------------------------------------------------------------------------
    152 // Implementation details follow
    153 // -----------------------------------------------------------------------------
    154 template <typename RealType>
    155 template <typename URBG>
    156 typename uniform_real_distribution<RealType>::result_type
    157 uniform_real_distribution<RealType>::operator()(
    158    URBG& gen, const param_type& p) {  // NOLINT(runtime/references)
    159  using random_internal::GeneratePositiveTag;
    160  using random_internal::GenerateRealFromBits;
    161  using real_type =
    162      absl::conditional_t<std::is_same<RealType, float>::value, float, double>;
    163 
    164  while (true) {
    165    const result_type sample =
    166        GenerateRealFromBits<real_type, GeneratePositiveTag, true>(
    167            fast_u64_(gen));
    168    const result_type res = p.a() + (sample * p.range_);
    169    if (res < p.b() || p.range_ <= 0 || !std::isfinite(p.range_)) {
    170      return res;
    171    }
    172    // else sample rejected, try again.
    173  }
    174 }
    175 
    176 template <typename CharT, typename Traits, typename RealType>
    177 std::basic_ostream<CharT, Traits>& operator<<(
    178    std::basic_ostream<CharT, Traits>& os,  // NOLINT(runtime/references)
    179    const uniform_real_distribution<RealType>& x) {
    180  auto saver = random_internal::make_ostream_state_saver(os);
    181  os.precision(random_internal::stream_precision_helper<RealType>::kPrecision);
    182  os << x.a() << os.fill() << x.b();
    183  return os;
    184 }
    185 
    186 template <typename CharT, typename Traits, typename RealType>
    187 std::basic_istream<CharT, Traits>& operator>>(
    188    std::basic_istream<CharT, Traits>& is,     // NOLINT(runtime/references)
    189    uniform_real_distribution<RealType>& x) {  // NOLINT(runtime/references)
    190  using param_type = typename uniform_real_distribution<RealType>::param_type;
    191  using result_type = typename uniform_real_distribution<RealType>::result_type;
    192  auto saver = random_internal::make_istream_state_saver(is);
    193  auto a = random_internal::read_floating_point<result_type>(is);
    194  if (is.fail()) return is;
    195  auto b = random_internal::read_floating_point<result_type>(is);
    196  if (!is.fail()) {
    197    x.param(param_type(a, b));
    198  }
    199  return is;
    200 }
    201 ABSL_NAMESPACE_END
    202 }  // namespace absl
    203 
    204 #endif  // ABSL_RANDOM_UNIFORM_REAL_DISTRIBUTION_H_