12 #if !defined(RANDOMLIB_DISCRETENORMAL_HPP)
13 #define RANDOMLIB_DISCRETENORMAL_HPP 1
158 IntType mu_num = 0, IntType mu_den = 1);
166 template<
class Random>
172 IntType _sig, _mu, _d, _isig, _imu;
173 typedef unsigned short word;
177 mutable std::vector<word> _v;
178 mutable unsigned _m, _l;
182 static const unsigned alloc_incr = 16;
185 static IntType iceil(IntType n, IntType d);
187 static IntType iabs(IntType n);
188 static IntType gcd(IntType u, IntType v);
192 word LeadingDigit(IntType& p)
const;
201 template<
class Random>
static int Choose(
Random& r,
int m);
204 template<
class Random>
bool less_than(
Random& r)
const;
207 template<
class Random>
bool less_than(
Random& r, word x, IntType p)
const;
210 template<
class Random>
bool bernoulli(
Random& r, word x, IntType p)
const;
215 template<
class Random>
bool ExpProbH(
Random& r)
const;
220 template<
class Random>
bool ExpProb(
Random& r,
int n)
const;
226 template<
class Random>
int ExpProbN(
Random& r)
const;
232 template<
class Random>
233 bool B(
Random& r,
int k, word x0, IntType xn)
const;
237 (IntType sigma_num, IntType sigma_den,
238 IntType mu_num, IntType mu_den)
239 : _v(std::vector<word>(alloc_incr)), _m(0), _l(alloc_incr) {
241 "DiscreteNormal: invalid integer type IntType");
243 "DiscreteNormal: IntType must be a signed type");
245 "DiscreteNormal: word must be an unsigned type");
247 std::numeric_limits<word>::digits,
248 "DiscreteNormal: IntType must be at least as wide as word");
249 if (!( sigma_num > 0 && sigma_den > 0 && mu_den > 0 ))
250 throw RandomErr(
"DiscreteNormal: need sigma > 0");
251 _imu = mu_num / mu_den;
252 if (_imu == (std::numeric_limits<IntType>::min)())
253 throw RandomErr(
"DiscreteNormal: abs(mu) too large");
254 mu_num -= _imu * mu_den;
256 l = gcd(sigma_num, sigma_den); sigma_num /= l; sigma_den /= l;
257 l = gcd(mu_num, mu_den); mu_num /= l; mu_den /= l;
258 _isig = iceil(sigma_num, sigma_den);
259 l = gcd(sigma_den, mu_den);
260 _sig = sigma_num * (mu_den / l);
261 _mu = mu_num * (sigma_den / l);
262 _d = sigma_den * (mu_den / l);
265 IntType maxint = (std::numeric_limits<IntType>::max)();
266 if (!( mu_den / l <= maxint / sigma_num &&
267 mu_num <= maxint / (sigma_den / l) &&
268 mu_den / l <= maxint / sigma_den ))
269 throw RandomErr(
"DiscreteNormal: sigma or mu overflow");
274 if (!( kmax + 1 <= maxint / _isig &&
275 _isig * (kmax + 1) <= maxint - iabs(_imu) ))
276 throw RandomErr(
"DiscreteNormal: possible overflow a");
278 if (!( kmax <= maxint / _sig &&
279 _sig * kmax <= maxint - iabs(_mu) ))
280 throw RandomErr(
"DiscreteNormal: possible overflow b");
283 if (!( _sig <= (maxint >> 8) ))
284 throw RandomErr(
"DiscreteNormal: overflow in LeadingDigit");
287 template<
typename IntType>
template<
class Random>
291 if (!ExpProb(r, k * (k - 1)))
continue;
294 xn = _sig * IntType(k) + s * _mu,
295 i = iceil(xn, _d) + r.template Integer<IntType>(_isig);
297 if (xn >= _sig || (k == 0 && s < 0 && xn <= 0))
continue;
299 word x0 = LeadingDigit(xn);
300 int h = k + 1;
while (h-- && B(r, k, x0, xn));
301 if (!(h < 0))
continue;
307 template<
typename IntType>
309 { IntType k = n / d;
return k + (k * d < n ? 1 : 0); }
311 template<
typename IntType> IntType DiscreteNormal<IntType>::iabs(IntType n)
312 {
return n < 0 ? -n : n; }
314 template<
typename IntType>
315 IntType DiscreteNormal<IntType>::gcd(IntType u, IntType v) {
317 u = iabs(u); v = iabs(v);
318 while (v > 0) { IntType r = u % v; u = v; v = r; }
322 template<
typename IntType>
typename DiscreteNormal<IntType>::word
323 DiscreteNormal<IntType>::LeadingDigit(IntType& p)
const {
324 static const unsigned bits = 8;
325 static const unsigned num = std::numeric_limits<word>::digits / bits;
326 STATIC_ASSERT(bits * num == std::numeric_limits<word>::digits,
327 "Number of digits in word must be multiple of 8");
329 for (
unsigned c = num; c--;) {
330 p <<= bits; s <<= bits;
331 word d = word(p / _sig);
333 p -= IntType(d) * _sig;
338 template<
typename IntType>
template<
class Random>
339 int DiscreteNormal<IntType>::Choose(
Random& r,
int m) {
340 int k = r.template Integer<int>(m);
341 return k == 0 ? 0 : (k == 1 ? -1 : 1);
344 template<
typename IntType>
template<
class Random>
345 bool DiscreteNormal<IntType>::less_than(
Random& r)
const {
346 for (
unsigned j = 0; ; ++j) {
349 if (_l == _m) _v.resize(_l += alloc_incr);
350 _v[_m++] = r.template Integer<word>();
352 word w = r.template Integer<word>();
355 else if (w < _v[j]) {
364 template<
typename IntType>
template<
class Random>
365 bool DiscreteNormal<IntType>::less_than(
Random& r, word x, IntType p)
const {
366 if (_m == 0) _v[_m++] = r.template Integer<word>();
367 if (_v[0] != x)
return _v[0] < x;
368 for (
unsigned j = 1; ; ++j) {
369 if (p == 0)
return false;
371 if (_l == _m) _v.resize(_l += alloc_incr);
372 _v[_m++] = r.template Integer<word>();
375 if (_v[j] != x)
return _v[j] < x;
379 template<
typename IntType>
template<
class Random>
380 bool DiscreteNormal<IntType>::bernoulli(
Random& r, word x, IntType p)
const {
381 word w = r.template Integer<word>();
382 if (w != x)
return w < x;
384 if (p == 0)
return false;
386 w = r.template Integer<word>();
387 if (w != x)
return w < x;
391 template<
typename IntType>
template<
class Random>
392 bool DiscreteNormal<IntType>::ExpProbH(
Random& r)
const {
393 static const word half = word(1) << (std::numeric_limits<word>::digits - 1);
395 if ((_v[_m++] = r.template Integer<word>()) & half)
return true;
398 for (
unsigned s = 0; ; s ^= 1) {
399 if (!less_than(r))
return s != 0u;
403 template<
typename IntType>
template<
class Random>
404 bool DiscreteNormal<IntType>::ExpProb(
Random& r,
int n)
const {
405 while (n-- > 0) {
if (!ExpProbH(r))
return false; }
409 template<
typename IntType>
template<
class Random>
410 int DiscreteNormal<IntType>::ExpProbN(
Random& r)
const {
412 while (ExpProbH(r)) ++n;
416 template<
typename IntType>
template<
class Random>
417 bool DiscreteNormal<IntType>::B(
Random& r,
int k, word x0, IntType xn)
419 int n = 0, h = 2 * k + 2, f;
422 if ( ((f = k ? 0 : Choose(r, h)) < 0) ||
423 !(n ? less_than(r) : less_than(r, x0, xn)) ||
424 ((f = k ? Choose(r, h) : f) < 0) ||
425 (f == 0 && !bernoulli(r, x0, xn)) )
break;
432 #endif // RANDOMLIB_DISCRETENORMAL_HPP
Generate random integers, reals, and booleans.
DiscreteNormal(IntType sigma_num, IntType sigma_den=1, IntType mu_num=0, IntType mu_den=1)
Exception handling for RandomLib.
#define STATIC_ASSERT(cond, reason)
RandomCanonical< RandomGenerator > Random
The discrete normal distribution.
IntType operator()(Random &r) const