File Coverage

MRMA.xs
Criterion Covered Total %
statement 247 258 95.7
branch 193 252 76.5
condition n/a
subroutine n/a
pod n/a
total 440 510 86.2


line stmt bran cond sub pod time code
1             /* Mersenne Twister PRNG
2              
3             A C-Program for MT19937 (32- and 64-bit versions), with initialization
4             improved 2002/1/26. Coded by Takuji Nishimura and Makoto Matsumoto,
5             and including Shawn Cokus's optimizations.
6              
7             Copyright (C) 1997 - 2004, Makoto Matsumoto and Takuji Nishimura,
8             All rights reserved.
9             Copyright (C) 2005, Mutsuo Saito, All rights reserved.
10             Copyright 2005 - 2009 Jerry D. Hedden
11              
12             Redistribution and use in source and binary forms, with or without
13             modification, are permitted provided that the following conditions
14             are met:
15              
16             1. Redistributions of source code must retain the above copyright
17             notice, this list of conditions and the following disclaimer.
18              
19             2. Redistributions in binary form must reproduce the above copyright
20             notice, this list of conditions and the following disclaimer in the
21             documentation and/or other materials provided with the distribution.
22              
23             3. The names of its contributors may not be used to endorse or promote
24             products derived from this software without specific prior written
25             permission.
26              
27             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28             "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29             LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30             A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
31             OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32             EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33             PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34             PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35             LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36             NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37             SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38              
39             Any feedback is very welcome.
40            
41             http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
42             */
43              
44             #include "EXTERN.h"
45             #include "perl.h"
46             #include "XSUB.h"
47             #define NEED_newRV_noinc
48             #include "ppport.h"
49              
50             #include
51              
52              
53             #if UVSIZE == 8
54             /* Constants related to the Mersenne Twister */
55             # define N 312 /* Number of 64-bit ints in state vector */
56             # define M 156
57              
58             /* Macros used inside Mersenne Twister algorithm */
59             # define MIXBITS(u,v) ( ((u) & 0xFFFFFFFF80000000ULL) | ((v) & 0x7FFFFFFFULL) )
60             # define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? 0xB5026F5AA96619E9ULL : 0ULL))
61              
62             /* Final randomization of integer extracted from state vector */
63             # define TEMPER_ELEM(x) \
64             x ^= (x >> 29) & 0x0000000555555555ULL; \
65             x ^= (x << 17) & 0x71D67FFFEDA60000ULL; \
66             x ^= (x << 37) & 0xFFF7EEE000000000ULL; \
67             x ^= (x >> 43)
68              
69             /* Seed routine constants */
70             # define BIT_SHIFT 62
71             # define MAGIC1 6364136223846793005ULL
72             # define MAGIC2 3935559000370003845ULL
73             # define MAGIC3 2862933555777941757ULL
74             # define HI_BIT 1ULL<<63
75              
76             /* Various powers of 2 */
77             # define TWOeMINUS51 4.44089209850062616169452667236328125e-16
78             # define TWOeMINUS52 2.220446049250313080847263336181640625e-16
79             # define TWOeMINUS53 1.1102230246251565404236316680908203125e-16
80              
81             /* Make a double between 0 (inclusive) and 1 (exclusive) */
82             # define RAND_0i_1x(x) (((NV)((x) >> 12)) * TWOeMINUS52)
83             /* Make a double between 0 and 1 (exclusive) */
84             # define RAND_0x_1x(x) (RAND_0i_1x(x) + TWOeMINUS53)
85             /* Make a double between 0 (exclusive) and 1 (inclusive) */
86             # define RAND_0x_1i(x) (((NV)(((x) >> 12) + 1)) * TWOeMINUS52)
87             /* Make a double between -1 and 1 (exclusive) */
88             # define RAND_NEG1x_1x(x) ((((NV)(((IV)(x)) >> 11)) * TWOeMINUS52) + TWOeMINUS53)
89              
90             #else
91             /* Constants related to the Mersenne Twister */
92             # define N 624 /* Number of 32-bit ints in state vector */
93             # define M 397
94              
95             /* Macros used inside Mersenne Twister algorithm */
96             # define MIXBITS(u,v) ( ((u) & 0x80000000) | ((v) & 0x7FFFFFFF) )
97             # define TWIST(u,v) ((MIXBITS((u),(v)) >> 1) ^ (((v)&1UL) ? 0x9908B0DF : 0UL))
98              
99             /* Final randomization of integer extracted from state vector */
100             # define TEMPER_ELEM(x) \
101             x ^= (x >> 11); \
102             x ^= (x << 7) & 0x9D2C5680; \
103             x ^= (x << 15) & 0xEFC60000; \
104             x ^= (x >> 18)
105              
106             /* Seed routine constants */
107             # define BIT_SHIFT 30
108             # define MAGIC1 1812433253
109             # define MAGIC2 1664525
110             # define MAGIC3 1566083941
111             # define HI_BIT 0x80000000
112              
113             /* Various powers of 2 */
114             # define TWOeMINUS31 4.656612873077392578125e-10
115             # define TWOeMINUS32 2.3283064365386962890625e-10
116             # define TWOeMINUS33 1.16415321826934814453125e-10
117              
118             /* Make a double between 0 (inclusive) and 1 (exclusive) */
119             # define RAND_0i_1x(x) ((NV)(x) * TWOeMINUS32)
120             /* Make a double between 0 and 1 (exclusive) */
121             # define RAND_0x_1x(x) (RAND_0i_1x(x) + TWOeMINUS33)
122             /* Make a double between 0 (exclusive) and 1 (inclusive) */
123             # define RAND_0x_1i(x) ((((NV)(x)) + 1.0) * TWOeMINUS32)
124             /* Make a double between -1 and 1 (exclusive) */
125             # define RAND_NEG1x_1x(x) ((((NV)((IV)(x))) * TWOeMINUS31) + TWOeMINUS32)
126             #endif
127              
128              
129             /* Standalone PRNG */
130             #define SA_PRNG "MRMA::PRNG"
131              
132             /* Definitions for getting PRNG context */
133             #define PRNG_VARS SV *addr
134              
135             #define PRNG_PREP addr = SvRV(ST(0))
136             #define GET_PRNG INT2PTR(struct mt *, SvUV(addr))
137              
138             /* Variable declarations for the dual (OO and functional) interface */
139             #define DUAL_VARS \
140             PRNG_VARS; \
141             struct mt *prng; \
142             int idx
143              
144             /* Sets up PRNG for dual-interface */
145             /* A ref check for an object call is good enough,
146             * and much faster than object or 'isa' checking. */
147             #define DUAL_PRNG \
148             if (items && SvROK(ST(0))) { \
149             /* OO interface */ \
150             PRNG_PREP; \
151             items--; \
152             idx = 1; \
153             } else { \
154             /* Standalone PRNG */ \
155             addr = SvRV(get_sv(SA_PRNG, 0));\
156             idx = 0; \
157             } \
158             prng = GET_PRNG;
159              
160             /* Get next random from a PRNG */
161             #define IRAND(x,y) \
162             x = ((--y->left == 0) ? _mt_algo(y) : *y->next++); \
163             TEMPER_ELEM(x)
164              
165              
166             /* The PRNG state structure (AKA the PRNG context) */
167             struct mt {
168             UV state[N];
169             UV *next;
170             IV left;
171              
172             struct {
173             IV have;
174             NV value;
175             } gaussian;
176              
177             struct {
178             NV mean;
179             NV log_mean;
180             NV sqrt2mean;
181             NV term;
182             } poisson;
183              
184             struct {
185             IV trials;
186             NV term;
187             NV prob;
188             NV plog;
189             NV pclog;
190             } binomial;
191             };
192              
193              
194             /* The state mixing algorithm for the Mersenne Twister */
195             static UV
196 4139           _mt_algo(struct mt *prng)
197             {
198 4139           UV *st = prng->state;
199 4139           UV *sn = &st[2];
200 4139           UV *sx = &st[M];
201 4139           UV n0 = st[0];
202 4139           UV n1 = st[1];
203             int kk;
204              
205 649823 100         for (kk = N-M+1; --kk; n0 = n1, n1 = *sn++) {
206 645684 100         *st++ = *sx++ ^ TWIST(n0, n1);
207             }
208 4139           sx = prng->state;
209 645684 100         for (kk = M; --kk; n0 = n1, n1 = *sn++) {
210 641545 100         *st++ = *sx++ ^ TWIST(n0, n1);
211             }
212 4139           n1 = *prng->state;
213 4139 100         *st = *sx ^ TWIST(n0, n1);
214              
215 4139           prng->next = &prng->state[1];
216 4139           prng->left = N;
217              
218 4139           return (n1);
219             }
220              
221              
222             /* Helper function to get next random double */
223             static NV
224 590           _rand(struct mt *prng)
225             {
226             UV x;
227 590 100         IRAND(x, prng);
228 590           return (RAND_0x_1x(x));
229             }
230              
231              
232             /* Helper function to calculate a random tan(angle) */
233             static NV
234 136           _tan(struct mt *prng)
235             {
236             UV x1, y1;
237             NV x2, y2;
238              
239             do {
240 174 50         IRAND(x1, prng);
241 174 50         IRAND(y1, prng);
242 174           x2 = RAND_NEG1x_1x(x1);
243 174           y2 = RAND_NEG1x_1x(y1);
244 174 100         } while (x2*x2 + y2*y2 > 1.0);
245 136           return (y2/x2);
246              
247             /* The above is faster than the following:
248             UV x;
249             IRAND(x, prng);
250             return (tan(3.1415926535897932 * RAND_0x_1x(x)));
251             */
252             }
253              
254              
255             /* Helper function that returns the value ln(gamma(x)) for x > 0 */
256             /* Optimized from 'Numerical Recipes in C', Chapter 6.1 */
257             static NV
258 146           _ln_gamma(NV x)
259             {
260             NV qq, ser;
261              
262 146           qq = x + 4.5;
263 146           qq -= (x - 0.5) * log(qq);
264              
265 146           ser = 1.000000000190015
266 146           + (76.18009172947146 / x)
267 146           - (86.50532032941677 / (x + 1.0))
268 146           + (24.01409824083091 / (x + 2.0))
269 146           - (1.231739572450155 / (x + 3.0))
270 146           + (1.208650973866179e-3 / (x + 4.0))
271 146           - (5.395239384953e-6 / (x + 5.0));
272              
273 146           return (log(2.5066282746310005 * ser) - qq);
274             }
275              
276              
277             MODULE = Math::Random::MT::Auto PACKAGE = Math::Random::MT::Auto
278             PROTOTYPES: DISABLE
279              
280              
281             # The functions below are the random number deviates for the module.
282              
283             # They work both as regular 'functions' for the functional interface to the
284             # standalone PRNG, as well as methods for the OO interface to PRNG objects.
285              
286              
287             # irand
288             #
289             # Returns a random integer.
290              
291             UV
292             irand(...)
293             PREINIT:
294             DUAL_VARS;
295             CODE:
296 9556 100         DUAL_PRNG
    50          
    50          
297 9556 100         IRAND(RETVAL, prng);
298             OUTPUT:
299             RETVAL
300              
301              
302             # rand
303             #
304             # Returns a random number on the range [0,1),
305             # or [0,X) if an argument is supplied.
306              
307             double
308             rand(...)
309             PREINIT:
310             DUAL_VARS;
311             UV rand;
312             CODE:
313 2030 100         DUAL_PRNG
    50          
    50          
314              
315             /* Random number on [0,1) interval */
316 2030 100         IRAND(rand, prng);
317 2030           RETVAL = RAND_0i_1x(rand);
318 2030 100         if (items) {
319             /* Random number on [0,X) interval */
320 30 100         RETVAL *= SvNV(ST(idx));
321             }
322             OUTPUT:
323             RETVAL
324              
325              
326             # shuffle
327             #
328             # Shuffles input data using the Fisher-Yates shuffle algorithm.
329              
330             SV *
331             shuffle(...)
332             PREINIT:
333             DUAL_VARS;
334             AV *ary;
335             I32 ii, jj;
336             UV rand;
337             SV *elem;
338             CODE:
339             /* Same as DUAL_PRNG except needs more stringent object check */
340 4 50         if (items && sv_isobject(ST(0))) {
    100          
341             /* OO interface */
342 1           PRNG_PREP;
343 1           items--;
344 1           idx = 1;
345             } else {
346             /* Standalone PRNG */
347 3           addr = SvRV(get_sv(SA_PRNG, 0));
348 3           idx = 0;
349             }
350 4 50         prng = GET_PRNG;
351              
352             /* Handle arguments */
353 4 100         if (items == 1 && SvROK(ST(idx)) && SvTYPE(SvRV(ST(idx)))==SVt_PVAV) {
    50          
    50          
354             /* User supplied an array reference */
355 2           ary = (AV*)SvRV(ST(idx));
356 2           RETVAL = newRV_inc((SV *)ary);
357              
358 2 50         } else if (GIMME_V == G_ARRAY) {
    100          
359             /* If called in array context, shuffle directly on stack */
360 7 100         for (ii = items-1 ; ii > 0 ; ii--) {
361             /* Pick a random element from the beginning
362             of the array to the current element */
363 6 50         IRAND(rand, prng);
364 6           jj = rand % (ii + 1);
365             /* Swap elements */
366 6           SV *elem = ST(jj);
367 6           ST(jj) = ST(ii);
368 6           ST(ii) = elem;
369             }
370 1           XSRETURN(items);
371              
372             } else {
373             /* Create an array from user supplied values */
374 1           ary = newAV();
375 1           av_extend(ary, items);
376 8 100         while (items--) {
377 7           av_push(ary, newSVsv(ST(idx++)));
378             }
379 1           RETVAL = newRV_noinc((SV *)ary);
380             }
381              
382             /* Process elements from last to second */
383 21 100         for (ii=av_len(ary); ii > 0; ii--) {
384             /* Pick a random element from the beginning
385             of the array to the current element */
386 18 50         IRAND(rand, prng);
387 18           jj = rand % (ii + 1);
388             /* Swap elements */
389 18           elem = AvARRAY(ary)[ii];
390 18           AvARRAY(ary)[ii] = AvARRAY(ary)[jj];
391 18           AvARRAY(ary)[jj] = elem;
392             }
393             OUTPUT:
394             RETVAL
395              
396              
397             # gaussian
398             #
399             # Returns random numbers from a Gaussian distribution.
400             #
401             # On the first pass it calculates two numbers, returning one and saving the
402             # other. On the next pass, it just returns the previously saved number.
403              
404             double
405             gaussian(...)
406             PREINIT:
407             DUAL_VARS;
408             UV u1, u2;
409             NV v1, v2, r, factor;
410             CODE:
411 1000000 50         DUAL_PRNG
    100          
    50          
412              
413 1000000 100         if (prng->gaussian.have) {
414             /* Use number generated during previous call */
415 500000           RETVAL = prng->gaussian.value;
416 500000           prng->gaussian.have = 0;
417              
418             } else {
419             /* Marsaglia's polar method for the Box-Muller transformation */
420             /* See 'Numerical Recipes in C', Chapter 7.2 */
421             do {
422 637082 100         IRAND(u1, prng);
423 637082 50         IRAND(u2, prng);
424 637082           v1 = RAND_NEG1x_1x(u1);
425 637082           v2 = RAND_NEG1x_1x(u2);
426 637082           r = v1*v1 + v2*v2;
427 637082 100         } while (r >= 1.0);
428              
429 500000           factor = sqrt((-2.0 * log(r)) / r);
430 500000           RETVAL = v1 * factor;
431              
432             /* Save 2nd value for later */
433 500000           prng->gaussian.value = v2 * factor;
434 500000           prng->gaussian.have = 1;
435             }
436              
437 1000000 50         if (items) {
438             /* Gaussian distribution with SD = X */
439 1000000 100         RETVAL *= SvNV(ST(idx));
440 1000000 50         if (items > 1) {
441             /* Gaussian distribution with mean = Y */
442 0 0         RETVAL += SvNV(ST(idx+1));
443             }
444             }
445             OUTPUT:
446             RETVAL
447              
448              
449             # exponential
450             #
451             # Returns random numbers from an exponential distribution.
452              
453             double
454             exponential(...)
455             PREINIT:
456             DUAL_VARS;
457             CODE:
458 20 100         DUAL_PRNG
    50          
    50          
459              
460             /* Exponential distribution with mean = 1 */
461 20           RETVAL = -log(_rand(prng));
462 20 100         if (items) {
463             /* Exponential distribution with mean = X */
464 10 100         RETVAL *= SvNV(ST(idx));
465             }
466             OUTPUT:
467             RETVAL
468              
469              
470             # erlang
471             #
472             # Returns random numbers from an Erlang distribution.
473              
474             double
475             erlang(...)
476             PREINIT:
477             DUAL_VARS;
478             IV order;
479             IV ii;
480             NV am, ss, tang, bound;
481             CODE:
482 40 50         DUAL_PRNG
    100          
    50          
483              
484             /* Check argument */
485 40 50         if (! items) {
486 0           Perl_croak(aTHX_ "Missing argument to 'erlang'");
487             }
488 40 50         if ((order = SvIV(ST(idx))) < 1) {
    50          
489 0           Perl_croak(aTHX_ "Bad argument (< 1) to 'erlang'");
490             }
491              
492 40 100         if (order < 6) {
493             /* Direct method of 'adding exponential randoms' */
494 20           RETVAL = 1.0;
495 80 100         for (ii=0; ii < order; ii++) {
496 60           RETVAL *= _rand(prng);
497             }
498 20           RETVAL = -log(RETVAL);
499              
500             } else {
501             /* Use J. H. Ahren's rejection method */
502             /* See 'Numerical Recipes in C', Chapter 7.3 */
503 20           am = order - 1;
504 20           ss = sqrt(2.0 * am + 1.0);
505             do {
506             do {
507 36           tang = _tan(prng);
508 36           RETVAL = (tang * ss) + am;
509 36 100         } while (RETVAL <= 0.0);
510 32           bound = (1.0 + tang*tang) * exp(am * log(RETVAL/am) - ss*tang);
511 32 100         } while (_rand(prng) > bound);
512             }
513              
514 40 50         if (items > 1) {
515             /* Erlang distribution with mean = X */
516 0 0         RETVAL *= SvNV(ST(idx+1));
517             }
518             OUTPUT:
519             RETVAL
520              
521              
522             # poisson
523             #
524             # Returns random numbers from a Poisson distribution.
525              
526             IV
527             poisson(...)
528             PREINIT:
529             DUAL_VARS;
530             NV mean;
531             NV em, tang, bound, limit;
532             CODE:
533 40 50         DUAL_PRNG
    100          
    50          
534              
535             /* Check argument(s) */
536 40 50         if (! items) {
537 0           Perl_croak(aTHX_ "Missing argument(s) to 'poisson'");
538             }
539 40 50         if (items == 1) {
540 40 100         if ((mean = SvNV(ST(idx))) <= 0.0) {
    50          
541 0           Perl_croak(aTHX_ "Bad argument (<= 0) to 'poisson'");
542             }
543             } else {
544 0 0         if ((mean = SvNV(ST(idx)) * SvNV(ST(idx+1))) < 1.0) {
    0          
    0          
545 0           Perl_croak(aTHX_ "Bad arguments (rate*time <= 0) to 'poisson'");
546             }
547             }
548              
549 40 100         if (mean < 12.0) {
550             /* Direct method */
551 20           bound = 1.0;
552 20           limit = exp(-mean);
553 20           for (RETVAL=0; ; RETVAL++) {
554 69           bound *= _rand(prng);
555 69 100         if (bound < limit) {
556 20           break;
557             }
558 69           }
559              
560             } else {
561             /* Rejection method */
562             /* See 'Numerical Recipes in C', Chapter 7.3 */
563 20 100         if (prng->poisson.mean != mean) {
564 2           prng->poisson.mean = mean;
565 2           prng->poisson.log_mean = log(mean);
566 2           prng->poisson.sqrt2mean = sqrt(2.0 * mean);
567 2           prng->poisson.term = (mean * prng->poisson.log_mean)
568 2           - _ln_gamma(mean + 1.0);
569             }
570             do {
571             do {
572 32           tang = _tan(prng);
573 32           em = (tang * prng->poisson.sqrt2mean) + mean;
574 32 100         } while (em < 0.0);
575 30           em = floor(em);
576 60           bound = 0.9 * (1.0 + tang*tang)
577 60           * exp((em * prng->poisson.log_mean)
578 30           - _ln_gamma(em+1.0)
579 30           - prng->poisson.term);
580 30 100         } while (_rand(prng) > bound);
581 20           RETVAL = (int)em;
582             }
583             OUTPUT:
584             RETVAL
585              
586              
587             # binomial
588             #
589             # Returns random numbers from a binomial distribution.
590              
591             IV
592             binomial(...)
593             PREINIT:
594             DUAL_VARS;
595             NV prob;
596             IV trials;
597             int ii;
598             NV p, pc, mean;
599             NV en, em, tang, bound, limit, sq;
600             CODE:
601 60 50         DUAL_PRNG
    100          
    50          
602              
603             /* Check argument(s) */
604 60 50         if (items < 2) {
605 0           Perl_croak(aTHX_ "Missing argument(s) to 'binomial'");
606             }
607 120 50         if (((prob = SvNV(ST(idx))) < 0.0 || prob > 1.0) ||
    50          
    50          
    50          
608 60 50         ((trials = SvIV(ST(idx+1))) < 0))
609             {
610 0           Perl_croak(aTHX_ "Invalid argument(s) to 'binomial'");
611             }
612              
613             /* If probability > .5, then calculate based on non-occurance */
614 60 100         p = (prob <= 0.5) ? prob : 1.0-prob;
615              
616 60 100         if (trials < 25) {
617             /* Direct method */
618 20           RETVAL = 0;
619 320 100         for (ii=1; ii <= trials; ii++) {
620 300 100         if (_rand(prng) < p) {
621 141           RETVAL++;
622             }
623             }
624              
625             } else {
626 40 100         if ((mean = p * trials) < 1.0) {
627             /* Use direct Poisson method */
628 20           bound = 1.0;
629 20           limit = exp(-mean);
630 43 50         for (RETVAL=0; RETVAL < trials; RETVAL++) {
631 23           bound *= _rand(prng);
632 23 100         if (bound < limit) {
633 20           break;
634             }
635             }
636              
637             } else {
638             /* Rejection method */
639             /* See 'Numerical Recipes in C', Chapter 7.3 */
640 20           en = (NV)trials;
641 20           pc = 1.0 - p;
642 20           sq = sqrt(2.0 * mean * pc);
643              
644 20 100         if (trials != prng->binomial.trials) {
645 2           prng->binomial.trials = trials;
646 2           prng->binomial.term = _ln_gamma(en + 1.0);
647             }
648 20 100         if (p != prng->binomial.prob) {
649 2           prng->binomial.prob = p;
650 2           prng->binomial.plog = log(p);
651 2           prng->binomial.pclog = log(pc);
652             }
653              
654             do {
655             do {
656 68           tang = _tan(prng);
657 68           em = (sq * tang) + mean;
658 68 100         } while (em < 0.0 || em >= (en+1.0));
    100          
659 56           em = floor(em);
660 112           bound = 1.2 * sq * (1.0 + tang*tang) *
661 168           exp(prng->binomial.term -
662 56           _ln_gamma(em + 1.0) -
663 56           _ln_gamma(en - em + 1.0) +
664 56           em * prng->binomial.plog +
665 56           (en - em) * prng->binomial.pclog);
666 56 100         } while (_rand(prng) > bound);
667 20           RETVAL = (IV)em;
668             }
669             }
670              
671             /* Adjust results for occurance vs. non-occurance */
672 60 100         if (p < prob) {
673 20           RETVAL = trials - RETVAL;
674             }
675              
676             OUTPUT:
677             RETVAL
678              
679              
680              
681             # The functions below are for internal use by the Math::Random::MT::Auto
682             # package.
683              
684             MODULE = Math::Random::MT::Auto PACKAGE = Math::Random::MT::Auto::_
685              
686              
687             # new_prng
688             #
689             # Creates a new PRNG context for the OO Interface, and returns a pointer to it.
690              
691             SV *
692             new_prng(...)
693             PREINIT:
694             struct mt *prng;
695             CODE:
696 34           Newxz(prng, 1, struct mt);
697             /* Initializes with minimal data to ensure it's 'safe' */
698 34           prng->state[0] = HI_BIT;
699 34           prng->left = 1;
700 34           prng->poisson.mean = -1;
701 34           prng->binomial.trials = -1;
702 34           prng->binomial.prob = -1.0;
703 34           RETVAL = newSVuv(PTR2UV(prng));
704             OUTPUT:
705             RETVAL
706              
707              
708             # free_prng
709             #
710             # Frees the PRNG context as part of object destruction.
711              
712             void
713             free_prng(...)
714             PREINIT:
715             PRNG_VARS;
716             struct mt *prng;
717             CODE:
718 34           PRNG_PREP;
719 34 50         if ((prng = GET_PRNG)) {
    50          
720 34           Safefree(prng);
721             }
722              
723              
724             # seed_prng
725             #
726             # Applies a supplied seed to a specified PRNG.
727             #
728             # The specified PRNG may be either the standalone PRNG or an object's PRNG.
729              
730             void
731             seed_prng(...)
732             PREINIT:
733             PRNG_VARS;
734             struct mt *prng;
735             AV *myseed;
736             int len;
737             UV *st;
738             int ii, jj, kk;
739             CODE:
740 32           PRNG_PREP;
741 32 50         prng = GET_PRNG;
742              
743             /* Extract argument */
744 32           myseed = (AV*)SvRV(ST(1));
745              
746 32           len = av_len(myseed)+1;
747 32           st = prng->state;
748              
749             /* Initialize */
750 32           st[0]= 19650218;
751 9984 100         for (ii=1; ii
752 9952           st[ii] = (MAGIC1 * (st[ii-1] ^ (st[ii-1] >> BIT_SHIFT)) + ii);
753             }
754              
755             /* Add supplied seed */
756 32           ii=1; jj=0;
757 10016 100         for (kk = ((N>len) ? N : len); kk; kk--) {
758 29952           st[ii] = (st[ii] ^ ((st[ii-1] ^ (st[ii-1] >> BIT_SHIFT)) * MAGIC2))
759 9984 100         + SvUV(*av_fetch(myseed, jj, 0)) + jj;
760 9984 100         if (++ii >= N) { st[0] = st[N-1]; ii=1; }
761 9984 100         if (++jj >= len) jj=0;
762             }
763              
764             /* Final shuffle */
765 9984 100         for (kk=N-1; kk; kk--) {
766 9952           st[ii] = (st[ii] ^ ((st[ii-1] ^ (st[ii-1] >> BIT_SHIFT)) * MAGIC3)) - ii;
767 9952 100         if (++ii >= N) { st[0] = st[N-1]; ii=1; }
768             }
769              
770             /* Guarantee non-zero initial state */
771 32           st[0] = HI_BIT;
772              
773             /* Forces twist when first random is requested */
774 32           prng->left = 1;
775              
776              
777             # get_state
778             #
779             # Returns an array ref containing the state vector and internal data for a
780             # specified PRNG.
781             #
782             # The specified PRNG may be either the standalone PRNG or an object's PRNG.
783              
784             SV *
785             get_state(...)
786             PREINIT:
787             PRNG_VARS;
788             struct mt *prng;
789             AV *state;
790             int ii;
791             CODE:
792 9           PRNG_PREP;
793 9 50         prng = GET_PRNG;
794              
795             /* Create state array */
796 9           state = newAV();
797 9           av_extend(state, N+12);
798              
799             /* Add internal PRNG state to array */
800 2817 100         for (ii=0; ii
801 2808           av_push(state, newSVuv(prng->state[ii]));
802             }
803 9           av_push(state, newSViv(prng->left));
804              
805             /* Add non-uniform deviate function data to array */
806 9           av_push(state, newSViv(prng->gaussian.have));
807 9           av_push(state, newSVnv(prng->gaussian.value));
808 9           av_push(state, newSVnv(prng->poisson.mean));
809 9           av_push(state, newSVnv(prng->poisson.log_mean));
810 9           av_push(state, newSVnv(prng->poisson.sqrt2mean));
811 9           av_push(state, newSVnv(prng->poisson.term));
812 9           av_push(state, newSViv(prng->binomial.trials));
813 9           av_push(state, newSVnv(prng->binomial.term));
814 9           av_push(state, newSVnv(prng->binomial.prob));
815 9           av_push(state, newSVnv(prng->binomial.plog));
816 9           av_push(state, newSVnv(prng->binomial.pclog));
817              
818 9           RETVAL = newRV_noinc((SV *)state);
819             OUTPUT:
820             RETVAL
821              
822              
823             # set_state
824             #
825             # Sets the specified PRNG's state vector and internal data from a supplied
826             # array ref.
827             #
828             # The specified PRNG may be either the standalone PRNG or an object's PRNG.
829              
830             void
831             set_state(...)
832             PREINIT:
833             PRNG_VARS;
834             struct mt *prng;
835             AV *state;
836             int ii;
837             CODE:
838 8           PRNG_PREP;
839 8 50         prng = GET_PRNG;
840              
841             /* Extract argument */
842 8           state = (AV*)SvRV(ST(1));
843              
844             /* Validate size of argument */
845 8 50         if (av_len(state) != N+11) {
846 0           Perl_croak(aTHX_ "Invalid state vector");
847             }
848              
849             /* Extract internal PRNG state from array */
850 2504 100         for (ii=0; ii
851 2496 100         prng->state[ii] = SvUV(*av_fetch(state, ii, 0));
852             }
853 8 50         prng->left = SvIV(*av_fetch(state, ii, 0)); ii++;
854 8 100         if (prng->left > 1) {
855 4           prng->next = &prng->state[(N+1) - prng->left];
856             }
857              
858             /* Extract non-uniform deviate function data from array */
859 8 50         prng->gaussian.have = SvIV(*av_fetch(state, ii, 0)); ii++;
860 8 100         prng->gaussian.value = SvNV(*av_fetch(state, ii, 0)); ii++;
861 8 100         prng->poisson.mean = SvNV(*av_fetch(state, ii, 0)); ii++;
862 8 100         prng->poisson.log_mean = SvNV(*av_fetch(state, ii, 0)); ii++;
863 8 100         prng->poisson.sqrt2mean = SvNV(*av_fetch(state, ii, 0)); ii++;
864 8 100         prng->poisson.term = SvNV(*av_fetch(state, ii, 0)); ii++;
865 8 50         prng->binomial.trials = SvIV(*av_fetch(state, ii, 0)); ii++;
866 8 100         prng->binomial.term = SvNV(*av_fetch(state, ii, 0)); ii++;
867 8 100         prng->binomial.prob = SvNV(*av_fetch(state, ii, 0)); ii++;
868 8 100         prng->binomial.plog = SvNV(*av_fetch(state, ii, 0)); ii++;
869 8 100         prng->binomial.pclog = SvNV(*av_fetch(state, ii, 0));
870              
871             /* EOF */