Scopira  20080306
distrandom.h
1 
2 /*
3  * Copyright (c) 2002 National Research Council
4  *
5  * All rights reserved.
6  *
7  * This material is confidential and proprietary information of
8  * National Research Council Canada ("Confidential Information").
9  * This Confidential Information may only be used and reproduced
10  * in accordance with the terms of the license agreement.
11  *
12  */
13 
14 #ifndef __INCLUDED__SCOPIRA_TOOL_DISTRANDOM_H__
15 #define __INCLUDED__SCOPIRA_TOOL_DISTRANDOM_H__
16 
17 #include <scopira/tool/limits.h>
18 #include <scopira/tool/linconrandom.h>
19 
20 namespace scopira
21 {
22  namespace tool
23  {
24  template <class UniRanGen, class RealType = double>
25  class uni01_dist;
26  template <class UniRanGen, class RealType = double>
27  class unireal_dist;
28  template <class UniRanGen, class IntType = int>
30  template<class UniRanGen, class IntType = int>
31  class uniint_dist;
32 
33  // "typical" distrbutions
36  typedef unismallint_dist<lincon_core> lincon_smallint; // how small is small? who knows
38 
41  typedef unismallint_dist<scopira::tool::rand48> rand48_smallint; // how small is small? who knows
43  }
44 }
45 
46 // various random distributions
47 
56 template <class UniRanGen, class RealType>
58 {
59  public:
60  typedef UniRanGen base_type;
61  typedef RealType result_type;
62  static const bool has_fixed_range = true;
63 
65  explicit uni01_dist(base_type &rng) : m_rng(rng) { }
66 
68  result_type min() const { return 0.0; }
70  result_type max() const { return 1.0; }
71 
72  result_type operator()(void) {
73  return static_cast<result_type>(m_rng() - m_rng.min()) /
74  (static_cast<result_type>(m_rng.max()-m_rng.min()) +
75  (std::numeric_limits<base_result>::is_integer ? 1.0 : 0.0));
76  }
77 
78  private:
79  typedef typename base_type::result_type base_result;
80  base_type & m_rng;
81 };
82 
88 template <class UniRanGen, class RealType>
90 {
91  public:
92  typedef UniRanGen base_type;
93  typedef RealType result_type;
94  static const bool has_fixed_range = false;
95 
97  unireal_dist(base_type &rng, RealType min, RealType max)
98  : m_rng(rng), m_min(min), m_max(max) { }
99 
101  result_type min(void) const { return m_min; }
103  result_type max(void) const { return m_max; }
104 
105  result_type operator()() { return m_rng() * (m_max - m_min) + m_min; }
106 
107  private:
109  RealType m_min, m_max;
110 };
111 
117 template <class UniRanGen, class IntType>
119 {
120  public:
121  typedef UniRanGen base_type;
122  typedef IntType result_type;
123  static const bool has_fixed_range = false;
124 
125  public:
127  unismallint_dist(base_type &rng, IntType min, IntType max);
128 
130  result_type min(void) const { return m_min; }
132  result_type max(void) const { return m_max; }
133 
135  result_type operator()(void) {
136  // we must not use the low bits here, because LCGs get very bad then
137  return long((m_rng() - m_rng.min()) / m_factor) % long(m_range) + m_min; // MDA casts used to prevent bad types
138  }
139 
140  private:
141  typedef typename base_type::result_type base_result;
142  base_type & m_rng;
143  IntType m_min, m_max;
144  base_result m_range;
145  int m_factor;
146 };
147 
149 template <class UniRanGen, class IntType>
151  (base_type & rng, IntType min, IntType max)
152  : m_rng(rng), m_min(min), m_max(max),
153  m_range(static_cast<base_result>(m_max-m_min)+1), m_factor(1)
154 {
155  //assert(min < max);
156 
157  // LCGs get bad when only taking the low bits.
158  // (probably put this logic into a partial template specialization)
159  // Check how many low bits we can ignore before we get too much
160  // quantization error.
161  base_result r_base = m_rng.max() - m_rng.min();
162  if (r_base == std::numeric_limits<base_result>::max()) {
163  m_factor = 2;
164  r_base /= 2;
165  }
166  r_base += 1;
167  if(long(r_base) % long(m_range) == 0) { // MDA invalid double operators to %, added casts
168  // No quantization effects, good
169  m_factor = int(double(r_base) / double(m_range));
170  } else {
171  //const base_result r = 32 * m_range * m_range;
172  //for(; r_base >= r; m_factor *= 2)
173  //r_base /= 2;
174  // carefully avoid overflow; pessimizing heree
175  for ( ; r_base/m_range/32 >= m_range; m_factor *= 2)
176  r_base /= 2;
177  }
178 }
179 
180 template<class UniRanGen, class IntType>
182 {
183  public:
184  typedef UniRanGen base_type;
185  typedef IntType input_type;
186  typedef IntType result_type;
187  static const bool has_fixed_range = false;
188 
189  explicit uniint_dist(UniRanGen &rng, IntType min, IntType max)
190  : m_rng(rng), m_min(min), m_max(max) { m_range = m_max - m_min; }
191 
193  result_type min(void) const { return m_min; }
195  result_type max(void) const { return m_max; }
196 
198  result_type operator()(void);
199 
200  private:
201  typedef typename base_type::result_type base_result;
202  base_type & m_rng;
203  IntType m_min, m_max, m_range;
204 };
205 
206 template<class UniRanGen, class IntType>
208 {
209  base_result bmin = (m_rng.min)();
210  base_result brange = (m_rng.max)() - (m_rng.min)();
211 
212  if (m_range == 0) {
213  return m_min;
214  } else if (brange == m_range) {
215  // this will probably never happen in real life
216  // basically nothing to do; just take care we don't overflow / underflow
217  return static_cast<result_type>(m_rng() - bmin) + m_min;
218  } else if (brange < m_range) {
219  // use rejection method to handle things like 0..3 --> 0..4
220  for(;;) {
221  // concatenate several invocations of the base RNG
222  // take extra care to avoid overflows
223  result_type limit;
224  if(m_range == (std::numeric_limits<result_type>::max)()) {
225  limit = m_range/(result_type(brange)+1);
226  if(m_range % result_type(brange)+1 == result_type(brange))
227  ++limit;
228  } else {
229  limit = (m_range+1)/(result_type(brange)+1);
230  }
231  // We consider "result" as expressed to base (brange+1):
232  // For every power of (brange+1), we determine a random factor
233  result_type result = result_type(0);
234  result_type mult = result_type(1);
235  while(mult <= limit) {
236  result += (m_rng() - bmin) * mult;
237  mult *= result_type(brange)+result_type(1);
238  }
239  if(mult == limit)
240  // m_range+1 is an integer power of brange+1: no rejections required
241  return result;
242  // m_range/mult < brange+1 -> no endless loop
243  result += uniint_dist<UniRanGen, result_type>(m_rng, 0, m_range/mult)() * mult;
244  if(result <= m_range)
245  return result + m_min;
246  }
247  } else { // brange > range
248  if (brange / m_range > 4 /* quantization_cutoff */ ) {
249  // the new range is vastly smaller than the source range,
250  // so quantization effects are not relevant
251  return unismallint_dist<UniRanGen, result_type>(m_rng, m_min, m_max)();
252  } else {
253  // use rejection method to handle cases like 0..5 -> 0..4
254  for(;;) {
255  base_result result = m_rng() - bmin;
256  // result and range are non-negative, and result is possibly larger
257  // than range, so the cast is safe
258  if(result <= static_cast<base_result>(m_range))
259  return result + m_min;
260  }
261  }
262  }
263 }
264 
265 #endif
266 
result_type min() const
min
Definition: distrandom.h:68
unismallint_dist(base_type &rng, IntType min, IntType max)
ctor
Definition: distrandom.h:151
Definition: archiveflow.h:20
result_type min(void) const
min
Definition: distrandom.h:130
Definition: distrandom.h:31
result_type operator()(void)
get next
Definition: distrandom.h:135
result_type max(void) const
max
Definition: distrandom.h:195
Definition: distrandom.h:25
result_type max(void) const
max
Definition: distrandom.h:132
uni01_dist(base_type &rng)
ctor
Definition: distrandom.h:65
result_type operator()(void)
get next
Definition: distrandom.h:207
Definition: distrandom.h:29
Definition: distrandom.h:27
result_type max(void) const
max
Definition: distrandom.h:103
unireal_dist(base_type &rng, RealType min, RealType max)
ctor
Definition: distrandom.h:97
result_type min(void) const
min
Definition: distrandom.h:193
result_type min(void) const
min
Definition: distrandom.h:101
result_type max() const
max
Definition: distrandom.h:70