File Coverage

blib/lib/Math/Random/ISAAC/PP.pm
Criterion Covered Total %
statement 176 178 98.8
branch 2 2 100.0
condition n/a
subroutine 10 11 90.9
pod 3 3 100.0
total 191 194 98.4


line stmt bran cond sub pod time code
1             package Math::Random::ISAAC::PP;
2             BEGIN {
3 4     4   171235 $Math::Random::ISAAC::PP::VERSION = '1.004';
4             }
5             # ABSTRACT: Pure Perl port of the ISAAC PRNG algorithm
6              
7 4     4   41 use strict;
  4         10  
  4         127  
8 4     4   21 use warnings;
  4         8  
  4         121  
9 4     4   33 use Carp ();
  4         9  
  4         2008  
10              
11              
12             sub new {
13 1     1 1 225 my ($class, @seed) = @_;
14              
15 1         2 my $seedsize = scalar(@seed);
16              
17 1         2 my @mm;
18 1         7 $#mm = $#seed = 255; # predeclare arrays with 256 slots
19              
20             # Zero-fill our seed data
21 1         4 for ($seedsize .. 255) {
22 256         292 $seed[$_] = 0;
23             }
24              
25 1         8 my $self = {
26             randrsl => \@seed,
27             randcnt => 0,
28             randmem => \@mm,
29              
30             randa => 0,
31             randb => 0,
32             randc => 0,
33             };
34              
35 1         3 bless($self, $class);
36              
37 1         5 $self->_randinit();
38              
39 1         5 return $self;
40             }
41              
42              
43             # This package should have an interface similar to the builtin Perl
44             # random number routines; these are methods, not functions, so they
45             # are not problematic
46             ## no critic (ProhibitBuiltinHomonyms)
47              
48             sub rand {
49 0     0 1 0 my ($self) = @_;
50              
51 0         0 return ($self->irand() / (2**32-1));
52             }
53              
54              
55             sub irand {
56 600     600 1 496171 my ($self) = @_;
57              
58             # Reset the sequence if we run out of random stuff
59 600 100       1836 if (!$self->{randcnt}--)
60             {
61             # Call method like this because of our hack above
62 2         7 _isaac($self);
63 2         7 $self->{randcnt} = 255;
64             }
65              
66 600         4709 return sprintf('%u', $self->{randrsl}->[$self->{randcnt}]);
67             }
68              
69             # C-style for loops are used a lot since this is a port of the C version
70             ## no critic (ProhibitCStyleForLoops)
71              
72             # Numbers are specified in hex, so they don't need separators
73             ## no critic (RequireNumberSeparators)
74              
75             sub _isaac {
76 3     3   8 my ($self) = @_;
77              
78             # Use integer math
79 4     4   4446 use integer;
  4         46  
  4         21  
80              
81 3         9 my $mm = $self->{randmem};
82 3         7 my $r = $self->{randrsl};
83              
84             # $a and $b are reserved (see 'sort')
85 3         9 my $aa = $self->{randa};
86 3         49 my $bb = ($self->{randb} + (++$self->{randc})) & 0xffffffff;
87              
88 3         7 my ($x, $y); # temporary storage
89              
90             # The C code deals with two halves of the randmem separately; we deal with
91             # it here in one loop, by adding the &0xff parts. These calls represent the
92             # rngstep() macro, but it's inlined here for speed.
93 3         15 for (my $i = 0; $i < 256; $i += 4)
94             {
95 192         234 $x = $mm->[$i ];
96 192         256 $aa = (($aa ^ ($aa << 13)) + $mm->[($i + 128) & 0xff]);
97 192         201 $aa &= 0xffffffff; # Mask out high bits for 64-bit systems
98 192         304 $mm->[$i ] = $y = ($mm->[($x >> 2) & 0xff] + $aa + $bb) & 0xffffffff;
99 192         284 $r->[$i ] = $bb = ($mm->[($y >> 10) & 0xff] + $x) & 0xffffffff;
100              
101             # I don't actually know why the "0x03ffffff" stuff is for. It was in
102             # John L. Allen's code. If you can explain this please file a bug report.
103 192         231 $x = $mm->[$i+1];
104 192         293 $aa = (($aa ^ (0x03ffffff & ($aa >> 6))) + $mm->[($i+1+128) & 0xff]);
105 192         188 $aa &= 0xffffffff;
106 192         310 $mm->[$i+1] = $y = ($mm->[($x >> 2) & 0xff] + $aa + $bb) & 0xffffffff;
107 192         288 $r->[$i+1] = $bb = ($mm->[($y >> 10) & 0xff] + $x) & 0xffffffff;
108              
109 192         209 $x = $mm->[$i+2];
110 192         273 $aa = (($aa ^ ($aa << 2)) + $mm->[($i+2 + 128) & 0xff]);
111 192         190 $aa &= 0xffffffff;
112 192         368 $mm->[$i+2] = $y = ($mm->[($x >> 2) & 0xff] + $aa + $bb) & 0xffffffff;
113 192         281 $r->[$i+2] = $bb = ($mm->[($y >> 10) & 0xff] + $x) & 0xffffffff;
114              
115 192         8688 $x = $mm->[$i+3];
116 192         306 $aa = (($aa ^ (0x0000ffff & ($aa >> 16))) + $mm->[($i+3 + 128) & 0xff]);
117 192         172 $aa &= 0xffffffff;
118 192         306 $mm->[$i+3] = $y = ($mm->[($x >> 2) & 0xff] + $aa + $bb) & 0xffffffff;
119 192         1013 $r->[$i+3] = $bb = ($mm->[($y >> 10) & 0xff] + $x) & 0xffffffff;
120             }
121              
122 3         11 $self->{randb} = $bb;
123 3         5 $self->{randa} = $aa;
124              
125 3         7 return;
126             }
127              
128             sub _randinit
129             {
130 1     1   2 my ($self) = @_;
131              
132 4     4   1676 use integer;
  4         10  
  4         15  
133              
134             # $a and $b are reserved (see 'sort'); $i is the iterator
135 1         2 my ($c, $d, $e, $f, $g, $h, $j, $k);
136 1         3 $c=$d=$e=$f=$g=$h=$j=$k = 0x9e3779b9; # The golden ratio
137              
138 1         6 my $mm = $self->{randmem};
139 1         3 my $r = $self->{randrsl};
140              
141 1         4 for (1..4)
142             {
143 4         6 $c ^= $d << 11;
144 4         4 $f += $c;
145 4         5 $d += $e;
146              
147 4         6 $d ^= 0x3fffffff & ($e >> 2);
148 4         8 $g += $d;
149 4         4 $e += $f;
150              
151 4         5 $e ^= $f << 8;
152 4         5 $h += $e;
153 4         4 $f += $g;
154              
155 4         6 $f ^= 0x0000ffff & ($g >> 16);
156 4         5 $j += $f;
157 4         3 $g += $h;
158              
159 4         5 $g ^= $h << 10;
160 4         5 $k += $g;
161 4         5 $h += $j;
162              
163 4         5 $h ^= 0x0fffffff & ($j >> 4);
164 4         5 $c += $h;
165 4         4 $j += $k;
166              
167 4         5 $j ^= $k << 8;
168 4         5 $d += $j;
169 4         5 $k += $c;
170              
171 4         5 $k ^= 0x007fffff & ($c >> 9);
172 4         4 $e += $k;
173 4         7 $c += $d;
174             }
175              
176 1         6 for (my $i = 0; $i < 256; $i += 8)
177             {
178 32         35 $c += $r->[$i ];
179 32         34 $d += $r->[$i+1];
180 32         47 $e += $r->[$i+2];
181 32         37 $f += $r->[$i+3];
182 32         33 $g += $r->[$i+4];
183 32         34 $h += $r->[$i+5];
184 32         33 $j += $r->[$i+6];
185 32         32 $k += $r->[$i+7];
186              
187 32         30 $c ^= $d << 11;
188 32         30 $f += $c;
189 32         27 $d += $e;
190              
191 32         33 $d ^= 0x3fffffff & ($e >> 2);
192 32         32 $g += $d;
193 32         35 $e += $f;
194              
195 32         30 $e ^= $f << 8;
196 32         28 $h += $e;
197 32         31 $f += $g;
198              
199 32         32 $f ^= 0x0000ffff & ($g >> 16);
200 32         27 $j += $f;
201 32         29 $g += $h;
202              
203 32         31 $g ^= $h << 10;
204 32         30 $k += $g;
205 32         31 $h += $j;
206              
207 32         31 $h ^= 0x0fffffff & ($j >> 4);
208 32         33 $c += $h;
209 32         26 $j += $k;
210              
211 32         33 $j ^= $k << 8;
212 32         30 $d += $j;
213 32         27 $k += $c;
214              
215 32         33 $k ^= 0x007fffff & ($c >> 9);
216 32         27 $e += $k;
217 32         25 $c += $d;
218              
219 32         41 $mm->[$i ] = $c;
220 32         36 $mm->[$i+1] = $d;
221 32         35 $mm->[$i+2] = $e;
222 32         34 $mm->[$i+3] = $f;
223 32         33 $mm->[$i+4] = $g;
224 32         55 $mm->[$i+5] = $h;
225 32         39 $mm->[$i+6] = $j;
226 32         82 $mm->[$i+7] = $k;
227             }
228              
229 1         4 for (my $i = 0; $i < 256; $i += 8)
230             {
231 32         34 $c += $mm->[$i ];
232 32         31 $d += $mm->[$i+1];
233 32         31 $e += $mm->[$i+2];
234 32         32 $f += $mm->[$i+3];
235 32         33 $g += $mm->[$i+4];
236 32         27 $h += $mm->[$i+5];
237 32         33 $j += $mm->[$i+6];
238 32         32 $k += $mm->[$i+7];
239              
240 32         31 $c ^= $d << 11;
241 32         30 $f += $c;
242 32         26 $d += $e;
243              
244 32         30 $d ^= 0x3fffffff & ($e >> 2);
245 32         30 $g += $d;
246 32         25 $e += $f;
247              
248 32         26 $e ^= $f << 8;
249 32         27 $h += $e;
250 32         28 $f += $g;
251              
252 32         31 $f ^= 0x0000ffff & ($g >> 16);
253 32         490 $j += $f;
254 32         32 $g += $h;
255              
256 32         32 $g ^= $h << 10;
257 32         24 $k += $g;
258 32         28 $h += $j;
259              
260 32         32 $h ^= 0x0fffffff & ($j >> 4);
261 32         28 $c += $h;
262 32         27 $j += $k;
263              
264 32         32 $j ^= $k << 8;
265 32         25 $d += $j;
266 32         28 $k += $c;
267              
268 32         33 $k ^= 0x007fffff & ($c >> 9);
269 32         26 $e += $k;
270 32         30 $c += $d;
271              
272 32         34 $mm->[$i ] = $c;
273 32         31 $mm->[$i+1] = $d;
274 32         33 $mm->[$i+2] = $e;
275 32         32 $mm->[$i+3] = $f;
276 32         32 $mm->[$i+4] = $g;
277 32         32 $mm->[$i+5] = $h;
278 32         31 $mm->[$i+6] = $j;
279 32         73 $mm->[$i+7] = $k;
280             }
281              
282 1         5 $self->_isaac();
283 1         2 $self->{randcnt} = 256;
284              
285 1         3 return;
286             }
287              
288              
289             1;
290              
291             __END__