1 | /* boost random/uniform_01.hpp header file |
2 | * |
3 | * Copyright Jens Maurer 2000-2001 |
4 | * Distributed under the Boost Software License, Version 1.0. (See |
5 | * accompanying file LICENSE_1_0.txt or copy at |
6 | * http://www.boost.org/LICENSE_1_0.txt) |
7 | * |
8 | * See http://www.boost.org for most recent version including documentation. |
9 | * |
10 | * $Id$ |
11 | * |
12 | * Revision history |
13 | * 2001-02-18 moved to individual header files |
14 | */ |
15 | |
16 | #ifndef BOOST_RANDOM_UNIFORM_01_HPP |
17 | #define BOOST_RANDOM_UNIFORM_01_HPP |
18 | |
19 | #include <iostream> |
20 | #include <boost/config.hpp> |
21 | #include <boost/limits.hpp> |
22 | #include <boost/static_assert.hpp> |
23 | #include <boost/random/detail/config.hpp> |
24 | #include <boost/random/detail/ptr_helper.hpp> |
25 | |
26 | #include <boost/random/detail/disable_warnings.hpp> |
27 | |
28 | namespace boost { |
29 | namespace random { |
30 | |
31 | #ifdef BOOST_RANDOM_DOXYGEN |
32 | |
33 | /** |
34 | * The distribution function uniform_01 models a \random_distribution. |
35 | * On each invocation, it returns a random floating-point value |
36 | * uniformly distributed in the range [0..1). |
37 | * |
38 | * The template parameter RealType shall denote a float-like value type |
39 | * with support for binary operators +, -, and /. |
40 | * |
41 | * Note: The current implementation is buggy, because it may not fill |
42 | * all of the mantissa with random bits. I'm unsure how to fill a |
43 | * (to-be-invented) @c boost::bigfloat class with random bits efficiently. |
44 | * It's probably time for a traits class. |
45 | */ |
46 | template<class RealType = double> |
47 | class uniform_01 |
48 | { |
49 | public: |
50 | typedef RealType input_type; |
51 | typedef RealType result_type; |
52 | result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const; |
53 | result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const; |
54 | void reset(); |
55 | |
56 | template<class Engine> |
57 | result_type operator()(Engine& eng); |
58 | |
59 | #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS |
60 | template<class CharT, class Traits> |
61 | friend std::basic_ostream<CharT,Traits>& |
62 | operator<<(std::basic_ostream<CharT,Traits>& os, const new_uniform_01&) |
63 | { |
64 | return os; |
65 | } |
66 | |
67 | template<class CharT, class Traits> |
68 | friend std::basic_istream<CharT,Traits>& |
69 | operator>>(std::basic_istream<CharT,Traits>& is, new_uniform_01&) |
70 | { |
71 | return is; |
72 | } |
73 | #endif |
74 | }; |
75 | |
76 | #else |
77 | |
78 | namespace detail { |
79 | |
80 | template<class RealType> |
81 | class new_uniform_01 |
82 | { |
83 | public: |
84 | typedef RealType input_type; |
85 | typedef RealType result_type; |
86 | // compiler-generated copy ctor and copy assignment are fine |
87 | result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(0); } |
88 | result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(1); } |
89 | void reset() { } |
90 | |
91 | template<class Engine> |
92 | result_type operator()(Engine& eng) { |
93 | for (;;) { |
94 | typedef typename Engine::result_type base_result; |
95 | result_type factor = result_type(1) / |
96 | (result_type(base_result((eng.max)()-(eng.min)())) + |
97 | result_type(std::numeric_limits<base_result>::is_integer ? 1 : 0)); |
98 | result_type result = result_type(base_result(eng() - (eng.min)())) * factor; |
99 | if (result < result_type(1)) |
100 | return result; |
101 | } |
102 | } |
103 | |
104 | #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS |
105 | template<class CharT, class Traits> |
106 | friend std::basic_ostream<CharT,Traits>& |
107 | operator<<(std::basic_ostream<CharT,Traits>& os, const new_uniform_01&) |
108 | { |
109 | return os; |
110 | } |
111 | |
112 | template<class CharT, class Traits> |
113 | friend std::basic_istream<CharT,Traits>& |
114 | operator>>(std::basic_istream<CharT,Traits>& is, new_uniform_01&) |
115 | { |
116 | return is; |
117 | } |
118 | #endif |
119 | }; |
120 | |
121 | template<class UniformRandomNumberGenerator, class RealType> |
122 | class backward_compatible_uniform_01 |
123 | { |
124 | typedef boost::random::detail::ptr_helper<UniformRandomNumberGenerator> traits; |
125 | public: |
126 | typedef UniformRandomNumberGenerator base_type; |
127 | typedef RealType result_type; |
128 | |
129 | BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); |
130 | |
131 | #if !defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) |
132 | BOOST_STATIC_ASSERT(!std::numeric_limits<RealType>::is_integer); |
133 | #endif |
134 | |
135 | explicit backward_compatible_uniform_01(typename traits::rvalue_type rng) |
136 | : _rng(rng), |
137 | _factor(result_type(1) / |
138 | (result_type((base().max)()-(base().min)()) + |
139 | result_type(std::numeric_limits<base_result>::is_integer ? 1 : 0))) |
140 | { |
141 | } |
142 | // compiler-generated copy ctor and copy assignment are fine |
143 | |
144 | result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(0); } |
145 | result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(1); } |
146 | typename traits::value_type& base() { return traits::ref(_rng); } |
147 | const typename traits::value_type& base() const { return traits::ref(_rng); } |
148 | void reset() { } |
149 | |
150 | result_type operator()() { |
151 | for (;;) { |
152 | result_type result = result_type(base()() - (base().min)()) * _factor; |
153 | if (result < result_type(1)) |
154 | return result; |
155 | } |
156 | } |
157 | |
158 | #if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) |
159 | template<class CharT, class Traits> |
160 | friend std::basic_ostream<CharT,Traits>& |
161 | operator<<(std::basic_ostream<CharT,Traits>& os, const backward_compatible_uniform_01& u) |
162 | { |
163 | os << u._rng; |
164 | return os; |
165 | } |
166 | |
167 | template<class CharT, class Traits> |
168 | friend std::basic_istream<CharT,Traits>& |
169 | operator>>(std::basic_istream<CharT,Traits>& is, backward_compatible_uniform_01& u) |
170 | { |
171 | is >> u._rng; |
172 | return is; |
173 | } |
174 | #endif |
175 | |
176 | private: |
177 | typedef typename traits::value_type::result_type base_result; |
178 | UniformRandomNumberGenerator _rng; |
179 | result_type _factor; |
180 | }; |
181 | |
182 | #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION |
183 | // A definition is required even for integral static constants |
184 | template<class UniformRandomNumberGenerator, class RealType> |
185 | const bool backward_compatible_uniform_01<UniformRandomNumberGenerator, RealType>::has_fixed_range; |
186 | #endif |
187 | |
188 | template<class UniformRandomNumberGenerator, bool is_number = std::numeric_limits<UniformRandomNumberGenerator>::is_specialized> |
189 | struct select_uniform_01 |
190 | { |
191 | template<class RealType> |
192 | struct apply |
193 | { |
194 | typedef backward_compatible_uniform_01<UniformRandomNumberGenerator, RealType> type; |
195 | }; |
196 | }; |
197 | |
198 | template<class Num> |
199 | struct select_uniform_01<Num, true> |
200 | { |
201 | template<class RealType> |
202 | struct apply |
203 | { |
204 | typedef new_uniform_01<Num> type; |
205 | }; |
206 | }; |
207 | |
208 | } |
209 | |
210 | // Because it is so commonly used: uniform distribution on the real [0..1) |
211 | // range. This allows for specializations to avoid a costly int -> float |
212 | // conversion plus float multiplication |
213 | template<class UniformRandomNumberGenerator = double, class RealType = double> |
214 | class uniform_01 |
215 | : public detail::select_uniform_01<UniformRandomNumberGenerator>::BOOST_NESTED_TEMPLATE apply<RealType>::type |
216 | { |
217 | typedef typename detail::select_uniform_01<UniformRandomNumberGenerator>::BOOST_NESTED_TEMPLATE apply<RealType>::type impl_type; |
218 | typedef boost::random::detail::ptr_helper<UniformRandomNumberGenerator> traits; |
219 | public: |
220 | |
221 | uniform_01() {} |
222 | |
223 | explicit uniform_01(typename traits::rvalue_type rng) |
224 | : impl_type(rng) |
225 | { |
226 | } |
227 | |
228 | #if !defined(BOOST_NO_OPERATORS_IN_NAMESPACE) && !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) |
229 | template<class CharT, class Traits> |
230 | friend std::basic_ostream<CharT,Traits>& |
231 | operator<<(std::basic_ostream<CharT,Traits>& os, const uniform_01& u) |
232 | { |
233 | os << static_cast<const impl_type&>(u); |
234 | return os; |
235 | } |
236 | |
237 | template<class CharT, class Traits> |
238 | friend std::basic_istream<CharT,Traits>& |
239 | operator>>(std::basic_istream<CharT,Traits>& is, uniform_01& u) |
240 | { |
241 | is >> static_cast<impl_type&>(u); |
242 | return is; |
243 | } |
244 | #endif |
245 | }; |
246 | |
247 | #endif |
248 | |
249 | } // namespace random |
250 | |
251 | using random::uniform_01; |
252 | |
253 | } // namespace boost |
254 | |
255 | #include <boost/random/detail/enable_warnings.hpp> |
256 | |
257 | #endif // BOOST_RANDOM_UNIFORM_01_HPP |
258 | |