| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #ifndef ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_ |
| #define ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_ |
|
|
| |
| |
|
|
| #include <cstdint> |
| #include <cstring> |
| #include <limits> |
| #include <type_traits> |
|
|
| #include "absl/meta/type_traits.h" |
| #include "absl/numeric/bits.h" |
| #include "absl/random/internal/fastmath.h" |
| #include "absl/random/internal/traits.h" |
|
|
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
| namespace random_internal { |
|
|
| |
| struct GeneratePositiveTag {}; |
| struct GenerateNegativeTag {}; |
| struct GenerateSignedTag {}; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename RealType, |
| typename SignedTag = GeneratePositiveTag, |
| |
| |
| 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 unsigned 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}; |
|
|
| |
| |
| |
| 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); |
| } |
| |
| |
| bits = bits & uint64_t{0x7FFFFFFFFFFFFFFF}; |
| exp++; |
| } |
| if (IncludeZero) { |
| if (bits == 0u) return 0; |
| } |
|
|
| |
| |
| int clz = countl_zero(bits); |
| bits <<= (IncludeZero ? clz : (clz & 63)); |
| exp -= clz; |
| bits >>= (63 - kExp); |
|
|
| |
| |
| uint_type val = sign | (static_cast<uint_type>(exp) << kExp) | |
| (static_cast<uint_type>(bits) & kMask); |
|
|
| |
| real_type result; |
| memcpy(static_cast<void*>(&result), static_cast<const void*>(&val), |
| sizeof(result)); |
| return result; |
| } |
|
|
| } |
| ABSL_NAMESPACE_END |
| } |
|
|
| #endif |
|
|