1 //===-- runtime/random-templates.h ------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef FORTRAN_RUNTIME_RANDOM_TEMPLATES_H_
10 #define FORTRAN_RUNTIME_RANDOM_TEMPLATES_H_
13 #include "numeric-templates.h"
14 #include "flang/Common/optional.h"
15 #include "flang/Runtime/descriptor.h"
19 namespace Fortran::runtime::random
{
21 // Newer "Minimum standard", recommended by Park, Miller, and Stockmeyer in
22 // 1993. Same as C++17 std::minstd_rand, but explicitly instantiated for
25 std::linear_congruential_engine
<std::uint_fast32_t, 48271, 0, 2147483647>;
27 using GeneratedWord
= typename
Generator::result_type
;
28 static constexpr std::uint64_t range
{
29 static_cast<std::uint64_t>(Generator::max() - Generator::min() + 1)};
30 static constexpr bool rangeIsPowerOfTwo
{(range
& (range
- 1)) == 0};
31 static constexpr int rangeBits
{
32 64 - common::LeadingZeroBitCount(range
) - !rangeIsPowerOfTwo
};
35 extern Generator generator
;
36 extern Fortran::common::optional
<GeneratedWord
> nextValue
;
38 // Call only with lock held
39 static GeneratedWord
GetNextValue() {
41 if (nextValue
.has_value()) {
50 template <typename REAL
, int PREC
>
51 inline void Generate(const Descriptor
&harvest
) {
52 static constexpr std::size_t minBits
{
53 std::max
<std::size_t>(PREC
, 8 * sizeof(GeneratedWord
))};
54 using Int
= common::HostUnsignedIntType
<minBits
>;
55 static constexpr std::size_t words
{
56 static_cast<std::size_t>(PREC
+ rangeBits
- 1) / rangeBits
};
57 std::size_t elements
{harvest
.Elements()};
58 SubscriptValue at
[maxRank
];
59 harvest
.GetLowerBounds(at
);
61 CriticalSection critical
{lock
};
62 for (std::size_t j
{0}; j
< elements
; ++j
) {
64 Int fraction
{GetNextValue()};
65 if constexpr (words
> 1) {
66 for (std::size_t k
{1}; k
< words
; ++k
) {
67 static constexpr auto rangeMask
{
68 (GeneratedWord
{1} << rangeBits
) - 1};
69 GeneratedWord word
{(GetNextValue() - generator
.min()) & rangeMask
};
70 fraction
= (fraction
<< rangeBits
) | word
;
73 fraction
>>= words
* rangeBits
- PREC
;
75 LDEXPTy
<REAL
>::compute(static_cast<REAL
>(fraction
), -(PREC
+ 1))};
76 if (next
>= 0.0 && next
< 1.0) {
77 *harvest
.Element
<REAL
>(at
) = next
;
81 harvest
.IncrementSubscripts(at
);
86 } // namespace Fortran::runtime::random
88 #endif // FORTRAN_RUNTIME_RANDOM_TEMPLATES_H_