File Coverage

blib/lib/Math/BigInt/Random/OO.pm
Criterion Covered Total %
statement 122 126 96.8
branch 46 72 63.8
condition 2 6 33.3
subroutine 9 9 100.0
pod 2 2 100.0
total 181 215 84.1


line stmt bran cond sub pod time code
1             # -*- mode: perl; coding: utf-8-unix; -*-
2             #
3             # Author: Peter J. Acklam
4             # Time-stamp: 2010-02-23 21:20:43 +01:00
5             # E-mail: pjacklam@online.no
6             # URL: http://home.online.no/~pjacklam
7              
8             package Math::BigInt::Random::OO;
9              
10             ###############################################################################
11             ## Modules and general package variables.
12             ###############################################################################
13              
14 4     4   68613 use 5.008; # required version of Perl
  4         15  
  4         160  
15 4     4   20 use strict; # restrict unsafe constructs
  4         8  
  4         130  
16 4     4   20 use warnings; # control optional warnings
  4         7  
  4         103  
17 4     4   18 use utf8; # enable UTF-8 in source code
  4         5  
  4         20  
18              
19             # Modules from the Standard Perl Library.
20              
21 4     4   90 use Config;
  4         14  
  4         178  
22 4     4   22 use Carp;
  4         5  
  4         426  
23 4     4   6548 use Math::BigInt;
  4         127391  
  4         28  
24             #use Data::Dumper;
25              
26             ###############################################################################
27             # Package variables.
28             ###############################################################################
29              
30             our $VERSION = 0.03;
31              
32             =pod
33              
34             =encoding utf8
35              
36             =head1 NAME
37              
38             Math::BigInt::Random::OO - generate uniformly distributed Math::BigInt objects
39              
40             =head1 SYNOPSIS
41              
42             use Math::BigInt::Random::OO;
43              
44             # Random numbers between 1e20 and 2e30:
45              
46             my $gen = Math::BigInt::Random::OO -> new(min => "1e20",
47             min => "2e30");
48             $x = $gen -> generate(); # one number
49             $x = $gen -> generate(1); # ditto
50             @x = $gen -> generate(100); # 100 numbers
51              
52             # Random numbers with size fitting 20 hexadecimal digits:
53              
54             my $gen = Math::BigInt::Random::OO -> new(length => 20,
55             base => 16);
56             @x = $gen -> generate(100);
57              
58             =head1 ABSTRACT
59              
60             Math::BigInt::Random::OO is a module for generating arbitrarily large random
61             integers from a discrete, uniform distribution. The numbers are returned as
62             Math::BigInt objects.
63              
64             =head1 DESCRIPTION
65              
66             Math::BigInt::Random::OO is a module for generating arbitrarily large random
67             integers from a discrete, uniform distribution. The numbers are returned as
68             Math::BigInt objects.
69              
70             =head1 CONSTRUCTORS
71              
72             =over 4
73              
74             =item CLASS -E new ( ... )
75              
76             Returns a new C random number generator object. The
77             arguments are given in the "hash style", as shown in the following example
78             which constructs a generator for random numbers in the range from -2 to 3,
79             inclusive.
80              
81             my $gen = Math::BigInt::Random::OO -> new(min => -2,
82             max => 3);
83              
84             The following parameters are recognized.
85              
86             =over 4
87              
88             =item min =E NUM
89              
90             Specifies the minimum possible output value, i.e., the lower bound. If `max' is
91             given, but `min' is not, then `min' is set to zero.
92              
93             =item max =E NUM
94              
95             Specifies the maximum possible output value, i.e., the upper bound. If `max' is
96             given, but `min' is not, then `max' must be non-negative.
97              
98             =item length =E NUM
99              
100             Specifies the length of the output value, i.e., the number of digits. Use this
101             option to ensure that all random numbers have the same number of digits. If the
102             base is not given explicitly with the `base' option, then a base of 10 is used.
103             The following two constructors are equivalent
104              
105             Math::BigInt::Random::OO -> new(length => $n, base => $b);
106              
107             $min = Math::BigInt -> new($b) -> bpow($n - 1);
108             $max = Math::BigInt -> new($b) -> bpow($n) -> bsub(1));
109             Math::BigInt::Random::OO -> new(min => $min, max => $max);
110              
111             For instance, if the length is 4 and the base is 10, the random numbers will be
112             in the range from 1000 to 9999, inclusive. If the length is 3 and the base is
113             16, the random numbers will be in the range from 256 to 4095, which is 100 to
114             fff hexadecimal.
115              
116             This option is ignored if the `max' option is present.
117              
118             =item base =E NUM
119              
120             Sets the base to be used with the `length' option. See also the description for
121             the `length' option.
122              
123             =item length_bin =E NUM
124              
125             This option is only for compatibility with Math::BigInt::Random. The following
126             two cases are equivalent
127              
128             $cls -> new(length_bin => $n);
129             $cls -> new(length => $n, base => 2);
130              
131             =item length_hex =E NUM
132              
133             This option is only for compatibility with Math::BigInt::Random. The following
134             two cases are equivalent
135              
136             $cls -> new(length_hex => $n);
137             $cls -> new(length => $n, base => 16);
138              
139             =back
140              
141             =cut
142              
143             sub new {
144 230     230 1 23607228 my $proto = shift;
145 230         481 my $protoref = ref $proto;
146 230   33     1244 my $class = $protoref || $proto;
147 230         318 my $name = 'new';
148              
149             # Check how the method is called.
150              
151 230 50       483 croak "$name() is a class method, not an instance/object method"
152             if $protoref;
153              
154             # Check the number of input arguments.
155              
156 230 50       610 croak "$name(): not enough input arguments" if @_ < 1;
157 230 50       642 croak "$name(): odd number of input arguments" if @_ % 2;
158              
159             # Check the context.
160              
161 230 50       532 carp "$name(): useless use of method in void context"
162             unless defined wantarray;
163              
164             # Initialize the new object.
165              
166 230         1124 my $self = {
167             min => undef,
168             max => undef,
169             length => undef,
170             base => 10,
171             };
172              
173             # Get the input arguments.
174              
175 230         599 while (@_) {
176 458         645 my $key = shift;
177 458         610 my $val = shift;
178              
179 458 50       873 croak "$name(): parameter can't be undefined"
180             unless defined $key;
181              
182             # The minimum value, i.e., lower bound.
183              
184 458 100       961 if ($key eq 'min') {
185 157 50       290 croak "$name(): minimum value can't be undefined"
186             unless defined $val;
187 157 100       867 $val = Math::BigInt -> new($val)
188             unless UNIVERSAL::isa($val, 'Math::BigInt');
189 157 50       5048 croak "$name(): minimum is not a valid number"
190             if $val -> is_nan();
191 157         1253 $self -> {min} = $val -> as_int();
192 157         4823 next;
193             }
194              
195             # The maximum value, i.e., upper bound.
196              
197 301 100       697 if ($key eq 'max') {
198 157 50       296 croak "$name(): maximum value can't be undefined"
199             unless defined $val;
200 157 100       743 $val = Math::BigInt -> new($val)
201             unless UNIVERSAL::isa($val, 'Math::BigInt');
202 157 50       4312 croak "$name(): maximum is not a valid number"
203             if $val -> is_nan();
204 157         1102 $self -> {max} = $val -> as_int();
205 157         4430 next;
206             }
207              
208             # The length for the given base.
209              
210 144 100       383 if ($key eq 'length') {
211 71 50       170 croak "$name(): length value can't be undefined"
212             unless defined $val;
213 71 50       159 croak "$name(): length value must be positive"
214             unless $val > 0;
215 71         189 $self -> {length} = $val;
216 71         150 $self -> {base} = 10;
217 71         184 next;
218             }
219              
220             # The base used when computing the length.
221              
222 73 100       193 if ($key eq 'base') {
223 71 50       182 croak "$name(): base value can't be undefined"
224             unless defined $val;
225 71 50       148 croak "$name(): base value must be positive"
226             unless $val > 0;
227 71         169 $self -> {base} = $val;
228 71         223 next;
229             }
230              
231             # The length with an implicit base 16.
232              
233 2 100       6 if ($key eq 'length_hex') {
234 1 50       4 croak "$name(): length_hex value can't be undefined"
235             unless defined $val;
236 1 50       3 croak "$name(): length_hex value must be positive"
237             unless $val > 0;
238 1         2 $self -> {length} = $val;
239 1         2 $self -> {base} = 16;
240 1         3 next;
241             }
242              
243             # The length with an implicit base 2.
244              
245 1 50       4 if ($key eq 'length_bin') {
246 1 50       4 croak "$name(): length_bin value can't be undefined"
247             unless defined $val;
248 1 50       4 croak "$name(): length_bin value must be positive"
249             unless $val > 0;
250 1         2 $self -> {length} = $val;
251 1         2 $self -> {base} = 2;
252 1         4 next;
253             }
254              
255 0         0 croak "$name(): unknown parameter -- $key\n";
256             }
257              
258             # If the maximum value is given, use that. If the length is given, compute
259             # the minimum and maximum values for the given length and base. For
260             # instance, if the base is 10 and the length is 3, the minimum value is
261             # 100, and the maximum is 999. If the base is 2 and the length is 5, the
262             # minimum value is 10000 binary (= 16 decimal) and the maximum is 11111
263             # binary (= 31 decimal).
264              
265 230 100       584 if (defined $self->{max}) {
266              
267 157 50       305 if (defined $self->{length}) {
268 0         0 carp "$name(): 'max' is given, so 'length' is ignored";
269             }
270 157 50       290 if (! defined $self->{min}) {
271 0         0 $self->{min} = 0,
272             }
273              
274 157 50       534 croak "$name(): maximum can't be smaller than minimum"
275             if $self->{max} < $self->{min};
276              
277             } else {
278              
279 73 50       208 if (defined $self->{length}) {
280 73         3597 my $base = $self -> {base};
281 73         136 my $len = $self -> {length};
282 73         343 $self->{min} = Math::BigInt -> new($base) -> bpow($len - 1);
283 73         24529 $self->{max} = $self->{min} -> copy() -> bmul($base) -> bsub(1);
284             } else {
285 0         0 croak "$name(): either 'max' or 'length' must be given\n";
286             }
287              
288             }
289              
290             # The value of $rand_mult * CORE::rand() is a random integer X in the range
291             # 0 <= X < 2 ** $rand_bits.
292              
293 230         26635 my $range = $self->{max} - $self->{min};
294 230         23777 my $rand_bits = $Config{randbits};
295 230         10674 my $rand_mult = 2 ** $rand_bits; # multiplier
296              
297             # How many chunks, each of size $rand_bits bits, do we need? And what is
298             # the size of the highest chunk.
299              
300 230         346 my $chunks = 1;
301 230         591 my $hi_range = $range -> copy();
302 230         3541 while ($hi_range >= $rand_mult) {
303 172         16614 $hi_range /= $rand_mult;
304 172         41094 ++ $chunks;
305             }
306              
307             # How many bits in the highest (top) chunk?
308              
309 230         21641 my $hi_bits = 0;
310 230         610 my $tmp = $hi_range -> copy();
311 230         3539 while ($tmp > 0) {
312 2237         264159 $tmp /= 2;
313 2237         265997 ++ $hi_bits;
314             }
315              
316             # Save these, since they are needed to generate the random numbers.
317              
318 230         24586 $self->{_chunks} = $chunks;
319 230         408 $self->{_range} = $range;
320 230         697 $self->{_range_high} = $hi_range -> numify();
321 230         3914 $self->{_rand_mult} = $rand_mult;
322 230         468 $self->{_rand_mult_high} = 2 ** $hi_bits;
323              
324             ###########################################################################
325              
326             # Bless the reference into an object and return it.
327              
328 230         1602 bless $self, $class;
329             }
330              
331             =pod
332              
333             =item OBJECT -E generate ( COUNT )
334              
335             =item OBJECT -E generate ( )
336              
337             Generates the given number of random numbers, or one number, if no input
338             argument is given.
339              
340             # Generate ten random numbers:
341              
342             my @num = $gen -> generate(10);
343              
344             =cut
345              
346             sub generate {
347 226     226 1 1192 my $self = shift;
348 226         393 my $selfref = ref $self;
349 226   33     501 my $class = $selfref || $self;
350 226         331 my $name = 'generate';
351              
352             # Check how the method is called.
353              
354 226 50       422 croak "$name() is an object instance method, not a class method"
355             unless $selfref;
356              
357             # Check number of input arguments.
358              
359             #croak "$name(): not enough input arguments" if @_ < 1;
360 226 50       595 croak "$name(): too many input arguments" if @_ > 1;
361              
362             # Get the count;
363              
364 226         286 my $count = 1;
365 226 100       464 if (@_) {
366 187         494 $count = shift;
367 187 50       357 croak "$name(): input argument must be defined"
368             unless defined $count;
369 187 50       380 croak "$name(): input argument must be an integer"
370             unless $count = int $count;
371             }
372              
373             # Generate the random numbers.
374              
375 226         283 my @num;
376              
377 226         413 for (1 .. $count) {
378 2058         2355 my $num;
379              
380 2058         2376 do {
381 2618         72664 $num = 0;
382              
383             # Generate the highest (top) digits.
384              
385 2618         5615 $num = int CORE::rand $self->{_rand_mult_high};
386              
387 2618         6888 $num = Math::BigInt -> new($num);
388              
389             # Generate the chunks of lower digits.
390              
391 2618         89464 for (2 .. $self->{_chunks}) {
392 4991         438852 $num *= $self->{_rand_mult};
393 4991         810071 $num += CORE::rand $self->{_rand_mult};
394             }
395              
396             } until $num <= $self->{_range};
397              
398 2058         183794 $num += $self->{min};
399              
400 2058         114803 push @num, $num;
401             }
402              
403 226 100       1245 return @num if wantarray;
404 104         465 return $num[0];
405             }
406              
407             =pod
408              
409             =back
410              
411             =head1 TODO
412              
413             =over 4
414              
415             =item *
416              
417             Add a way to change the core uniform random number generator. Currently,
418             CORE::rand() is used, but it would be nice to be able to switch to, e.g.,
419             Math::Random::random_uniform_integer().
420              
421             =item *
422              
423             Add functionality similar to the `use_internet' parameter argument in
424             Math::BigInt::Rando::random_bigint(). This could be implemented using, e.g.,
425             Net::Random.
426              
427             =item *
428              
429             Add more tests.
430              
431             =back
432              
433             =head1 NOTES
434              
435             To fully understand how Math::BigInt::Random::OO works, one must understand how
436             Perl's CORE::rand() works.
437              
438             =head2 Details on CORE::rand()
439              
440             CORE::rand() is Perl's own function for generating uniformly distributed
441             pseudo-random integers. The core of CORE::rand() is an internal function, let's
442             call it RAND(), which generates uniformly distributed pseudo-random integers
443             greater than or equal to 0 and less 2**I. CORE::rand() is implemented
444             equivalently to
445              
446             K * RAND()
447             CORE::rand(K) = ---------------
448             2 ** RANDBITS
449              
450             One may think of the output of RAND() as a integer consisting of I
451             bits, where each bit is 0 or 1 with a 50% chance of each. To get a random
452             integer with all I bits, one must use
453              
454             CORE::rand(2 ** RANDBITS)
455              
456             Similarely, to get the first I bits, where I must be less than or equal
457             to I, use
458              
459             int CORE::rand(2 ** N)
460              
461             The commonly used idiom for generating a random integer in Perl,
462              
463             int CORE::rand(K)
464              
465             only returns uniformly distributed numbers when I is a power of two no lager
466             than I.
467              
468             You can see the number of I in your Perl with
469              
470             use Config;
471             print $Config{randbits};
472              
473             or on the command line with
474              
475             perl -MConfig -wle 'print $Config{randbits}'
476              
477             or, in new versions of Perl, also
478              
479             perl -V:randbits
480              
481             =head2 More on Math::BigInt::Random::OO -E generate()
482              
483             The goal is to generate a uniformly distributed random integer I greater
484             than or equal to I and less than or equal to I. The core of the
485             generate() method is an algorithm that generates a uniformly distributed
486             non-negative random integer I E 2**I, where I is the smallest
487             integer so that 2**I is larger than the range I = I - I.
488             Equivalently, I = 1 + int(log(I)/log(2)). If the generated integer I
489             is larger than I, that value is rejected and a new I is generated. This
490             is done until I is less than or equal to I. When a I is accepted, I
491             = I - I is returned.
492              
493             A uniformly distributed non-negative random integer I E 2**I is
494             generated by combining smaller uniformly distributed non-negative random
495             integer I E 2**I, where I less than or equal to I. Each
496             of the smaller random integers is generated with CORE::rand().
497              
498             Here is an example: Assume I is 15, which is not uncommon, and the
499             range is 10,000,000,000. The smallest power of two larger than 10,000,000,000
500             is 2**34 = 17,179,869,184. Since 34 is 4 + 15 + 15, a uniformly distributed
501             non-negative random integer I E 17,179,869,184 is generated by combining
502             three uniformly distributed non-negative random integers, I E 2**4,
503             I E 2**15, and I E 2**15.
504              
505             The following Perl code handles this special case, and produces a uniformly
506             distributed random integer I greater than or equal to I:
507              
508             $R = Math::BigInt->new('10_000_000_000'); # range
509              
510             do {
511             $U2 = Math::BigInt->new(int CORE::rand 2**4);
512             $U1 = Math::BigInt->new(int CORE::rand 2**15);
513             $U0 = Math::BigInt->new(int CORE::rand 2**15);
514             $U = (($U2 * 2**15) + $U1) * 2**15 + $U0;
515             } until $U <= $R;
516              
517             =head2 Problems with Math::BigInt::Random
518              
519             I wrote this module partly since Math::BigInt::Random v0.04 is buggy, and in
520             many cases slower, and partly because I prefer an object-oriented interface.
521             The bugs in Math::BigInt::Random v0.04 are
522              
523             =over 4
524              
525             =item *
526              
527             When the range (the maximum value minus the minimum value) is smaller than
528             1048575 (fffff hexadecimal), the maximum value will never be returned.
529              
530             =item *
531              
532             When Perl has been compiled with a number of I less than 20, certain
533             values will never occur.
534              
535             =item *
536              
537             When the range is not a power of two, certain values are more likely to occur
538             than others.
539              
540             =back
541              
542             The core of this two last problems is the use of int(rand(X)), which only
543             returns uniformly distributed numbers when X is a power of two no larger than
544             I.
545              
546             In addition, the function Math::BigInt::Random::random_bigint() generates only
547             one random integer at a time, and in doing so, there is some overhead. In
548             Math::BigInt::Random::OO, this overhead is placed in the new() constructor, so
549             it is done only once, independently of how many random numbers are generated by
550             the generator() method.
551              
552             =head1 CAVEATS
553              
554             =over 4
555              
556             =item *
557              
558             Some versions of Perl are compiled with the wrong number of I. This
559             module has way to detect if this is the case.
560              
561             =item *
562              
563             Some versions of CORE::rand() behave poorly. For intance, in some
564             implementations
565              
566             rand(1 << $Config{randbits}) % 2
567              
568             alternates between 0 and 1 deterministically.
569              
570             =back
571              
572             =head1 BUGS
573              
574             There are currently no known bugs.
575              
576             Please report any bugs or feature requests to
577             C, or through the web interface
578             at L
579             I will be notified, and then you'll automatically be notified of progress on
580             your bug as I make changes.
581              
582             =head1 SUPPORT
583              
584             You can find documentation for this module with the perldoc command.
585              
586             perldoc Math::BigInt::Random::OO
587              
588             You can also look for information at:
589              
590             =over 4
591              
592             =item * RT: CPAN's request tracker
593              
594             L
595              
596             =item * CPAN Ratings
597              
598             L
599              
600             =item * Search CPAN
601              
602             L
603              
604             =item * CPAN Testers PASS Matrix
605              
606             L
607              
608             =item * CPAN Testers Reports
609              
610             L
611              
612             =item * CPAN Testers Matrix
613              
614             L
615              
616             =back
617              
618             =head1 SEE ALSO
619              
620             Math::BigInt::Random(3), Math::Random(3), Net::Random(3).
621              
622             =head1 AUTHOR
623              
624             Peter John Acklam, Epjacklam@cpan.orgE
625              
626             =head1 COPYRIGHT & LICENSE
627              
628             Copyright 2010 by Peter John Acklam Epjacklam@cpan.orgE
629              
630             This library is free software; you can redistribute it and/or modify
631             it under the same terms as Perl itself, either Perl version 5.8.0 or,
632             at your option, any later version of Perl 5 you may have available.
633              
634             =cut
635              
636             1; # modules must return true