1 /* boost random/subtract_with_carry.hpp header file
3 * Copyright Jens Maurer 2002
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)
8 * See http://www.boost.org for most recent version including documentation.
16 #ifndef BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP
17 #define BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP
19 #include <boost/config/no_tr1/cmath.hpp>
21 #include <algorithm> // std::equal
23 #include <boost/config/no_tr1/cmath.hpp> // std::pow
24 #include <boost/config.hpp>
25 #include <boost/limits.hpp>
26 #include <boost/cstdint.hpp>
27 #include <boost/static_assert.hpp>
28 #include <boost/detail/workaround.hpp>
29 #include <boost/random/detail/config.hpp>
30 #include <boost/random/linear_congruential.hpp>
36 #if BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC > 1300
37 # define BOOST_RANDOM_EXTRACT_SWC_01
40 #if defined(__APPLE_CC__) && defined(__GNUC__) && (__GNUC__ == 3) && (__GNUC_MINOR__ <= 3)
41 # define BOOST_RANDOM_EXTRACT_SWC_01
44 # ifdef BOOST_RANDOM_EXTRACT_SWC_01
47 template <class IStream
, class SubtractWithCarry
, class RealType
>
48 void extract_subtract_with_carry_01(
50 , SubtractWithCarry
& f
56 for(unsigned int j
= 0; j
< f
.long_lag
; ++j
) {
57 is
>> value
>> std::ws
;
58 x
[j
] = value
/ modulus
;
60 is
>> value
>> std::ws
;
61 carry
= value
/ modulus
;
65 // subtract-with-carry generator
66 // Marsaglia and Zaman
68 template<class IntType
, IntType m
, unsigned int s
, unsigned int r
,
70 class subtract_with_carry
73 typedef IntType result_type
;
74 BOOST_STATIC_CONSTANT(bool, has_fixed_range
= true);
75 BOOST_STATIC_CONSTANT(result_type
, min_value
= 0);
76 BOOST_STATIC_CONSTANT(result_type
, max_value
= m
-1);
77 BOOST_STATIC_CONSTANT(result_type
, modulus
= m
);
78 BOOST_STATIC_CONSTANT(unsigned int, long_lag
= r
);
79 BOOST_STATIC_CONSTANT(unsigned int, short_lag
= s
);
81 subtract_with_carry() {
82 // MSVC fails BOOST_STATIC_ASSERT with std::numeric_limits at class scope
83 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
84 BOOST_STATIC_ASSERT(std::numeric_limits
<result_type
>::is_signed
);
85 BOOST_STATIC_ASSERT(std::numeric_limits
<result_type
>::is_integer
);
89 explicit subtract_with_carry(uint32_t value
) { seed(value
); }
90 template<class Generator
>
91 explicit subtract_with_carry(Generator
& gen
) { seed(gen
); }
92 template<class It
> subtract_with_carry(It
& first
, It last
) { seed(first
,last
); }
94 // compiler-generated copy ctor and assignment operator are fine
96 void seed(uint32_t value
= 19780503u)
98 random::linear_congruential
<int32_t, 40014, 0, 2147483563, 0> intgen(value
);
102 // For GCC, moving this function out-of-line prevents inlining, which may
103 // reduce overall object code size. However, MSVC does not grok
104 // out-of-line template member functions.
105 template<class Generator
>
106 void seed(Generator
& gen
)
108 // I could have used std::generate_n, but it takes "gen" by value
109 for(unsigned int j
= 0; j
< long_lag
; ++j
)
110 x
[j
] = gen() % modulus
;
111 carry
= (x
[long_lag
-1] == 0);
116 void seed(It
& first
, It last
)
119 for(j
= 0; j
< long_lag
&& first
!= last
; ++j
, ++first
)
120 x
[j
] = *first
% modulus
;
121 if(first
== last
&& j
< long_lag
)
122 throw std::invalid_argument("subtract_with_carry::seed");
123 carry
= (x
[long_lag
-1] == 0);
127 result_type min
BOOST_PREVENT_MACRO_SUBSTITUTION () const { return min_value
; }
128 result_type max
BOOST_PREVENT_MACRO_SUBSTITUTION () const { return max_value
; }
130 result_type
operator()()
132 int short_index
= k
- short_lag
;
134 short_index
+= long_lag
;
136 if (x
[short_index
] >= x
[k
] + carry
) {
138 delta
= x
[short_index
] - (x
[k
] + carry
);
142 delta
= modulus
- x
[k
] - carry
+ x
[short_index
];
153 static bool validation(result_type x
) { return x
== val
; }
155 #ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
157 #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
158 template<class CharT
, class Traits
>
159 friend std::basic_ostream
<CharT
,Traits
>&
160 operator<<(std::basic_ostream
<CharT
,Traits
>& os
,
161 const subtract_with_carry
& f
)
163 for(unsigned int j
= 0; j
< f
.long_lag
; ++j
)
164 os
<< f
.compute(j
) << " ";
165 os
<< f
.carry
<< " ";
169 template<class CharT
, class Traits
>
170 friend std::basic_istream
<CharT
,Traits
>&
171 operator>>(std::basic_istream
<CharT
,Traits
>& is
, subtract_with_carry
& f
)
173 for(unsigned int j
= 0; j
< f
.long_lag
; ++j
)
174 is
>> f
.x
[j
] >> std::ws
;
175 is
>> f
.carry
>> std::ws
;
181 friend bool operator==(const subtract_with_carry
& x
, const subtract_with_carry
& y
)
183 for(unsigned int j
= 0; j
< r
; ++j
)
184 if(x
.compute(j
) != y
.compute(j
))
189 friend bool operator!=(const subtract_with_carry
& x
, const subtract_with_carry
& y
)
190 { return !(x
== y
); }
192 // Use a member function; Streamable concept not supported.
193 bool operator==(const subtract_with_carry
& rhs
) const
195 for(unsigned int j
= 0; j
< r
; ++j
)
196 if(compute(j
) != rhs
.compute(j
))
201 bool operator!=(const subtract_with_carry
& rhs
) const
202 { return !(*this == rhs
); }
206 // returns x(i-r+index), where index is in 0..r-1
207 IntType
compute(unsigned int index
) const
209 return x
[(k
+index
) % long_lag
];
212 // state representation; next output (state) is x(i)
213 // x[0] ... x[k] x[k+1] ... x[long_lag-1] represents
214 // x(i-k) ... x(i) x(i+1) ... x(i-k+long_lag-1)
215 // speed: base: 20-25 nsec
216 // ranlux_4: 230 nsec, ranlux_7: 430 nsec, ranlux_14: 810 nsec
217 // This state representation makes operator== and save/restore more
218 // difficult, because we've already computed "too much" and thus
219 // have to undo some steps to get at x(i-r) etc.
221 // state representation: next output (state) is x(i)
222 // x[0] ... x[k] x[k+1] ... x[long_lag-1] represents
223 // x(i-k) ... x(i) x(i-long_lag+1) ... x(i-k-1)
224 // speed: base 28 nsec
225 // ranlux_4: 370 nsec, ranlux_7: 688 nsec, ranlux_14: 1343 nsec
231 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
232 // A definition is required even for integral static constants
233 template<class IntType
, IntType m
, unsigned int s
, unsigned int r
, IntType val
>
234 const bool subtract_with_carry
<IntType
, m
, s
, r
, val
>::has_fixed_range
;
235 template<class IntType
, IntType m
, unsigned int s
, unsigned int r
, IntType val
>
236 const IntType subtract_with_carry
<IntType
, m
, s
, r
, val
>::min_value
;
237 template<class IntType
, IntType m
, unsigned int s
, unsigned int r
, IntType val
>
238 const IntType subtract_with_carry
<IntType
, m
, s
, r
, val
>::max_value
;
239 template<class IntType
, IntType m
, unsigned int s
, unsigned int r
, IntType val
>
240 const IntType subtract_with_carry
<IntType
, m
, s
, r
, val
>::modulus
;
241 template<class IntType
, IntType m
, unsigned int s
, unsigned int r
, IntType val
>
242 const unsigned int subtract_with_carry
<IntType
, m
, s
, r
, val
>::long_lag
;
243 template<class IntType
, IntType m
, unsigned int s
, unsigned int r
, IntType val
>
244 const unsigned int subtract_with_carry
<IntType
, m
, s
, r
, val
>::short_lag
;
248 // use a floating-point representation to produce values in [0..1)
249 template<class RealType
, int w
, unsigned int s
, unsigned int r
, int val
=0>
250 class subtract_with_carry_01
253 typedef RealType result_type
;
254 BOOST_STATIC_CONSTANT(bool, has_fixed_range
= false);
255 BOOST_STATIC_CONSTANT(int, word_size
= w
);
256 BOOST_STATIC_CONSTANT(unsigned int, long_lag
= r
);
257 BOOST_STATIC_CONSTANT(unsigned int, short_lag
= s
);
259 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
260 BOOST_STATIC_ASSERT(!std::numeric_limits
<result_type
>::is_integer
);
263 subtract_with_carry_01() { init_modulus(); seed(); }
264 explicit subtract_with_carry_01(uint32_t value
)
265 { init_modulus(); seed(value
); }
266 template<class It
> subtract_with_carry_01(It
& first
, It last
)
267 { init_modulus(); seed(first
,last
); }
272 #ifndef BOOST_NO_STDC_NAMESPACE
273 // allow for Koenig lookup
276 _modulus
= pow(RealType(2), word_size
);
280 // compiler-generated copy ctor and assignment operator are fine
282 void seed(uint32_t value
= 19780503u)
284 #ifndef BOOST_NO_STDC_NAMESPACE
285 // allow for Koenig lookup
288 random::linear_congruential
<int32_t, 40014, 0, 2147483563, 0> gen(value
);
289 unsigned long array
[(w
+31)/32 * long_lag
];
290 for(unsigned int j
= 0; j
< sizeof(array
)/sizeof(unsigned long); ++j
)
292 unsigned long * start
= array
;
293 seed(start
, array
+ sizeof(array
)/sizeof(unsigned long));
297 void seed(It
& first
, It last
)
299 #ifndef BOOST_NO_STDC_NAMESPACE
300 // allow for Koenig lookup
304 unsigned long mask
= ~((~0u) << (w
%32)); // now lowest (w%32) bits set
305 RealType two32
= pow(RealType(2), 32);
307 for(j
= 0; j
< long_lag
&& first
!= last
; ++j
) {
309 for(int i
= 0; i
< w
/32 && first
!= last
; ++i
, ++first
)
310 x
[j
] += *first
/ pow(two32
,i
+1);
311 if(first
!= last
&& mask
!= 0) {
312 x
[j
] += fmod((*first
& mask
) / _modulus
, RealType(1));
316 if(first
== last
&& j
< long_lag
)
317 throw std::invalid_argument("subtract_with_carry_01::seed");
318 carry
= (x
[long_lag
-1] ? 0 : 1 / _modulus
);
322 result_type min
BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(0); }
323 result_type max
BOOST_PREVENT_MACRO_SUBSTITUTION () const { return result_type(1); }
325 result_type
operator()()
327 int short_index
= k
- short_lag
;
329 short_index
+= long_lag
;
330 RealType delta
= x
[short_index
] - x
[k
] - carry
;
332 delta
+= RealType(1);
333 carry
= RealType(1)/_modulus
;
344 static bool validation(result_type x
)
345 { return x
== val
/pow(RealType(2), word_size
); }
347 #ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
349 #ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
350 template<class CharT
, class Traits
>
351 friend std::basic_ostream
<CharT
,Traits
>&
352 operator<<(std::basic_ostream
<CharT
,Traits
>& os
,
353 const subtract_with_carry_01
& f
)
355 #ifndef BOOST_NO_STDC_NAMESPACE
356 // allow for Koenig lookup
359 std::ios_base::fmtflags oldflags
= os
.flags(os
.dec
| os
.fixed
| os
.left
);
360 for(unsigned int j
= 0; j
< f
.long_lag
; ++j
)
361 os
<< (f
.compute(j
) * f
._modulus
) << " ";
362 os
<< (f
.carry
* f
._modulus
);
367 template<class CharT
, class Traits
>
368 friend std::basic_istream
<CharT
,Traits
>&
369 operator>>(std::basic_istream
<CharT
,Traits
>& is
, subtract_with_carry_01
& f
)
371 # ifdef BOOST_RANDOM_EXTRACT_SWC_01
372 detail::extract_subtract_with_carry_01(is
, f
, f
.carry
, f
.x
, f
._modulus
);
374 // MSVC (up to 7.1) and Borland (up to 5.64) don't handle the template type
375 // parameter "RealType" available from the class template scope, so use
376 // the member typedef
377 typename
subtract_with_carry_01::result_type value
;
378 for(unsigned int j
= 0; j
< long_lag
; ++j
) {
379 is
>> value
>> std::ws
;
380 f
.x
[j
] = value
/ f
._modulus
;
382 is
>> value
>> std::ws
;
383 f
.carry
= value
/ f
._modulus
;
390 friend bool operator==(const subtract_with_carry_01
& x
,
391 const subtract_with_carry_01
& y
)
393 for(unsigned int j
= 0; j
< r
; ++j
)
394 if(x
.compute(j
) != y
.compute(j
))
399 friend bool operator!=(const subtract_with_carry_01
& x
,
400 const subtract_with_carry_01
& y
)
401 { return !(x
== y
); }
403 // Use a member function; Streamable concept not supported.
404 bool operator==(const subtract_with_carry_01
& rhs
) const
406 for(unsigned int j
= 0; j
< r
; ++j
)
407 if(compute(j
) != rhs
.compute(j
))
412 bool operator!=(const subtract_with_carry_01
& rhs
) const
413 { return !(*this == rhs
); }
417 RealType
compute(unsigned int index
) const;
420 RealType x
[long_lag
];
424 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
425 // A definition is required even for integral static constants
426 template<class RealType
, int w
, unsigned int s
, unsigned int r
, int val
>
427 const bool subtract_with_carry_01
<RealType
, w
, s
, r
, val
>::has_fixed_range
;
428 template<class RealType
, int w
, unsigned int s
, unsigned int r
, int val
>
429 const int subtract_with_carry_01
<RealType
, w
, s
, r
, val
>::word_size
;
430 template<class RealType
, int w
, unsigned int s
, unsigned int r
, int val
>
431 const unsigned int subtract_with_carry_01
<RealType
, w
, s
, r
, val
>::long_lag
;
432 template<class RealType
, int w
, unsigned int s
, unsigned int r
, int val
>
433 const unsigned int subtract_with_carry_01
<RealType
, w
, s
, r
, val
>::short_lag
;
436 template<class RealType
, int w
, unsigned int s
, unsigned int r
, int val
>
437 RealType subtract_with_carry_01
<RealType
, w
, s
, r
, val
>::compute(unsigned int index
) const
439 return x
[(k
+index
) % long_lag
];
443 } // namespace random
446 #endif // BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP