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