git-subtree-dir: third_party/abseil_cpp git-subtree-mainline:ffb2ae54begit-subtree-split:768eb2ca28
		
			
				
	
	
		
			146 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright 2017 The Abseil Authors.
 | 
						|
//
 | 
						|
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
// you may not use this file except in compliance with the License.
 | 
						|
// You may obtain a copy of the License at
 | 
						|
//
 | 
						|
//      https://www.apache.org/licenses/LICENSE-2.0
 | 
						|
//
 | 
						|
// Unless required by applicable law or agreed to in writing, software
 | 
						|
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
// See the License for the specific language governing permissions and
 | 
						|
// limitations under the License.
 | 
						|
 | 
						|
#ifndef ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_
 | 
						|
#define ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_
 | 
						|
 | 
						|
// This file contains some implementation details which are used by one or more
 | 
						|
// of the absl random number distributions.
 | 
						|
 | 
						|
#include <cstdint>
 | 
						|
#include <cstring>
 | 
						|
#include <limits>
 | 
						|
#include <type_traits>
 | 
						|
 | 
						|
#include "absl/base/internal/bits.h"
 | 
						|
#include "absl/meta/type_traits.h"
 | 
						|
#include "absl/random/internal/fastmath.h"
 | 
						|
#include "absl/random/internal/traits.h"
 | 
						|
 | 
						|
namespace absl {
 | 
						|
ABSL_NAMESPACE_BEGIN
 | 
						|
namespace random_internal {
 | 
						|
 | 
						|
// Tristate tag types controlling the output of GenerateRealFromBits.
 | 
						|
struct GeneratePositiveTag {};
 | 
						|
struct GenerateNegativeTag {};
 | 
						|
struct GenerateSignedTag {};
 | 
						|
 | 
						|
// GenerateRealFromBits generates a single real value from a single 64-bit
 | 
						|
// `bits` with template fields controlling the output.
 | 
						|
//
 | 
						|
// The `SignedTag` parameter controls whether positive, negative,
 | 
						|
// or either signed/unsigned may be returned.
 | 
						|
//   When SignedTag == GeneratePositiveTag, range is U(0, 1)
 | 
						|
//   When SignedTag == GenerateNegativeTag, range is U(-1, 0)
 | 
						|
//   When SignedTag == GenerateSignedTag, range is U(-1, 1)
 | 
						|
//
 | 
						|
// When the `IncludeZero` parameter is true, the function may return 0 for some
 | 
						|
// inputs, otherwise it never returns 0.
 | 
						|
//
 | 
						|
// When a value in U(0,1) is required, use:
 | 
						|
//   Uniform64ToReal<double, PositiveValueT, true>;
 | 
						|
//
 | 
						|
// When a value in U(-1,1) is required, use:
 | 
						|
//   Uniform64ToReal<double, SignedValueT, false>;
 | 
						|
//
 | 
						|
//   This generates more distinct values than the mathematical equivalent
 | 
						|
//   `U(0, 1) * 2.0 - 1.0`.
 | 
						|
//
 | 
						|
// Scaling the result by powers of 2 (and avoiding a multiply) is also possible:
 | 
						|
//   GenerateRealFromBits<double>(..., -1);  => U(0, 0.5)
 | 
						|
//   GenerateRealFromBits<double>(..., 1);   => U(0, 2)
 | 
						|
//
 | 
						|
template <typename RealType,  // Real type, either float or double.
 | 
						|
          typename SignedTag = GeneratePositiveTag,  // Whether a positive,
 | 
						|
                                                     // negative, or signed
 | 
						|
                                                     // value is generated.
 | 
						|
          bool IncludeZero = true>
 | 
						|
inline RealType GenerateRealFromBits(uint64_t bits, int exp_bias = 0) {
 | 
						|
  using real_type = RealType;
 | 
						|
  using uint_type = absl::conditional_t<std::is_same<real_type, float>::value,
 | 
						|
                                        uint32_t, uint64_t>;
 | 
						|
 | 
						|
  static_assert(
 | 
						|
      (std::is_same<double, real_type>::value ||
 | 
						|
       std::is_same<float, real_type>::value),
 | 
						|
      "GenerateRealFromBits must be parameterized by either float or double.");
 | 
						|
 | 
						|
  static_assert(sizeof(uint_type) == sizeof(real_type),
 | 
						|
                "Mismatched unsinged and real types.");
 | 
						|
 | 
						|
  static_assert((std::numeric_limits<real_type>::is_iec559 &&
 | 
						|
                 std::numeric_limits<real_type>::radix == 2),
 | 
						|
                "RealType representation is not IEEE 754 binary.");
 | 
						|
 | 
						|
  static_assert((std::is_same<SignedTag, GeneratePositiveTag>::value ||
 | 
						|
                 std::is_same<SignedTag, GenerateNegativeTag>::value ||
 | 
						|
                 std::is_same<SignedTag, GenerateSignedTag>::value),
 | 
						|
                "");
 | 
						|
 | 
						|
  static constexpr int kExp = std::numeric_limits<real_type>::digits - 1;
 | 
						|
  static constexpr uint_type kMask = (static_cast<uint_type>(1) << kExp) - 1u;
 | 
						|
  static constexpr int kUintBits = sizeof(uint_type) * 8;
 | 
						|
 | 
						|
  int exp = exp_bias + int{std::numeric_limits<real_type>::max_exponent - 2};
 | 
						|
 | 
						|
  // Determine the sign bit.
 | 
						|
  // Depending on the SignedTag, this may use the left-most bit
 | 
						|
  // or it may be a constant value.
 | 
						|
  uint_type sign = std::is_same<SignedTag, GenerateNegativeTag>::value
 | 
						|
                       ? (static_cast<uint_type>(1) << (kUintBits - 1))
 | 
						|
                       : 0;
 | 
						|
  if (std::is_same<SignedTag, GenerateSignedTag>::value) {
 | 
						|
    if (std::is_same<uint_type, uint64_t>::value) {
 | 
						|
      sign = bits & uint64_t{0x8000000000000000};
 | 
						|
    }
 | 
						|
    if (std::is_same<uint_type, uint32_t>::value) {
 | 
						|
      const uint64_t tmp = bits & uint64_t{0x8000000000000000};
 | 
						|
      sign = static_cast<uint32_t>(tmp >> 32);
 | 
						|
    }
 | 
						|
    // adjust the bits and the exponent to account for removing
 | 
						|
    // the leading bit.
 | 
						|
    bits = bits & uint64_t{0x7FFFFFFFFFFFFFFF};
 | 
						|
    exp++;
 | 
						|
  }
 | 
						|
  if (IncludeZero) {
 | 
						|
    if (bits == 0u) return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  // Number of leading zeros is mapped to the exponent: 2^-clz
 | 
						|
  // bits is 0..01xxxxxx. After shifting, we're left with 1xxx...0..0
 | 
						|
  int clz = base_internal::CountLeadingZeros64(bits);
 | 
						|
  bits <<= (IncludeZero ? clz : (clz & 63));  // remove 0-bits.
 | 
						|
  exp -= clz;                                 // set the exponent.
 | 
						|
  bits >>= (63 - kExp);
 | 
						|
 | 
						|
  // Construct the 32-bit or 64-bit IEEE 754 floating-point value from
 | 
						|
  // the individual fields: sign, exp, mantissa(bits).
 | 
						|
  uint_type val =
 | 
						|
      (std::is_same<SignedTag, GeneratePositiveTag>::value ? 0u : sign) |
 | 
						|
      (static_cast<uint_type>(exp) << kExp) |
 | 
						|
      (static_cast<uint_type>(bits) & kMask);
 | 
						|
 | 
						|
  // bit_cast to the output-type
 | 
						|
  real_type result;
 | 
						|
  memcpy(static_cast<void*>(&result), static_cast<const void*>(&val),
 | 
						|
         sizeof(result));
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace random_internal
 | 
						|
ABSL_NAMESPACE_END
 | 
						|
}  // namespace absl
 | 
						|
 | 
						|
#endif  // ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_
 |