Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Where is the zero coming from?

by Pauleduc (Initiate)
on Aug 01, 2014 at 22:04 UTC ( [id://1095970]=perlquestion: print w/replies, xml ) Need Help??

Pauleduc has asked for the wisdom of the Perl Monks concerning the following question:

Hello, Monks. I am very new here, (my first post) and am trying to learn perl. For my first little exercise, I am trying to write a script to print out a series of 6 random lotto numbers. I have loaded an array with numbers 1to 49, and even printed it out to make sure it was loaded correctly. However, when the program runs, it occasionally ends up with a zero as on of my lucky picks, and I have no idea where this is coming from, as it is not one of the 49 choices!
#!/usr/bin/perl # Program to pick 6 random & unique lottery numbers from a list of 49. # # # use strict; use warnings; $loop = 50; # number of picks to make while ($loop) { @choices = (1 .. 49); # list of available numbers # print "@choices \n"; # just for testing $count = 5; # number of picks less 1 @picks = (); # initialize/clear the array $num = rand(@choices); # get 1st random pick push (@picks, $num); # and load it into array while ($count) { # now get 5 more numbers $num = rand(@choices); if ($num ~~ @picks) { # if we already have this number, tr +y again next; } # end if push (@picks, $num); # add new number to list $count -- ; # decrement count and get another nu +mber } # end while $count @picks = sort { $a <=> $b } @picks; printf ("Lucky numbers: %02d %02d %02d %02d %02d %02d \n\n", @picks +); $loop -- ; # decrement counter } # end while $loop exit;

Replies are listed 'Best First'.
Re: Where is the zero coming from?
by InfiniteSilence (Curate) on Aug 01, 2014 at 22:22 UTC

    I think you need to read the perldoc for the rand() function:

    linux> perldoc -f rand
    perl -e '@choices = qw|a b c d e|; print rand(@choices) . qq|\n|;' 0.785222268100387

    It doesn't return a random element from your list.

    Since your question reads so much like homework I'll leave you with this:

    • Since rand() gives you a non-integer you need to turn it into an integer (read the perldoc)
    • You only have 49 elements in your bucket of lotto balls -- how can you restrict the return value of rand() so that the greatest value it can produce is 49 (hint, you might try using a modulus)?

    Celebrate Intellectual Diversity

Re: Where is the zero coming from?
by Cristoforo (Curate) on Aug 01, 2014 at 23:18 UTC
    Try changing: $num = rand(@choices);

    to: $num = $choices[ rand(@choices) ];

    rand(@choices) will give you a random index (from 0 to 48).

    Update: Changed @choices[ rand(@choices) ]; to $choices[ rand(@choices) ];

      Ah, now I understand... Thanks!
Re: Where is the zero coming from?
by AnomalousMonk (Archbishop) on Aug 02, 2014 at 07:05 UTC

    And if this wasn't a homework question, the standard | kneejerk approach would be List::Util::shuffle (if: the list you're shuffling is relatively small; you don't necessarily need robust randomness, because shuffle is based on the rand functions in the libc library against which your Perl is built, and they may not be terribly random :).

    c:\@Work\Perl\monks>perl -wMstrict -le "use List::Util qw(shuffle); ;; use constant N => 6; use constant LIST => (1 .. 49); use constant FMT => ' %02d' x N; ;; for my $pick (1 .. 5) { my @picks = sort { $a <=> $b } (shuffle LIST)[0 .. N-1]; printf qq{pick %2d: ${ \FMT } \n}, $pick, @picks; } " pick 1: 01 05 15 34 38 39 pick 2: 11 20 22 31 38 48 pick 3: 11 15 18 21 22 29 pick 4: 05 07 09 12 20 48 pick 5: 01 13 16 24 44 45
      I believe that this is the only suggestion which correctly simulates picking six balls without putting each ball back in the box before drawing the next ball. (Most lotteries keep the balls out and display all six of them.)
      Bill

        Although I haven't tested it, I think CountZero's approach avoids dupes: splice removes each spliced element from the  @choices source array before the next pick. I like CountZero's approach better because it's simple, doesn't depend on a module, and seems like it would scale well to very large arrays. The only drawback I see is that the source array is mutated. However, I believe there is a large literature base on 'fair' picking, so there's probably an even better solution!

Re: Where is the zero coming from?
by CountZero (Bishop) on Aug 02, 2014 at 08:58 UTC
    It doesn't have to be more complicated than this:
    use Modern::Perl '2014'; my @choices = ( 1 .. 49 ); printf "Lucky numbers: %02d %02d %02d %02d %02d %02d \n\n", sort { $a <=> $b } map { splice @choices, rand(@choices), 1 } ( 1 .. + 6 );
    Basically 1 line (other than the setting up of the array to pick from) and 1 variable to hold the choices to pick from.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

    My blog: Imperial Deltronics
Re: Where is the zero coming from?
by AppleFritter (Vicar) on Aug 01, 2014 at 23:03 UTC

    InfiniteSilence is correct, of course. Here's what rand's documentation has to say:

    rand EXPR

    [...]

    Returns a random fractional number greater than or equal to 0 and less than the value of EXPR.

    In your code, @choices is used in scalar context and evaluates to its number of elements; since it's got 49 elements, you're essentially telling Perl that you want to a random number between 0 (inclusive) and 49 (exclusive).

    So you're not only occasionally getting zero, you're also never getting the number 49.

Re: Where is the zero coming from?
by Laurent_R (Canon) on Aug 02, 2014 at 14:29 UTC
    This is an easy way to get six random integer numbers between 1 and 49:
    $ perl -e 'print int (1 + rand 49), " ", for 1..6' 48 16 40 39 21 24
    Adding 1 to the result of the rand function makes it sure that the obtained integers will be between 1 and 49 (and not between 0 and 48). It can even be made slightly simpler:
    $ perl -e 'print 1 + int rand 49, " ", for 1..6' 5 33 19 21 25 39

    If you are under Windows, change quotes for apostrophes and vice-versa:

    perl -e "print 1 + int rand 49, ' ', for 1..6"
    However, besides everything that has already been said, this still suffers from a major drawback if you're going to use it for picking up lotto numbers: there is no guarantee that you don't get twice the same number. I only had to run the first Perl one-liner above 9 times to get the following result:
    $ perl -e 'print int (1 + rand 49), " ", for 1..6' 20 32 37 32 3 39
    where number 32 appears twice, which is not good for lotto numbers. Since this looks a bit like a homework assignment, I'll leave it to you to find out how to make an additional draw if you find a number that has already been picked up.

    A final additional advice: don't comment out use strict;, rather solve the problems that it diagnoses (hint: use my to declare your variables).

      Once again, I thank everyone for your comments and suggestions... some of which use code that I have not yet studied, but will eventually get there. Keep in mind that this is a hobby with me and I am only half way thru my perl for dummies book :-) But again, I do appreciate the responses. The script was not meant to be practical, but rather an exercise in learning basic perl.
        My own personal opinion is that you should probably not use the "Perl for dummies" book, it is really not very good. Actually, as far as CS is concerned, most of the "XXX for dummies" books are bad and seem to be aimed as making you a dummy. Use the O'Reilly books instead if you can, their are much much better. "Learning Perl", by O'Reilly, is probably my best advice for a starter.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1095970]
Approved by igelkott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (4)
As of 2024-04-19 23:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found