That is an interesting problem and ++ for your effective solution.
I hope you don't mind me modifying your script to make it a little more Perlish. It is more idiomatic (and often simpler) to use Perl-style rather than C-style loops. It is also, I think, preferable to declare variables inside the scope where they will be used rather than at the beginning of the script which, in effect, makes them global. I have renamed $toss to $tailsCt as I think that better describes its purpose. I have employed constants for number of runs and tosses just to illustrate their use. I also have added plenty of comments to clarify what I have done.
# Employ strictures and warnings.
#
use strict;
use warnings;
# Declare things we don't change as constants (by convention
# use upper-case for these).
#
use constant {
NUM_TOSSES => 20,
RUNS => 10_000_000,
};
# Initialise all possible elements of @collect to avoid
# "uninitialised" warnings at the printing stage if, for
# example, no "twenties" were thrown.
#
my @collect = map 0, 0 .. NUM_TOSSES;
# Use Perl-style for or foreach loops rather than C-style
# ones. The for and foreach are synonymous in Perl and can
# be freely interchanged. The loop variable is, by default,
# available in $_ or you can assign it to a lexically
# scoped variable as I do further down when printing the
# results. We don't need it in these nested loops.
#
for ( 1 .. RUNS )
{
# Declare lexically scoped $tailsCt so a new variable is
# brought into existence each time round the outer loop
# and will go out of scope on loop exit, thus no need to
# zeroise every time.
#
my $tailsCt;
# Toss the coin NUM_TOSSES times.
#
for ( 1 .. NUM_TOSSES )
{
# Give rand() an argument n and it will return a value
# such that 0 <= value < n. Use int to truncate so
# that $tailsCt is incremented by 0 or 1 (heads or
# tails respectively).
#
$tailsCt += int rand 2;
}
$collect[ $tailsCt ] ++;
}
# Rather than trying to line things up with tabs it might be
# easier to use printf and employ the same field widths in the
# heading and data rows. The RUNS constant is, in effect, a
# piece of code rather than a variable so we have to enclose
# it in a ${ \ ... } or a @{ [ ... ] } construct to interpolate
# it into a double-quoted string.
#
printf qq{%5s%25s%9s\n},
q{Tails}, qq{Count out of ${ \ RUNS }}, q{%ge};
# q{Tails}, qq{Count out of @{ [ RUNS ] }}, q{%ge}; also works
# Loop over the possible results from all heads to all tails
# using lexically scoped $tailsCt to access elements in the
# @collect array. This $tailsCt is a different variable to the
# $tailsCt in the for ( 1 .. RUNS ) { ... } loop above and is
# only in existence within the scope of this loop.
#
foreach my $tailsCt ( 0 .. NUM_TOSSES )
{
# Rather than using a temporary variable and sprintf you
# can just use printf directly and do the calculation in
# the argument list.
#
printf qq{%5d%25d%9.2f\n},
$tailsCt,
$collect[ $tailsCt ],
$collect[ $tailsCt ] / RUNS * 100;
}
I hope these observations are useful.
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.