Help with loops for project 2

17 views
Skip to first unread message

Disa Bäckström

unread,
Jun 27, 2014, 5:53:09 AM6/27/14
to unix-and-perl-...@googlegroups.com
When doing Project 2 I realized that I have problems with handling loops. I have solved everything except for the calculation of the variance. My idea is that I should construct a loop which takes each element, subtracts it from the mean, squares it and sums all elements up. However, I can't figure out how to do the squaring with the available commands. {$i ** 2} doesn't seem to do the job. Also, it would be convenient if I was able to tell the loop to perform more than one computation on the elements, but I can't figure out how to do that.

I'm probably overlooking some obvious solution which has been discussed in the tutorial, and I just need a nudge in the right direction. Here is my script this far:

#!/usr/bin/perl
# stats.pl by Disa
use strict; use warnings;

die "usage: stats.pl <number1> <number2> <etc>\n" unless @ARGV > 1;

# sum and mean

my @array = @ARGV;
my $length = @array;
my $sum = 0;

foreach my $i (@array) {$sum += $i}
my $mean = $sum / $length;
print "count: $length \t sum: $sum\t mean: $mean\n";

#median, min and max

my @sorted_array = sort {$a <=> $b} @array;
my $min = $sorted_array[0];
my $max = $sorted_array[$length - 1];
my $even_median = ($sorted_array[$length / 2] + $sorted_array[($length / 2) - 1]) / 2;
my $odd_median = $sorted_array [$length / 2];
print "min: $min \t max: $max \t ";

if ($length % 2 == 0)    {print "median: $even_median\n"}
elsif ($length % 2 == 1) {print "median: $odd_median\n"}


# Variance: 1)calculated each elements difference from the mean
my @diff = "";
foreach my $i (@array) {push (@diff, $mean -$i)}
my $diff = join(", ", @diff);
print $diff, "\n";
#How to square each element and sum them up???
#my $variance = $mean / $length;
#print  "variance: $variance\n";

#calculate stdev with sqrt($variance)

 -------------------------------------------------------------------------

Output:
 stats.pl 2 3 4 1 5 
count: 5         sum: 15         mean: 3
min: 1   max: 5          median: 3
, 1, 0, -1, 2, -2


Great course by the way. It's my first time programming and I find it very challenging and fun!
/Disa

Keith Bradnam

unread,
Jun 27, 2014, 1:56:10 PM6/27/14
to unix-and-perl-...@googlegroups.com
Comments:

  1. @array is a terrible choice for an array name! Not descriptive of the contents at all
  2. You should only need to calculate the median *once* (inside the if-else statement). No need to calculate it twice and then see which one to use.
  3. You can calculate the square of something by using the exponentiation ** operator (look at the Perl documentation on perldoc.org to find out more)
  4. Variance is the sum of the squared deviations (between observed value and mean), so you ideally should declare a $variance variable *before* the foreach loop and add to this value *inside* the foreach loop.
  5. The thing you add to $variance will be ($value - $mean) ** 2

Disa Bäckström

unread,
Jun 30, 2014, 10:06:47 AM6/30/14
to unix-and-perl-...@googlegroups.com
Thank you for your comments Keith. In the end I came up with a solution before reading your comment. It became quite condensed, but I printed out the sum of the squared differences from the mean and controlled that it was correct.

I made the calculation of the mean more efficient thanks to your suggestion. I also changed the name of the @array to @input. I hope it's a more informative array name.

Here is the relevant part of the script:

if ($length % 2 == 0)    {my $median = ($sorted_input[$length / 2] + $sorted_input[($length / 2) - 1]) / 2;
print "median: $median\n"}
elsif ($length % 2 == 1) {my $median = $sorted_input [$length / 2];
print "median: $median\n"}

# Variance
my $sqdiffsum = 0;
for (my $i= 0; $i < @input; $i++) {$sqdiffsum += (($mean -$input[$i])*($mean-$input[$i]))}
my $variance = $sqdiffsum / ($length -1);
my $stdev = sqrt($variance);

#print "$sqdiffsum\n" TEST
print "Sample variance: $variance \t Standard deviation: $stdev \n";

Output:
stats.pl 2 3 1 4 5
count: 5         sum: 15         mean: 3
min: 1   max: 5          median: 3
Sample variance: 2.5     Standard deviation: 1.58113883008419

Keith Bradnam

unread,
Jul 9, 2014, 7:55:14 AM7/9/14
to unix-and-perl-...@googlegroups.com
You only should declare 'my $median' once. This should happen before the if else statement. We typically declare variables once, but assign contents many times.

Also, you only need to print the median once. By moving the print statement outside of the if-else block you remove one unnecessary line of code.

Finally, you really should use the exponentiation operator to square the deviations. Your fix might work, but doesn't scale well if you wanted to raise anything to a higher power.

Regards,

Keith

Reply all
Reply to author
Forward
0 new messages