File Coverage

Xoshiro256.xs
Criterion Covered Total %
statement 41 64 64.0
branch 7 12 58.3
condition n/a
subroutine n/a
pod n/a
total 48 76 63.1


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4             #include
5              
6             /* xoshiro256+ core */
7 40066           static inline uint64_t rotl(const uint64_t x, int k) {
8 40066           return (x << k) | (x >> (64 - k));
9             }
10              
11             /* OOP interface: define a struct to hold state for each object */
12             typedef struct {
13             uint64_t s[4];
14             } xoshiro256_state;
15              
16             #define SvXoshiro256State(sv) ((xoshiro256_state*)SvIV(SvRV(sv)))
17              
18             /* Remove the static s[4] global */
19              
20             /* Make core routines instance methods */
21 0           static uint64_t next_xoshiro256plus(xoshiro256_state *st) {
22 0           const uint64_t result = st->s[0] + st->s[3];
23 0           const uint64_t t = st->s[1] << 17;
24 0           st->s[2] ^= st->s[0];
25 0           st->s[3] ^= st->s[1];
26 0           st->s[1] ^= st->s[2];
27 0           st->s[0] ^= st->s[3];
28 0           st->s[2] ^= t;
29 0           st->s[3] = rotl(st->s[3], 45);
30 0           return result;
31             }
32              
33             // https://prng.di.unimi.it/xoshiro256starstar.c
34 20033           static uint64_t next_xoshiro256starstar(xoshiro256_state *st) {
35 20033           const uint64_t result = rotl(st->s[1] * 5, 7) * 9;
36              
37 20033           const uint64_t t = st->s[1] << 17;
38              
39 20033           st->s[2] ^= st->s[0];
40 20033           st->s[3] ^= st->s[1];
41 20033           st->s[1] ^= st->s[2];
42 20033           st->s[0] ^= st->s[3];
43              
44 20033           st->s[2] ^= t;
45              
46 20033           st->s[3] = rotl(st->s[3], 45);
47              
48 20033           return result;
49             }
50              
51             /* splitmix64 for seeding */
52 0           static uint64_t splitmix64(uint64_t *state) {
53 0           uint64_t z = (*state += 0x9E3779B97F4A7C15ULL);
54 0           z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ULL;
55 0           z = (z ^ (z >> 27)) * 0x94D049BB133111EBULL;
56 0           return z ^ (z >> 31);
57             }
58              
59             /* ========================================================================== */
60             /* ========================================================================== */
61              
62             MODULE = Math::Random::Xoshiro256 PACKAGE = Math::Random::Xoshiro256
63              
64             SV* _xs_new(class)
65             const char* class;
66             CODE:
67             {
68 1           xoshiro256_state *st = malloc(sizeof(xoshiro256_state));
69 1 50         if (!st) croak("Allocation failed");
70             /* Default: zero-init; must seed before use */
71 1           st->s[0]=st->s[1]=st->s[2]=st->s[3]=0ULL;
72 1           SV* obj_ref = newSViv(0);
73 1           SV* obj = newSVrv(obj_ref, class);
74 1           sv_setiv(obj, (IV)st);
75 1           SvREADONLY_on(obj);
76 1           RETVAL = obj_ref;
77             }
78             OUTPUT: RETVAL
79              
80             void DESTROY(self)
81             SV* self;
82             CODE:
83             {
84 1           xoshiro256_state *st = SvXoshiro256State(self);
85 1           free(st);
86             }
87              
88             void seed(self, seed)
89             SV* self;
90             UV seed;
91             CODE:
92             {
93 0           xoshiro256_state *st = SvXoshiro256State(self);
94 0           uint64_t s = (uint64_t)seed;
95 0           st->s[0] = splitmix64(&s);
96 0           st->s[1] = splitmix64(&s);
97 0           st->s[2] = splitmix64(&s);
98 0           st->s[3] = splitmix64(&s);
99             }
100              
101             void seed4(self, seed1, seed2, seed3, seed4)
102             SV* self;
103             UV seed1;
104             UV seed2;
105             UV seed3;
106             UV seed4;
107             CODE:
108             {
109 1           xoshiro256_state *st = SvXoshiro256State(self);
110 1           st->s[0] = seed1;
111 1           st->s[1] = seed2;
112 1           st->s[2] = seed3;
113 1           st->s[3] = seed4;
114             }
115              
116             UV rand64(self)
117             SV* self;
118             CODE:
119             {
120 10004           xoshiro256_state *st = SvXoshiro256State(self);
121 10004           RETVAL = (UV) next_xoshiro256starstar(st);
122             }
123             OUTPUT: RETVAL
124              
125             double __next_double(self)
126             SV* self;
127             CODE:
128             {
129 1           xoshiro256_state *st = SvXoshiro256State(self);
130 1           uint64_t v = next_xoshiro256starstar(st);
131 1           uint64_t top53 = v >> 11; /* keep top 53 bits */
132 1 50         RETVAL = (double) top53 * (1.0 / 9007199254740992.0); /* 2^53 */
133             }
134             OUTPUT: RETVAL
135              
136             IV random_int(self, min, max)
137             SV* self;
138             IV min;
139             IV max;
140             CODE:
141             {
142 10028           xoshiro256_state *st = SvXoshiro256State(self);
143              
144 10028 50         if (min > max) {
145 0           croak("random_int: min must be <= max");
146             }
147              
148 10028           uint64_t range = (max - min) + 1;
149              
150 10028 50         if (range == 0) {
151 0           croak("random_int: Invalid arguments (range overflow or zero)");
152             }
153              
154 10028           uint64_t threshold = (-range) % range;
155             uint64_t v;
156             do {
157 10028           v = next_xoshiro256starstar(st);
158 10028 50         } while (v < threshold);
159              
160 10028 100         RETVAL = (IV)((int64_t)min + (int64_t)(v % range));
161             }
162             OUTPUT: RETVAL