Skip to content

Commit 92fe17e

Browse files
committed
Support exponential draws as well (closes #1)
1 parent cd61cb0 commit 92fe17e

File tree

6 files changed

+101
-10
lines changed

6 files changed

+101
-10
lines changed

ChangeLog

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
2025-01-02 Dirk Eddelbuettel <[email protected]>
2+
3+
* inst/include/Ziggurat.h (kiss): Use an inline function avoiding a
4+
compiler nag relative which KISS macro triggers
5+
(rexp): Added, using inline kiss()
6+
(efix): Added as well supporting rexp()
7+
(init): Also initialize tables for exponential RNG
8+
9+
* src/ziggurat.cpp (zrexp): Added, calling rexp()
10+
* man/ziggurat.Rd: Add alias for zrexp()
11+
* src/RcppExports.cpp: Regenerated
12+
* R/RcppExports.R: Idem
13+
114
2024-12-30 Dirk Eddelbuettel <[email protected]>
215

316
* R/standardTest.R (.safeMaxCores): New helper function to provide

R/RcppExports.R

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ zrnorm <- function(n) {
4141
.Call(`_RcppZiggurat_zrnorm`, n)
4242
}
4343

44+
zrexp <- function(n) {
45+
.Call(`_RcppZiggurat_zrexp`, n)
46+
}
47+
4448
zrnormVec <- function(x) {
4549
.Call(`_RcppZiggurat_zrnormVec`, x)
4650
}

inst/include/Ziggurat.h

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2-
//
31
// Ziggurat.h: Marsaglia + Tsang / Leong, Zhang et al Ziggurat generator
42
//
5-
// Copyright (C) 2013 Dirk Eddelbuettel
3+
// Copyright (C) 2013 - 2025 Dirk Eddelbuettel
64
//
75
// This file is part of RcppZiggurat.
86
//
@@ -66,7 +64,8 @@ namespace Ziggurat {
6664

6765
#define UNI (0.5 + (int32_t) KISS * 0.2328306e-09)
6866
#define IUNI KISS
69-
#define RNOR (hz = KISS, iz = hz & 127, ( abs ( hz ) < kn[iz] ) ? hz * wn[iz] : nfix())
67+
//#define RNOR (hz = KISS, iz = hz & 127, ( abs ( hz ) < kn[iz] ) ? hz * wn[iz] : nfix())
68+
//#define REXP (jz = KISS, iz = jz & 255, ( jz < ke[iz] ) ? jz * we[iz] : efix())
7069

7170
class Ziggurat : public Zigg {
7271
public:
@@ -88,8 +87,14 @@ namespace Ziggurat {
8887
uint32_t getSeed() {
8988
return jsr;
9089
}
90+
inline uint32_t kiss() {
91+
return ((MWC ^ CONG ) + SHR3);
92+
}
9193
inline double norm() {
92-
return RNOR;
94+
return (hz = kiss(), iz = hz & 127, ( abs ( hz ) < kn[iz] ) ? hz * wn[iz] : nfix());
95+
}
96+
inline double rexp() {
97+
return (jz = kiss(), iz = jz & 255, ( jz < ke[iz] ) ? jz * we[iz] : efix());
9398
}
9499
std::vector<uint32_t> getPars() {
95100
//C++11: std::vector<uint32_t> pars{ jsr, z, w, jcong };
@@ -109,23 +114,25 @@ namespace Ziggurat {
109114

110115
private:
111116
double fn[128];
117+
double fe[256];
112118
int32_t hz;
113119
uint32_t iz;
114120
uint32_t jcong;
115121
uint32_t jsr;
116122
uint32_t jz;
117123
uint32_t kn[128];
124+
uint32_t ke[256];
118125
uint32_t w;
119126
double wn[128];
127+
double we[256];
120128
uint32_t z;
121129

122130
void init() { // called from ctor, could be in ctor
123-
double dn = 3.442619855899;
131+
double dn = 3.442619855899, de=7.697117470131487;
124132
int i;
125-
const double m1 = 2147483648.0;
126-
double q;
127-
double tn = 3.442619855899;
128-
const double vn = 9.91256303526217E-03;
133+
const double m1 = 2147483648.0, m2 = 4294967296.0;
134+
double tn = dn, te = de, q;
135+
const double vn = 9.91256303526217E-03, ve=3.949659822581572e-3;
129136

130137
// Set up the tables for the normal random number generator.
131138
q = vn / exp (- 0.5 * dn * dn);
@@ -145,6 +152,25 @@ namespace Ziggurat {
145152
fn[i] = (double) (exp( - 0.5 * dn * dn));
146153
wn[i] = (double) (dn / m1);
147154
}
155+
156+
// Set up the tables for the exponential random number generator.
157+
q = ve/exp(-de);
158+
ke[0] = (uint32_t) (de/q)*m2;
159+
ke[1]=0;
160+
161+
we[0] = (double) q/m2;
162+
we[255] = (double) de/m2;
163+
164+
fe[0] = 1.0;
165+
fe[255] = (double) exp(-de);
166+
167+
for (i=254; i>=1; i--) {
168+
de = -log(ve/de+exp(-de));
169+
ke[i+1] = (de/te) * m2;
170+
te = de;
171+
fe[i] = (double) exp(-de);
172+
we[i] = (double) de/m2;
173+
}
148174
return;
149175
}
150176

@@ -177,6 +203,26 @@ namespace Ziggurat {
177203
}
178204
}
179205
}
206+
inline double efix(void) {
207+
double x;
208+
for ( ; ; ) {
209+
// IZ = 0.
210+
if (iz == 0) {
211+
return (7.69711 - log (UNI));
212+
}
213+
x = jz * we[iz];
214+
if (fe[iz] + UNI * (fe[iz-1] - fe[iz]) < exp (- x)) {
215+
return x;
216+
}
217+
// Initiate, try to exit the loop.
218+
jz = SHR3; // note we still use SHR3; using KISS leads to degradation
219+
iz = (jz & 255);
220+
if (jz < ke[iz]) {
221+
return ((double) (jz * we[iz]));
222+
}
223+
}
224+
}
225+
180226
};
181227

182228
#undef znew

man/ziggurat.Rd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
\name{zrnorm}
22
\alias{zrnorm}
3+
\alias{zrexp}
34
\alias{zrnormLZLLV}
45
\alias{zrnormMT}
56
\alias{zrnormV1}
@@ -36,6 +37,7 @@
3637
}
3738
\usage{
3839
zrnorm(n)
40+
zrexp(n)
3941
zrnormLZLLV(n)
4042
zrnormMT(n)
4143
zrnormV1(n)

src/RcppExports.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66

77
using namespace Rcpp;
88

9+
#ifdef RCPP_USE_GLOBAL_ROSTREAM
10+
Rcpp::Rostream<true>& Rcpp::Rcout = Rcpp::Rcpp_cout_get();
11+
Rcpp::Rostream<false>& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get();
12+
#endif
13+
914
// zrnormMT
1015
Rcpp::NumericVector zrnormMT(int n);
1116
RcppExport SEXP _RcppZiggurat_zrnormMT(SEXP nSEXP) {
@@ -112,6 +117,17 @@ BEGIN_RCPP
112117
return rcpp_result_gen;
113118
END_RCPP
114119
}
120+
// zrexp
121+
Rcpp::NumericVector zrexp(int n);
122+
RcppExport SEXP _RcppZiggurat_zrexp(SEXP nSEXP) {
123+
BEGIN_RCPP
124+
Rcpp::RObject rcpp_result_gen;
125+
Rcpp::RNGScope rcpp_rngScope_gen;
126+
Rcpp::traits::input_parameter< int >::type n(nSEXP);
127+
rcpp_result_gen = Rcpp::wrap(zrexp(n));
128+
return rcpp_result_gen;
129+
END_RCPP
130+
}
115131
// zrnormVec
116132
Rcpp::NumericVector zrnormVec(Rcpp::NumericVector x);
117133
RcppExport SEXP _RcppZiggurat_zrnormVec(SEXP xSEXP) {
@@ -315,6 +331,7 @@ static const R_CallMethodDef CallEntries[] = {
315331
{"_RcppZiggurat_zsetseedV1", (DL_FUNC) &_RcppZiggurat_zsetseedV1, 1},
316332
{"_RcppZiggurat_zgetseedV1", (DL_FUNC) &_RcppZiggurat_zgetseedV1, 0},
317333
{"_RcppZiggurat_zrnorm", (DL_FUNC) &_RcppZiggurat_zrnorm, 1},
334+
{"_RcppZiggurat_zrexp", (DL_FUNC) &_RcppZiggurat_zrexp, 1},
318335
{"_RcppZiggurat_zrnormVec", (DL_FUNC) &_RcppZiggurat_zrnormVec, 1},
319336
{"_RcppZiggurat_zrnormStl", (DL_FUNC) &_RcppZiggurat_zrnormStl, 1},
320337
{"_RcppZiggurat_zsetseed", (DL_FUNC) &_RcppZiggurat_zsetseed, 1},

src/ziggurat.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ Rcpp::NumericVector zrnorm(int n) {
130130
return x;
131131
}
132132

133+
// [[Rcpp::export]]
134+
Rcpp::NumericVector zrexp(int n) {
135+
Rcpp::NumericVector x(n);
136+
for (int i=0; i<n; i++) {
137+
x[i] = zigg.rexp();
138+
}
139+
return x;
140+
}
141+
133142
// [[Rcpp::export]]
134143
Rcpp::NumericVector zrnormVec(Rcpp::NumericVector x) {
135144
int n = x.size();

0 commit comments

Comments
 (0)