http://www.perlmonks.org?node_id=1005043

dr.jekyllandme has asked for the wisdom of the Perl Monks concerning the following question:

Hello, I have a simple script that simulates a coin toss. I define an array with strings "heads" and "tails" and use rand to choose between these two strings.
#!usr/bin/perl use strict; use warnings; my %probs; foreach( 1..10 ) { print "Coin toss $_\n"; my $value = &coin_toss; $probs{ $value }++; print "Value = $value\n\n"; } print "Total Heads = $probs{ heads }\n"; print "Total Tails = $probs{ tails }\n"; sub coin_toss { my @coin = qw( heads tails ); my $index = rand @coin; return $coin[ $index ]; }
My question is, is this actually random? Is there an equal percentage of choosing either value. I notice that it is very rare for me to get 5 heads and 5 tails. It could be that I am only tossing coins 10 times, is that too small? Is there a better way to do this? Thank you.

Replies are listed 'Best First'.
Re: Is this really random?
by Athanasius (Archbishop) on Nov 22, 2012 at 04:45 UTC

    From Pseudorandom:

    A pseudorandom process is a process that appears to be random but is not. Pseudorandom sequences typically exhibit statistical randomness while being generated by an entirely deterministic causal process.

    So yes, the “statistical randomness” guarantees that there is an equal probability of choosing either value.

    I notice that it is very rare for me to get 5 heads and 5 tails.

    Well, the probability of getting 5 heads in a row followed by 5 tails in a row is 1/1024. But the probability that 10 rolls will result in 5 heads and 5 tails (in any order) is (10!/5!5!)/1024 = 0.246 or approx. 25%, so this should happen around once in every 4 runs of the simulation.

    Is there a better way to do this?

    Don’t call a sub using the & prefix:

    my $value = &coin_toss;

    This syntax is used for overriding prototypes, and should be avoided unless you have a good reason to use it. Prefer:

    my $value = coin_toss();

    Hope that helps,

    Athanasius <°(((><contra mundum

      Overriding prototypes is not all it does!

      sub foo { print "Called foo(" . join(',', @_) . ")\n"; } sub bar { print "Called bar(" . join(',', @_) . ")\n"; print "foo(); : "; foo(); print "&foo; : "; &foo; } bar(1,2,3);

      Jenda
      Enoch was right!
      Enjoy the last years of Rome.

        Also don't forget &foo() which overrides prototypes without the effect of passing along the caller's @_.

        perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: Is this really random?
by muba (Priest) on Nov 22, 2012 at 03:11 UTC

    No, it's pseudorandom, but for most applications that's good enough.

    Also, higher values of n always give more reliable results, statistically.

Re: Is this really random?
by 2teez (Vicar) on Nov 22, 2012 at 03:37 UTC

      ...what about using this?

      #!/usr/bin/perl use strict; use warnings; open(RANDOM, "<", "/dev/random") || die $!; read(RANDOM, $_, 4); close RANDOM; my $seed = unpack("L", $_); print $seed . qq(\n); srand($seed); # do stuff...

      Regards, Karl

      «The Crux of the Biscuit is the Apostrophe»

Re: Is this really random?
by ColonelPanic (Friar) on Nov 22, 2012 at 08:39 UTC

    A simple test:

    my $sum = 0; for( 1..10_000_000 ) { $sum++ if coin_toss() eq 'heads'; } print $sum;

    The result I got was 5,000,938, meaning heads happened 50.01% of the time. Seems pretty reasonable.

    Most people's perceptions of randomness are notoriously faulty. For example, they seriously underestimate the number of times repeated numbers will appear in a sequence.

    One suggestion: I think it is clearer to use int() to specify that you want a random integer:

    my $index = int rand @coin; return $coin[ $index ];

    As your code is written, you are using a floating point number as the array index. This works (because it is converted to integer), but it is a little unusual. You wouldn't write  $array[1.5]



    When's the last time you used duct tape on a duct? --Larry Wall
Re: Is this really random?
by aitap (Curate) on Nov 22, 2012 at 17:47 UTC
    Well, actual probability of getting 5 heads and 5 tails is C(10,5)*p(head)^5*p(tail)^5 = (10!)/(5!*5!)*(0.5^5)*(0.5^5) = 0.24609375, so you probably won't always get this result.
    (See Bernoulli trial for more information)
    Sorry if my advice was wrong.