I agree with Excel, for the most part:
condition1 50.73
condition2 44.34
condition3 52.05
condition4 56.39
use strict;
use warnings;
use List::Util 'sum';
sub sample_sd {
die unless @_ and ref $_[ 0 ] eq 'ARRAY' and @{ $_[ 0 ] } > 1;
my $data = shift;
my $sum = sum @$data;
my $n = @$data;
my $mean = $sum/$n;
my $sq_dev = sum map $_*$_, map $_ - $mean, @$data;
return sqrt( ( $sq_dev )/( $n - 1 ) );
}
while ( <DATA> ) {
my @data = split;
my $label = shift @data;
my $sd = sample_sd( \@data );
printf "$label %.2f\n", $sd;
}
__DATA__
condition1 397 322 350 346 338 324 461 477 432 373 386 412 475 360.5 3
+84 324 424 319 454.5 412 387 370
condition2 360.5 318.5 356 316.5 330 296.5 444 474 416.5 355 320 401.5
+ 363.5 332 363 324 388 312 344 372 347.5 338
condition3 372 354 358 311 336.5 297 485 461 407.5 365 342 428 494 343
+.5 372 324 379.5 345 389 384 363 346
condition4 324 305.5 364 320 327.5 288.5 432.5 434 447 369 315 397.5 5
+15 339 405 330 396 319 345 381.5 340 317
Here's a more efficient alternative, closer in spirit to the algorithm you posted originally, but properly making the finite-sample correction:
use List::Util 'sum';
sub sample_sd {
die unless @_ and ref $_[ 0 ] eq 'ARRAY' and @{ $_[ 0 ] } > 1;
my $data = shift;
my $sum = sum @$data;
my $sum2 = sum map $_*$_, @$data;
my $n = @$data;
return sqrt( ( $sum2 - (( $sum*$sum )/$n) )/($n-1) );
}