generate_real.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // Copyright 2017 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_
  15. #define ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_
  16. // This file contains some implementation details which are used by one or more
  17. // of the absl random number distributions.
  18. #include <cstdint>
  19. #include <cstring>
  20. #include <limits>
  21. #include <type_traits>
  22. #include "absl/meta/type_traits.h"
  23. #include "absl/numeric/bits.h"
  24. #include "absl/random/internal/fastmath.h"
  25. #include "absl/random/internal/traits.h"
  26. namespace absl {
  27. ABSL_NAMESPACE_BEGIN
  28. namespace random_internal {
  29. // Tristate tag types controlling the output of GenerateRealFromBits.
  30. struct GeneratePositiveTag {};
  31. struct GenerateNegativeTag {};
  32. struct GenerateSignedTag {};
  33. // GenerateRealFromBits generates a single real value from a single 64-bit
  34. // `bits` with template fields controlling the output.
  35. //
  36. // The `SignedTag` parameter controls whether positive, negative,
  37. // or either signed/unsigned may be returned.
  38. // When SignedTag == GeneratePositiveTag, range is U(0, 1)
  39. // When SignedTag == GenerateNegativeTag, range is U(-1, 0)
  40. // When SignedTag == GenerateSignedTag, range is U(-1, 1)
  41. //
  42. // When the `IncludeZero` parameter is true, the function may return 0 for some
  43. // inputs, otherwise it never returns 0.
  44. //
  45. // When a value in U(0,1) is required, use:
  46. // GenerateRealFromBits<double, PositiveValueT, true>;
  47. //
  48. // When a value in U(-1,1) is required, use:
  49. // GenerateRealFromBits<double, SignedValueT, false>;
  50. //
  51. // This generates more distinct values than the mathematical equivalent
  52. // `U(0, 1) * 2.0 - 1.0`.
  53. //
  54. // Scaling the result by powers of 2 (and avoiding a multiply) is also possible:
  55. // GenerateRealFromBits<double>(..., -1); => U(0, 0.5)
  56. // GenerateRealFromBits<double>(..., 1); => U(0, 2)
  57. //
  58. template <typename RealType, // Real type, either float or double.
  59. typename SignedTag = GeneratePositiveTag, // Whether a positive,
  60. // negative, or signed
  61. // value is generated.
  62. bool IncludeZero = true>
  63. inline RealType GenerateRealFromBits(uint64_t bits, int exp_bias = 0) {
  64. using real_type = RealType;
  65. using uint_type = absl::conditional_t<std::is_same<real_type, float>::value,
  66. uint32_t, uint64_t>;
  67. static_assert(
  68. (std::is_same<double, real_type>::value ||
  69. std::is_same<float, real_type>::value),
  70. "GenerateRealFromBits must be parameterized by either float or double.");
  71. static_assert(sizeof(uint_type) == sizeof(real_type),
  72. "Mismatched unsigned and real types.");
  73. static_assert((std::numeric_limits<real_type>::is_iec559 &&
  74. std::numeric_limits<real_type>::radix == 2),
  75. "RealType representation is not IEEE 754 binary.");
  76. static_assert((std::is_same<SignedTag, GeneratePositiveTag>::value ||
  77. std::is_same<SignedTag, GenerateNegativeTag>::value ||
  78. std::is_same<SignedTag, GenerateSignedTag>::value),
  79. "");
  80. static constexpr int kExp = std::numeric_limits<real_type>::digits - 1;
  81. static constexpr uint_type kMask = (static_cast<uint_type>(1) << kExp) - 1u;
  82. static constexpr int kUintBits = sizeof(uint_type) * 8;
  83. int exp = exp_bias + int{std::numeric_limits<real_type>::max_exponent - 2};
  84. // Determine the sign bit.
  85. // Depending on the SignedTag, this may use the left-most bit
  86. // or it may be a constant value.
  87. uint_type sign = std::is_same<SignedTag, GenerateNegativeTag>::value
  88. ? (static_cast<uint_type>(1) << (kUintBits - 1))
  89. : 0;
  90. if (std::is_same<SignedTag, GenerateSignedTag>::value) {
  91. if (std::is_same<uint_type, uint64_t>::value) {
  92. sign = bits & uint64_t{0x8000000000000000};
  93. }
  94. if (std::is_same<uint_type, uint32_t>::value) {
  95. const uint64_t tmp = bits & uint64_t{0x8000000000000000};
  96. sign = static_cast<uint32_t>(tmp >> 32);
  97. }
  98. // adjust the bits and the exponent to account for removing
  99. // the leading bit.
  100. bits = bits & uint64_t{0x7FFFFFFFFFFFFFFF};
  101. exp++;
  102. }
  103. if (IncludeZero) {
  104. if (bits == 0u) return 0;
  105. }
  106. // Number of leading zeros is mapped to the exponent: 2^-clz
  107. // bits is 0..01xxxxxx. After shifting, we're left with 1xxx...0..0
  108. int clz = countl_zero(bits);
  109. bits <<= (IncludeZero ? clz : (clz & 63)); // remove 0-bits.
  110. exp -= clz; // set the exponent.
  111. bits >>= (63 - kExp);
  112. // Construct the 32-bit or 64-bit IEEE 754 floating-point value from
  113. // the individual fields: sign, exp, mantissa(bits).
  114. uint_type val = sign | (static_cast<uint_type>(exp) << kExp) |
  115. (static_cast<uint_type>(bits) & kMask);
  116. // bit_cast to the output-type
  117. real_type result;
  118. memcpy(static_cast<void*>(&result), static_cast<const void*>(&val),
  119. sizeof(result));
  120. return result;
  121. }
  122. } // namespace random_internal
  123. ABSL_NAMESPACE_END
  124. } // namespace absl
  125. #endif // ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_