File Coverage

blib/lib/Math/BigInt/Random/OO.pm
Criterion Covered Total %
statement 121 125 96.8
branch 47 74 63.5
condition 1 3 33.3
subroutine 9 9 100.0
pod 2 2 100.0
total 180 213 84.5


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