$vars{partsum} = sum(0, grep {length} @values[$linemin .. $linemax])
if $linemin <= $linemax and ($opt{hidemin} or $opt{hidemax});
%vars = (%vars,
- sum => sum(@order),
min => $order[-1],
max => $order[0],
);
- $vars{avg} = $vars{sum} / @order;
}
say varfmt($opt{report}, \%vars);
return 1;
sub calc {
my ($func) = @_;
if ($func eq 'avg') {
- return sum(@order) / @order;
+ return calc('sum') / @order;
}
elsif ($func eq 'sum') {
- return sum(@order);
+ state $cache; # avoid recount
+ state $cachednr = 0; # if unchanged
+ unless (@order == $cachednr) {
+ $cache = sum(@order);
+ $cachednr = @order;
+ }
+ return $cache;
}
elsif ($func =~ /\A([0-9.]+)v\z/) {
$1 <= 100 or die(
"percentile $1 out of bounds\n"
);
my $index = $#order * $1 / 100;
- return ($order[$index] + $order[$index + .5]) / 2;
+ my $f = $index - int $index;
+ my $val = $order[$index];
+ if ($f) {
+ my $next = $order[$index + 1];
+ $val -= $f * ($val - $next);
+ }
+ return $val;
}
elsif ($func =~ /\A-?[0-9.]+\z/) {
return $func;
defined && do {
$_ = $opt{'value-format'}->($_) if $format;
if ($cmd and $op eq ':') {
- $_ = varfmt($cmd, $vars);
+ $_ = !!$_ && varfmt($cmd, $vars);
}
elsif ($cmd) {
eval $cmd;
=item I<percentage>B<v>
-Ranked value at the given percentile.
-The default shows C<+> at C<50v> for the mean or median;
-the middle value or average between middle values.
-One standard deviation right of the mean is at about C<68.3v>.
+Ranked value at the given percentile,
+or score at or below which a percentage falls
+in its frequency distribution (inclusive).
+
+The default shows C<+> at C<50v> for the mean or median:
+the middle value or interpolation between two values.
+One standard deviation below the median is at about C<68v>.
The default includes C<< >31.73v <68.27v >>
to encompass all I<normal> results, or 68% of all entries, by I<< <--> >>.