in reply to Average start time handling midnight
Then, you can even iterate a few times centering the interval around the best average ($best_avg) found:use POSIX qw(fmod); my @data = (1, 1, 1, 0, 1, 2, 3, 4, 21, 22, 20, 22, 23, 20, 22); sub circular_average { my ($pivot, $round, @data) = @_; my $sum = 0; my $sum2 = 0; my $displacement = 1.5 * $round - $pivot; for my $data (@data) { my $displaced = fmod($data + $displacement, $round); # printf "%2i->%3i,%2i ", $data, $displaced, $displaced - $dis +placement; $sum += $displaced; $sum2 += $displaced * $displaced; } # print "\n"; my $inv_n = 1.0 / @data; my $avg = fmod($inv_n * $sum + 0.5 * $round + $pivot, $round); wantarray ? ($avg, $inv_n * $sum2 - $inv_n * $inv_n * $sum * $sum) + : $avg; } my ($best_avg, $best_s2); for my $time (0..23) { my ($avg, $s2) = circular_average $time, 24, @data; if (not defined $best_s2 or $best_s2 > $s2) { $best_avg = $avg; $best_s2 = $s2; } } printf "avg: %.1f, s2: %.1f\n", $best_avg, $best_s2;
for (0..5) { ($best_avg, $best_s2) = circular_average $best_avg, 24, @data; printf "avg: %.1f, s2: %.1f\n", $best_avg, $best_s2; }
|
|---|