| // 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/config.h" | |
| #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 { | |
| // 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: | |
| // GenerateRealFromBits<double, PositiveValueT, true>; | |
| // | |
| // When a value in U(-1,1) is required, use: | |
| // GenerateRealFromBits<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 = | |
| std::conditional_t<std::is_same_v<real_type, float>, uint32_t, uint64_t>; | |
| static_assert( | |
| (std::is_same_v<double, real_type> || std::is_same_v<float, real_type>), | |
| "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_v<SignedTag, GeneratePositiveTag> || | |
| std::is_same_v<SignedTag, GenerateNegativeTag> || | |
| std::is_same_v<SignedTag, GenerateSignedTag>)); | |
| 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_v<SignedTag, GenerateNegativeTag> | |
| ? (static_cast<uint_type>(1) << (kUintBits - 1)) | |
| : 0; | |
| if (std::is_same_v<SignedTag, GenerateSignedTag>) { | |
| if (std::is_same_v<uint_type, uint64_t>) { | |
| sign = bits & uint64_t{0x8000000000000000}; | |
| } | |
| if (std::is_same_v<uint_type, uint32_t>) { | |
| 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 = countl_zero(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 = 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_ |