Mercurial > octave
diff liboctave/numeric/randgamma.cc @ 25434:859ad1f0b85e
use templates to eliminate duplicate code in random number generators
* randgamma.h, randgamma.cc: Use templates to eliminate nearly duplicate
specializations.
* randpoisson.h, randpoisson.cc: Likewise.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Sat, 17 Mar 2018 11:59:05 -0500 |
parents | 49e0447413ad |
children | 00f796120a6d |
line wrap: on
line diff
--- a/liboctave/numeric/randgamma.cc Sat Mar 17 07:02:30 2018 -0500 +++ b/liboctave/numeric/randgamma.cc Sat Mar 17 11:59:05 2018 -0500 @@ -89,37 +89,31 @@ namespace octave { - -#define INFINITE lo_ieee_isinf -#define RUNI rand_uniform<double> () -#define RNOR rand_normal<double> () -#define REXP rand_exponential<double> () - - template <> void rand_gamma<double> (double a, octave_idx_type n, double *r) + template <typename T> void rand_gamma (T a, octave_idx_type n, T *r) { octave_idx_type i; /* If a < 1, start by generating gamma (1+a) */ - const double d = (a < 1. ? 1.+a : a) - 1./3.; - const double c = 1./std::sqrt (9.*d); + const T d = (a < 1. ? 1.+a : a) - 1./3.; + const T c = 1./std::sqrt (9.*d); /* Handle invalid cases */ - if (a <= 0 || INFINITE(a)) + if (a <= 0 || lo_ieee_isinf (a)) { for (i=0; i < n; i++) - r[i] = numeric_limits<double>::NaN (); + r[i] = numeric_limits<T>::NaN (); return; } for (i=0; i < n; i++) { - double x, xsq, v, u; + T x, xsq, v, u; restart: - x = RNOR; + x = rand_normal<T> (); v = (1+c*x); v *= v*v; if (v <= 0) goto restart; /* rare, so don't bother moving up */ - u = RUNI; + u = rand_uniform<T> (); xsq = x*x; if (u >= 1.-0.0331*xsq*xsq && std::log (u) >= 0.5*xsq + d*(1-v+std::log (v))) goto restart; @@ -130,55 +124,10 @@ /* Use gamma(a) = gamma(1+a)*U^(1/a) */ /* Given REXP = -log(U) then U^(1/a) = exp(-REXP/a) */ for (i = 0; i < n; i++) - r[i] *= exp (-REXP/a); + r[i] *= exp (-rand_exponential<T> () / a); } } -#undef RUNI -#undef RNOR -#undef REXP - -#define RUNI rand_uniform<float> () -#define RNOR rand_normal<float> () -#define REXP rand_exponential<float> () - - template <> void rand_gamma<float> (float a, octave_idx_type n, float *r) - { - octave_idx_type i; - /* If a < 1, start by generating gamma(1+a) */ - const float d = (a < 1. ? 1.+a : a) - 1./3.; - const float c = 1./std::sqrt (9.*d); - - /* Handle invalid cases */ - if (a <= 0 || INFINITE(a)) - { - for (i=0; i < n; i++) - r[i] = numeric_limits<float>::NaN (); - return; - } - - for (i=0; i < n; i++) - { - float x, xsq, v, u; - frestart: - x = RNOR; - v = (1+c*x); - v *= v*v; - if (v <= 0) - goto frestart; /* rare, so don't bother moving up */ - u = RUNI; - xsq = x*x; - if (u >= 1.-0.0331*xsq*xsq && std::log (u) >= 0.5*xsq + d*(1-v+std::log (v))) - goto frestart; - r[i] = d*v; - } - if (a < 1) - { - /* Use gamma(a) = gamma(1+a)*U^(1/a) */ - /* Given REXP = -log(U) then U^(1/a) = exp(-REXP/a) */ - for (i = 0; i < n; i++) - r[i] *= exp (-REXP/a); - } - } - + template void rand_gamma (double, octave_idx_type, double *); + template void rand_gamma (float, octave_idx_type, float *); }