20
20
#ifndef TILEDARRAY_RANDOM_H__INCLUDED
21
21
#define TILEDARRAY_RANDOM_H__INCLUDED
22
22
23
- #include < complex> // for std::complex
24
- #include < cstdlib> // for std::rand
25
- #include < type_traits> // for true_type, false_type, and enable_if
23
+ #include < complex> // for std::complex
24
+ #include < cstdlib> // for std::rand
25
+ #include < type_traits> // for true_type, false_type, and enable_if
26
26
27
27
namespace TiledArray ::detail {
28
28
@@ -37,28 +37,28 @@ namespace TiledArray::detail {
37
37
// / types. Specific types can be enabled by specializing CanMakeRandom.
38
38
// /
39
39
// / \tparam ValueType The type of random value we are attempting to generate.
40
- template <typename ValueType>
41
- struct CanMakeRandom : std::false_type{};
40
+ template <typename ValueType>
41
+ struct CanMakeRandom : std::false_type {};
42
42
43
43
// / Enables generating random int values
44
- template <>
45
- struct CanMakeRandom <int > : std::true_type{};
44
+ template <>
45
+ struct CanMakeRandom <int > : std::true_type {};
46
46
47
47
// / Enables generating random float values
48
- template <>
49
- struct CanMakeRandom <float > : std::true_type{};
48
+ template <>
49
+ struct CanMakeRandom <float > : std::true_type {};
50
50
51
51
// / Enables generating random double values
52
- template <>
53
- struct CanMakeRandom <double > : std::true_type{};
52
+ template <>
53
+ struct CanMakeRandom <double > : std::true_type {};
54
54
55
55
// / Enables generating random std::complex<float> values
56
- template <>
57
- struct CanMakeRandom <std::complex<float >> : std::true_type{};
56
+ template <>
57
+ struct CanMakeRandom <std::complex<float >> : std::true_type {};
58
58
59
59
// / Enables generating random std::complex<double> values
60
- template <>
61
- struct CanMakeRandom <std::complex<double >> : std::true_type{};
60
+ template <>
61
+ struct CanMakeRandom <std::complex<double >> : std::true_type {};
62
62
63
63
// / Variable for whether or not we can make a random value of type ValueType
64
64
// /
@@ -67,13 +67,13 @@ struct CanMakeRandom<std::complex<double>> : std::true_type{};
67
67
// / example `can_make_random_v<T>` is shorthand for `CanMakeRandom<T>::value`.
68
68
// /
69
69
// / \tparam ValueType the type of random value we are attempting to make.
70
- template <typename ValueType>
70
+ template <typename ValueType>
71
71
static constexpr auto can_make_random_v = CanMakeRandom<ValueType>::value;
72
72
73
73
// / Enables a function only when we can generate a random value of type `T`
74
74
// /
75
75
// / \tparam T The type of random value we are attempting to generate.
76
- template <typename T>
76
+ template <typename T>
77
77
using enable_if_can_make_random_t = std::enable_if_t <can_make_random_v<T>>;
78
78
79
79
// ------------------------------------------------------------------------------
@@ -83,16 +83,36 @@ using enable_if_can_make_random_t = std::enable_if_t<can_make_random_v<T>>;
83
83
// / Struct wrapping the process of generating a random value of type `ValueType`
84
84
// /
85
85
// / MakeRandom contains a single static member function `generate_value`, which
86
- // / can be called to generate a random value of type `ValueType` between 0
87
- // / and 1. Users can specialize the MakeRandom class to control how random
86
+ // / generates a random value using `std::rand()`. The default implementation is
87
+ // / only provided for fundamental types:
88
+ // / - for a floating-point type this returns a random value in [-1,1].
89
+ // / - for a signed integral type this returns a random value in [-4,4].
90
+ // / - for an unsigned integral type this returns a random value in [0,8].
91
+ // / Users can specialize the MakeRandom class to control how random
88
92
// / values of other types are formed.
89
93
// /
90
94
// / \tparam ValueType The type of random value to generate
91
- template <typename ValueType>
95
+ template <typename ValueType>
92
96
struct MakeRandom {
93
97
// / Generates a random value of type ValueType
94
98
static ValueType generate_value () {
95
- return static_cast <ValueType>(static_cast <double >(std::rand ()) / RAND_MAX);
99
+ static_assert (std::is_floating_point_v<ValueType> ||
100
+ std::is_integral_v<ValueType>);
101
+ if constexpr (std::is_floating_point_v<ValueType>)
102
+ return (2 * static_cast <ValueType>(std::rand ()) / RAND_MAX) - 1 ;
103
+ else if constexpr (std::is_integral_v<ValueType>) {
104
+ static_assert (RAND_MAX == 2147483647 );
105
+ static_assert (RAND_MAX % 2 == 1 );
106
+ constexpr std::int64_t RAND_MAX_DIVBY_9 =
107
+ (static_cast <std::int64_t >(RAND_MAX) + 8 ) / 9 ;
108
+ const ValueType v = static_cast <ValueType>(
109
+ static_cast <std::int64_t >(std::rand ()) / RAND_MAX_DIVBY_9);
110
+ if constexpr (std::is_signed_v<ValueType>) {
111
+ return v - 4 ;
112
+ } else {
113
+ return v;
114
+ }
115
+ }
96
116
}
97
117
};
98
118
@@ -105,18 +125,20 @@ struct MakeRandom {
105
125
// /
106
126
// / \tparam ScalarType The type used to hold the real and imaginary components
107
127
// / of the complex value.
108
- template <typename ScalarType>
128
+ template <typename ScalarType>
109
129
struct MakeRandom <std::complex<ScalarType>> {
110
-
111
130
// / Generates a random complex number.
112
131
static auto generate_value () {
132
+ static_assert (
133
+ std::is_floating_point_v<ScalarType>); // std::complex is only defined
134
+ // for fundamental
135
+ // floating-point types
113
136
const ScalarType real = MakeRandom<ScalarType>::generate_value ();
114
137
const ScalarType imag = MakeRandom<ScalarType>::generate_value ();
115
138
return std::complex<ScalarType>(real, imag);
116
139
}
117
140
};
118
141
119
- } // namespace TiledArray::detail
120
-
142
+ } // namespace TiledArray::detail
121
143
122
144
#endif
0 commit comments