You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

generate_real.h 6.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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. {
  28. ABSL_NAMESPACE_BEGIN
  29. namespace random_internal
  30. {
  31. // Tristate tag types controlling the output of GenerateRealFromBits.
  32. struct GeneratePositiveTag
  33. {
  34. };
  35. struct GenerateNegativeTag
  36. {
  37. };
  38. struct GenerateSignedTag
  39. {
  40. };
  41. // GenerateRealFromBits generates a single real value from a single 64-bit
  42. // `bits` with template fields controlling the output.
  43. //
  44. // The `SignedTag` parameter controls whether positive, negative,
  45. // or either signed/unsigned may be returned.
  46. // When SignedTag == GeneratePositiveTag, range is U(0, 1)
  47. // When SignedTag == GenerateNegativeTag, range is U(-1, 0)
  48. // When SignedTag == GenerateSignedTag, range is U(-1, 1)
  49. //
  50. // When the `IncludeZero` parameter is true, the function may return 0 for some
  51. // inputs, otherwise it never returns 0.
  52. //
  53. // When a value in U(0,1) is required, use:
  54. // GenerateRealFromBits<double, PositiveValueT, true>;
  55. //
  56. // When a value in U(-1,1) is required, use:
  57. // GenerateRealFromBits<double, SignedValueT, false>;
  58. //
  59. // This generates more distinct values than the mathematical equivalent
  60. // `U(0, 1) * 2.0 - 1.0`.
  61. //
  62. // Scaling the result by powers of 2 (and avoiding a multiply) is also possible:
  63. // GenerateRealFromBits<double>(..., -1); => U(0, 0.5)
  64. // GenerateRealFromBits<double>(..., 1); => U(0, 2)
  65. //
  66. template<typename RealType, // Real type, either float or double.
  67. typename SignedTag = GeneratePositiveTag, // Whether a positive,
  68. // negative, or signed
  69. // value is generated.
  70. bool IncludeZero = true>
  71. inline RealType GenerateRealFromBits(uint64_t bits, int exp_bias = 0)
  72. {
  73. using real_type = RealType;
  74. using uint_type = absl::conditional_t<std::is_same<real_type, float>::value, uint32_t, uint64_t>;
  75. static_assert(
  76. (std::is_same<double, real_type>::value ||
  77. std::is_same<float, real_type>::value),
  78. "GenerateRealFromBits must be parameterized by either float or double."
  79. );
  80. static_assert(sizeof(uint_type) == sizeof(real_type), "Mismatched unsinged and real types.");
  81. static_assert((std::numeric_limits<real_type>::is_iec559 && std::numeric_limits<real_type>::radix == 2), "RealType representation is not IEEE 754 binary.");
  82. static_assert((std::is_same<SignedTag, GeneratePositiveTag>::value || std::is_same<SignedTag, GenerateNegativeTag>::value || std::is_same<SignedTag, GenerateSignedTag>::value), "");
  83. static constexpr int kExp = std::numeric_limits<real_type>::digits - 1;
  84. static constexpr uint_type kMask = (static_cast<uint_type>(1) << kExp) - 1u;
  85. static constexpr int kUintBits = sizeof(uint_type) * 8;
  86. int exp = exp_bias + int{std::numeric_limits<real_type>::max_exponent - 2};
  87. // Determine the sign bit.
  88. // Depending on the SignedTag, this may use the left-most bit
  89. // or it may be a constant value.
  90. uint_type sign = std::is_same<SignedTag, GenerateNegativeTag>::value ? (static_cast<uint_type>(1) << (kUintBits - 1)) : 0;
  91. if (std::is_same<SignedTag, GenerateSignedTag>::value)
  92. {
  93. if (std::is_same<uint_type, uint64_t>::value)
  94. {
  95. sign = bits & uint64_t{0x8000000000000000};
  96. }
  97. if (std::is_same<uint_type, uint32_t>::value)
  98. {
  99. const uint64_t tmp = bits & uint64_t{0x8000000000000000};
  100. sign = static_cast<uint32_t>(tmp >> 32);
  101. }
  102. // adjust the bits and the exponent to account for removing
  103. // the leading bit.
  104. bits = bits & uint64_t{0x7FFFFFFFFFFFFFFF};
  105. exp++;
  106. }
  107. if (IncludeZero)
  108. {
  109. if (bits == 0u)
  110. return 0;
  111. }
  112. // Number of leading zeros is mapped to the exponent: 2^-clz
  113. // bits is 0..01xxxxxx. After shifting, we're left with 1xxx...0..0
  114. int clz = countl_zero(bits);
  115. bits <<= (IncludeZero ? clz : (clz & 63)); // remove 0-bits.
  116. exp -= clz; // set the exponent.
  117. bits >>= (63 - kExp);
  118. // Construct the 32-bit or 64-bit IEEE 754 floating-point value from
  119. // the individual fields: sign, exp, mantissa(bits).
  120. uint_type val = sign | (static_cast<uint_type>(exp) << kExp) |
  121. (static_cast<uint_type>(bits) & kMask);
  122. // bit_cast to the output-type
  123. real_type result;
  124. memcpy(static_cast<void*>(&result), static_cast<const void*>(&val), sizeof(result));
  125. return result;
  126. }
  127. } // namespace random_internal
  128. ABSL_NAMESPACE_END
  129. } // namespace absl
  130. #endif // ABSL_RANDOM_INTERNAL_GENERATE_REAL_H_