in reply to How do I get the root mean square of a list?

thanks guys - horribly inefficient incorrectly named "rms" sub now looks like
sub std_dev($) { my $listref = $_[0]; my $avg = avg $listref; sqrt(sum([map{($avg-$_)*($avg-$_)}@{$listref}])/@{$listref}); }
Can I improve on this?

Replies are listed 'Best First'.
Re: Answer: How do I get the root mean square of a list?
by MeowChow (Vicar) on Jun 04, 2001 at 20:36 UTC
    Pass-by-reference isn't winning you anything here, since you are explicitly dereferencing and iterating over the entire array anyway. I would rewrite as:
    sub std_dev { my ($sum, $avg, $variance, $t); $sum += $_ for @_; $avg = $sum / @_; $variance += ($t = ($avg - $_)) * $t for @_; $variance /= @_; sqrt $variance; }
    This benchmarks over twice as fast, mostly because it's not calling outside subs for summation and averaging. There's a little intermediate result optimization in there as well.

    I wonder, however, if there isn't a more efficient algorithm for calculating standard deviation, that doesn't require iterating twice... tilly?

       MeowChow                                   
                   s aamecha.s a..a\u$&owag.print
      You need to iterate twice. However the following version should be slightly faster and I think is numerically more stable:
      sub std_dev { my ($sum, $sqr_sum); for (@_) { $sum += $_; $sqr_sum += $_ * $_; } sqrt(($sqr_sum - $sum * $sum / @_)/@_); }
      And, of course, if your set of numbers is a sample set from a random distribution, the standard deviation of the numbers is a biased predictor of the true standard deviation, so you may prefer the following:
      # Produces an unbiased estimate of a standard deviation # from a sample sub std_dev_samp { my ($sum, $sqr_sum); for (@_) { $sum += $_; $sqr_sum += $_ * $_; } sqrt(($sqr_sum - $sum * $sum / @_)/$#_); }
      you have heard of PDL havent you? it handles array ops as fast as C within Perl. and it does have rms as part of its stats() function.