// Ranlux24 PRNG. (2.02)
// Chaotic with long period but slow due to discard.
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <assert.h>
#include <stdio.h>
#include <time.h>
// Utility.
#define BITS(x) \
(sizeof(x) * CHAR_BIT)
#define UNLIKELY(cond) \
__builtin_expect(!!(cond), 0)
#define NEW_T(T, n) \
((T *) allocate(n * sizeof(T)))
void *allocate(size_t n)
{
return r;
}
// Private.
#define SWC_M 0xFFFFFFL
#define SWC_S 10
#define SWC_R 24
#define BLK_P 223
#define BLK_R 23
typedef struct {
int_least32_t *x; int c, i, j;
} Ranlux24;
static inline long next(int_least32_t *x, int i_s, int i_r, int *carry)
{
int_least32_t y = x[i_s] - x[i_r] - *carry;
*carry = -(y >> (BITS(y) - 1));
return y & SWC_M;
}
static long subtract_with_carry_next(Ranlux24 *self)
{
self->i += 1;
int_least32_t *x = self->x;
int i = self->i, r = SWC_R;
if (UNLIKELY(i == r))
{
int c = self->c, s = SWC_S, t = r - s;
for (i = 0; i < s; i++)
x[i] = next(x, i + t, i, &c);
for (i = s; i < r; i++)
x[i] = next(x, i - s, i, &c);
self->c = c;
self->i = i = 0;
}
return x[i];
}
static void subtract_with_carry_discard(Ranlux24 *self, long n)
{
for (long i = 0; i < n; i++)
subtract_with_carry_next(self);
}
// Public.
long ranlux24_next(Ranlux24 *self)
{
if (UNLIKELY(self->j == 0))
{
subtract_with_carry_discard(self, BLK_P - BLK_R);
self->j = BLK_R;
}
self->j -= 1;
return subtract_with_carry_next(self);
}
void ranlux24_discard(Ranlux24 *self, long n)
{
for (long i = 0; i < n; i++)
ranlux24_next(self);
}
void ranlux24_delete(Ranlux24 *self)
{
if (self != 0)
{
}
}
Ranlux24 *ranlux24_new(unsigned long seed)
{
Ranlux24 *self = NEW_T(Ranlux24, 1);
self->x = NEW_T(int_least32_t, SWC_R);
self->c = 0;
self->i = SWC_R-1;
self->j = BLK_R;
unsigned short rs[3] = {0x330E, seed, seed>>16};
for (int i = 0; i < SWC_R; i++)
self->x[i] = nrand48(rs) & SWC_M;
return self;
}
// Main.
double clock_now(void)
{
struct timespec now;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &now);
return now.tv_sec + now.tv_nsec / 1.0E+09;
}
int main(void)
{
unsigned long seed
= time(0); Ranlux24 *engine = ranlux24_new(seed);
for (int i = 0; i < 24; i++)
{
long r = ranlux24_next(engine);
}
long n = 10000000;
double t = clock_now();
ranlux24_discard(engine, n);
printf("Elapsed: %.9fs\n", clock_now
() - t
);
ranlux24_delete(engine);
return 0;
}
Ly8gUmFubHV4MjQgUFJORy4gKDIuMDIpCi8vIENoYW90aWMgd2l0aCBsb25nIHBlcmlvZCBidXQgc2xvdyBkdWUgdG8gZGlzY2FyZC4KCiNpbmNsdWRlIDxzdGRsaWIuaD4KI2luY2x1ZGUgPHN0ZGludC5oPgojaW5jbHVkZSA8bGltaXRzLmg+CiNpbmNsdWRlIDxhc3NlcnQuaD4KI2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDx0aW1lLmg+CgovLyBVdGlsaXR5LgoKI2RlZmluZSBCSVRTKHgpIFwKICAgIChzaXplb2YoeCkgKiBDSEFSX0JJVCkKCiNkZWZpbmUgVU5MSUtFTFkoY29uZCkgXAogICAgX19idWlsdGluX2V4cGVjdCghIShjb25kKSwgMCkKCiNkZWZpbmUgTkVXX1QoVCwgbikgXAogICAgKChUICopIGFsbG9jYXRlKG4gKiBzaXplb2YoVCkpKQoKdm9pZCAqYWxsb2NhdGUoc2l6ZV90IG4pCnsKICAgIHZvaWQgKnIgPSBtYWxsb2Mobik7CiAgICBhc3NlcnQociAhPSAwIHx8IG4gPT0gMCk7CiAgICByZXR1cm4gcjsKfQoKLy8gUHJpdmF0ZS4KCiNkZWZpbmUgU1dDX00gMHhGRkZGRkZMCiNkZWZpbmUgU1dDX1MgMTAKI2RlZmluZSBTV0NfUiAyNAojZGVmaW5lIEJMS19QIDIyMwojZGVmaW5lIEJMS19SIDIzCgp0eXBlZGVmIHN0cnVjdCB7CiAgICBpbnRfbGVhc3QzMl90ICp4OyBpbnQgYywgaSwgajsKfSBSYW5sdXgyNDsKCnN0YXRpYyBpbmxpbmUgbG9uZyBuZXh0KGludF9sZWFzdDMyX3QgKngsIGludCBpX3MsIGludCBpX3IsIGludCAqY2FycnkpCnsKICAgIGludF9sZWFzdDMyX3QgeSA9IHhbaV9zXSAtIHhbaV9yXSAtICpjYXJyeTsKICAgICpjYXJyeSA9IC0oeSA+PiAoQklUUyh5KSAtIDEpKTsKICAgIHJldHVybiB5ICYgU1dDX007Cn0KCnN0YXRpYyBsb25nIHN1YnRyYWN0X3dpdGhfY2FycnlfbmV4dChSYW5sdXgyNCAqc2VsZikKewogICAgc2VsZi0+aSArPSAxOwogICAgaW50X2xlYXN0MzJfdCAqeCA9IHNlbGYtPng7CiAgICBpbnQgaSA9IHNlbGYtPmksIHIgPSBTV0NfUjsKCiAgICBpZiAoVU5MSUtFTFkoaSA9PSByKSkKICAgIHsKICAgICAgICBpbnQgYyA9IHNlbGYtPmMsIHMgPSBTV0NfUywgdCA9IHIgLSBzOwoKICAgICAgICBmb3IgKGkgPSAwOyBpIDwgczsgaSsrKQogICAgICAgICAgICB4W2ldID0gbmV4dCh4LCBpICsgdCwgaSwgJmMpOwogICAgICAgIGZvciAoaSA9IHM7IGkgPCByOyBpKyspCiAgICAgICAgICAgIHhbaV0gPSBuZXh0KHgsIGkgLSBzLCBpLCAmYyk7CiAgICAgICAgc2VsZi0+YyA9IGM7CiAgICAgICAgc2VsZi0+aSA9IGkgPSAwOwogICAgfQogICAgcmV0dXJuIHhbaV07Cn0KCnN0YXRpYyB2b2lkIHN1YnRyYWN0X3dpdGhfY2FycnlfZGlzY2FyZChSYW5sdXgyNCAqc2VsZiwgbG9uZyBuKQp7CiAgICBmb3IgKGxvbmcgaSA9IDA7IGkgPCBuOyBpKyspCiAgICAgICAgc3VidHJhY3Rfd2l0aF9jYXJyeV9uZXh0KHNlbGYpOwp9CgovLyBQdWJsaWMuCgpsb25nIHJhbmx1eDI0X25leHQoUmFubHV4MjQgKnNlbGYpCnsKICAgIGlmIChVTkxJS0VMWShzZWxmLT5qID09IDApKQogICAgewogICAgICAgIHN1YnRyYWN0X3dpdGhfY2FycnlfZGlzY2FyZChzZWxmLCBCTEtfUCAtIEJMS19SKTsKICAgICAgICBzZWxmLT5qID0gQkxLX1I7CiAgICB9CiAgICBzZWxmLT5qIC09IDE7CiAgICByZXR1cm4gc3VidHJhY3Rfd2l0aF9jYXJyeV9uZXh0KHNlbGYpOwp9Cgp2b2lkIHJhbmx1eDI0X2Rpc2NhcmQoUmFubHV4MjQgKnNlbGYsIGxvbmcgbikKewogICAgZm9yIChsb25nIGkgPSAwOyBpIDwgbjsgaSsrKQogICAgICAgIHJhbmx1eDI0X25leHQoc2VsZik7Cn0KCnZvaWQgcmFubHV4MjRfZGVsZXRlKFJhbmx1eDI0ICpzZWxmKQp7CiAgICBpZiAoc2VsZiAhPSAwKQogICAgewogICAgICAgIGZyZWUoc2VsZi0+eCk7CiAgICAgICAgZnJlZShzZWxmKTsKICAgIH0KfQoKUmFubHV4MjQgKnJhbmx1eDI0X25ldyh1bnNpZ25lZCBsb25nIHNlZWQpCnsKICAgIFJhbmx1eDI0ICpzZWxmID0gTkVXX1QoUmFubHV4MjQsIDEpOwogICAgc2VsZi0+eCA9IE5FV19UKGludF9sZWFzdDMyX3QsIFNXQ19SKTsKICAgIHNlbGYtPmMgPSAwOwogICAgc2VsZi0+aSA9IFNXQ19SLTE7CiAgICBzZWxmLT5qID0gQkxLX1I7CgogICAgdW5zaWduZWQgc2hvcnQgcnNbM10gPSB7MHgzMzBFLCBzZWVkLCBzZWVkPj4xNn07CgogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBTV0NfUjsgaSsrKQogICAgICAgIHNlbGYtPnhbaV0gPSBucmFuZDQ4KHJzKSAmIFNXQ19NOwogICAgcmV0dXJuIHNlbGY7Cn0KCi8vIE1haW4uCgpkb3VibGUgY2xvY2tfbm93KHZvaWQpCnsKICAgIHN0cnVjdCB0aW1lc3BlYyBub3c7CiAgICBjbG9ja19nZXR0aW1lKENMT0NLX1BST0NFU1NfQ1BVVElNRV9JRCwgJm5vdyk7CiAgICByZXR1cm4gbm93LnR2X3NlYyArIG5vdy50dl9uc2VjIC8gMS4wRSswOTsKfQoKaW50IG1haW4odm9pZCkKewogICAgdW5zaWduZWQgbG9uZyBzZWVkID0gdGltZSgwKTsKICAgIFJhbmx1eDI0ICplbmdpbmUgPSByYW5sdXgyNF9uZXcoc2VlZCk7CgogICAgZm9yIChpbnQgaSA9IDA7IGkgPCAyNDsgaSsrKQogICAgewogICAgICAgIGxvbmcgciA9IHJhbmx1eDI0X25leHQoZW5naW5lKTsKICAgICAgICBwcmludGYoIiVsZFxuIiwgcik7CiAgICB9CgogICAgbG9uZyBuID0gMTAwMDAwMDA7CiAgICBkb3VibGUgdCA9IGNsb2NrX25vdygpOwogICAgcmFubHV4MjRfZGlzY2FyZChlbmdpbmUsIG4pOwogICAgcHJpbnRmKCJFbGFwc2VkOiAlLjlmc1xuIiwgY2xvY2tfbm93KCkgLSB0KTsKCiAgICByYW5sdXgyNF9kZWxldGUoZW5naW5lKTsKICAgIHJldHVybiAwOwp9