123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- // 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/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 = 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};
- // 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 = 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_
|