Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-15 09:01:08

0001 // Copyright 2017 The Abseil Authors.
0002 //
0003 // Licensed under the Apache License, Version 2.0 (the "License");
0004 // you may not use this file except in compliance with the License.
0005 // You may obtain a copy of the License at
0006 //
0007 //      https://www.apache.org/licenses/LICENSE-2.0
0008 //
0009 // Unless required by applicable law or agreed to in writing, software
0010 // distributed under the License is distributed on an "AS IS" BASIS,
0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012 // See the License for the specific language governing permissions and
0013 // limitations under the License.
0014 
0015 #ifndef ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_
0016 #define ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_
0017 
0018 // This file contains some implementation details which are used by one or more
0019 // of the absl random number distributions.
0020 
0021 #include <cstdint>
0022 #include <cstring>
0023 #include <limits>
0024 #include <type_traits>
0025 
0026 #include "absl/meta/type_traits.h"
0027 #include "absl/numeric/bits.h"
0028 #include "absl/random/internal/fastmath.h"
0029 #include "absl/random/internal/traits.h"
0030 
0031 namespace absl {
0032 ABSL_NAMESPACE_BEGIN
0033 namespace random_internal {
0034 
0035 // Tristate tag types controlling the output of GenerateRealFromBits.
0036 struct GeneratePositiveTag {};
0037 struct GenerateNegativeTag {};
0038 struct GenerateSignedTag {};
0039 
0040 // GenerateRealFromBits generates a single real value from a single 64-bit
0041 // `bits` with template fields controlling the output.
0042 //
0043 // The `SignedTag` parameter controls whether positive, negative,
0044 // or either signed/unsigned may be returned.
0045 //   When SignedTag == GeneratePositiveTag, range is U(0, 1)
0046 //   When SignedTag == GenerateNegativeTag, range is U(-1, 0)
0047 //   When SignedTag == GenerateSignedTag, range is U(-1, 1)
0048 //
0049 // When the `IncludeZero` parameter is true, the function may return 0 for some
0050 // inputs, otherwise it never returns 0.
0051 //
0052 // When a value in U(0,1) is required, use:
0053 //   GenerateRealFromBits<double, PositiveValueT, true>;
0054 //
0055 // When a value in U(-1,1) is required, use:
0056 //   GenerateRealFromBits<double, SignedValueT, false>;
0057 //
0058 //   This generates more distinct values than the mathematical equivalent
0059 //   `U(0, 1) * 2.0 - 1.0`.
0060 //
0061 // Scaling the result by powers of 2 (and avoiding a multiply) is also possible:
0062 //   GenerateRealFromBits<double>(..., -1);  => U(0, 0.5)
0063 //   GenerateRealFromBits<double>(..., 1);   => U(0, 2)
0064 //
0065 template <typename RealType,  // Real type, either float or double.
0066           typename SignedTag = GeneratePositiveTag,  // Whether a positive,
0067                                                      // negative, or signed
0068                                                      // value is generated.
0069           bool IncludeZero = true>
0070 inline RealType GenerateRealFromBits(uint64_t bits, int exp_bias = 0) {
0071   using real_type = RealType;
0072   using uint_type = absl::conditional_t<std::is_same<real_type, float>::value,
0073                                         uint32_t, uint64_t>;
0074 
0075   static_assert(
0076       (std::is_same<double, real_type>::value ||
0077        std::is_same<float, real_type>::value),
0078       "GenerateRealFromBits must be parameterized by either float or double.");
0079 
0080   static_assert(sizeof(uint_type) == sizeof(real_type),
0081                 "Mismatched unsigned and real types.");
0082 
0083   static_assert((std::numeric_limits<real_type>::is_iec559 &&
0084                  std::numeric_limits<real_type>::radix == 2),
0085                 "RealType representation is not IEEE 754 binary.");
0086 
0087   static_assert((std::is_same<SignedTag, GeneratePositiveTag>::value ||
0088                  std::is_same<SignedTag, GenerateNegativeTag>::value ||
0089                  std::is_same<SignedTag, GenerateSignedTag>::value),
0090                 "");
0091 
0092   static constexpr int kExp = std::numeric_limits<real_type>::digits - 1;
0093   static constexpr uint_type kMask = (static_cast<uint_type>(1) << kExp) - 1u;
0094   static constexpr int kUintBits = sizeof(uint_type) * 8;
0095 
0096   int exp = exp_bias + int{std::numeric_limits<real_type>::max_exponent - 2};
0097 
0098   // Determine the sign bit.
0099   // Depending on the SignedTag, this may use the left-most bit
0100   // or it may be a constant value.
0101   uint_type sign = std::is_same<SignedTag, GenerateNegativeTag>::value
0102                        ? (static_cast<uint_type>(1) << (kUintBits - 1))
0103                        : 0;
0104   if (std::is_same<SignedTag, GenerateSignedTag>::value) {
0105     if (std::is_same<uint_type, uint64_t>::value) {
0106       sign = bits & uint64_t{0x8000000000000000};
0107     }
0108     if (std::is_same<uint_type, uint32_t>::value) {
0109       const uint64_t tmp = bits & uint64_t{0x8000000000000000};
0110       sign = static_cast<uint32_t>(tmp >> 32);
0111     }
0112     // adjust the bits and the exponent to account for removing
0113     // the leading bit.
0114     bits = bits & uint64_t{0x7FFFFFFFFFFFFFFF};
0115     exp++;
0116   }
0117   if (IncludeZero) {
0118     if (bits == 0u) return 0;
0119   }
0120 
0121   // Number of leading zeros is mapped to the exponent: 2^-clz
0122   // bits is 0..01xxxxxx. After shifting, we're left with 1xxx...0..0
0123   int clz = countl_zero(bits);
0124   bits <<= (IncludeZero ? clz : (clz & 63));  // remove 0-bits.
0125   exp -= clz;                                 // set the exponent.
0126   bits >>= (63 - kExp);
0127 
0128   // Construct the 32-bit or 64-bit IEEE 754 floating-point value from
0129   // the individual fields: sign, exp, mantissa(bits).
0130   uint_type val = sign | (static_cast<uint_type>(exp) << kExp) |
0131                   (static_cast<uint_type>(bits) & kMask);
0132 
0133   // bit_cast to the output-type
0134   real_type result;
0135   memcpy(static_cast<void*>(&result), static_cast<const void*>(&val),
0136          sizeof(result));
0137   return result;
0138 }
0139 
0140 }  // namespace random_internal
0141 ABSL_NAMESPACE_END
0142 }  // namespace absl
0143 
0144 #endif  // ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_