+sub calc {
+ my ($func) = @_;
+ if ($func eq 'avg') {
+ return calc('sum') / @order;
+ }
+ elsif ($func eq 'sum') {
+ 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;
+ 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;
+ }
+ else {
+ die "$func unknown\n";
+ }
+}
+