Averages/Mean time of day: Difference between revisions

From Rosetta Code
Content added Content deleted
Line 106: Line 106:
</pre>
</pre>



----
=={{header|Erlang}}==
=={{header|Erlang}}==
{{incorrect|Erlang|Seconds are wrong?}}
<lang Erlang>
<lang Erlang>
-module( mean_time_of_day ).
-module( mean_time_of_day ).

Revision as of 05:32, 2 July 2013

Task
Averages/Mean time of day
You are encouraged to solve this task according to the task description, using any language you may know.

A particular activity of bats occurs at these times of the day:

23:00:17, 23:40:20, 00:12:45, 00:17:19

Using the idea that there are twenty-four hours in a day, which is analogous to there being 360 degrees in a circle, map times of day to and from angles; and using the ideas of Averages/Mean angle compute and show the average time of the nocturnal activity to an accuracy of one second of time.

AWK

<lang AWK>#!/usr/bin/awk -f {

   c = atan2(0,-1)/(12*60*60);
   x=0.0; y=0.0;
   for (i=1; i<=NF; i++) {	
       split($i,a,":");

p = (a[1]*3600+a[2]*60+a[3])*c; x += sin(p); y += cos(p);

   }
   p = atan2(x,y)/c;	
   if (p<0) p += 24*60*60;
   print strftime("%T",p,1);

}</lang>

$ echo 23:00:17, 23:40:20, 00:12:45, 00:17:19 | awk -f mean_time_of_day.awk
23:47:43

C

<lang c>/*29th August, 2012 Abhishek Ghosh*/

  1. include<stdlib.h>
  2. include<math.h>
  3. include<stdio.h>

typedef struct {

 int hour, minute, second;

} digitime;

double timeToDegrees (digitime time) {

 return (360 * time.hour / 24.0 + 360 * time.minute / (24 * 60.0) +
         360 * time.second / (24 * 3600.0));

}

digitime timeFromDegrees (double angle) {

 digitime d;
 double totalSeconds = 24 * 60 * 60 * angle / 360;
 d.second = (int) totalSeconds % 60;
 d.minute = ((int) totalSeconds % 3600 - d.second) / 60;
 d.hour = (int) totalSeconds / 3600;
 return d;

}

double meanAngle (double *angles, int size) {

 double y_part = 0, x_part = 0;
 int i;
 for (i = 0; i < size; i++)
   {
     x_part += cos (angles[i] * M_PI / 180);
     y_part += sin (angles[i] * M_PI / 180);
   }
 return atan2 (y_part / size, x_part / size) * 180 / M_PI;

}

int main () {

 digitime *set, meanTime;
 int inputs, i;
 double *angleSet, angleMean;
 printf ("Enter number of inputs : ");
 scanf ("%d", &inputs);
 set = malloc (inputs * sizeof (digitime));
 angleSet = malloc (inputs * sizeof (double));
 printf ("\n\nEnter the data separated by a space between each unit : ");
 for (i = 0; i < inputs; i++)
   {
     scanf ("%d:%d:%d", &set[i].hour, &set[i].minute, &set[i].second);
     angleSet[i] = timeToDegrees (set[i]);
   }
 meanTime = timeFromDegrees (360 + meanAngle (angleSet, inputs));
 printf ("\n\nThe mean time is : %d:%d:%d", meanTime.hour, meanTime.minute,
         meanTime.second);
 return 0;

}</lang>

Output:
Enter number of inputs : 4


Enter the data separated by a space between each unit : 23:00:17 23:40:20 00:12:45 00:17:19


The mean time is : 23:47:43



Erlang

This example is incorrect. Please fix the code and remove this message.

Details: Seconds are wrong?

<lang Erlang> -module( mean_time_of_day ). -export( [from_times/1, task/0] ).

from_times( Times ) -> Seconds = [seconds_from_time(X) || X <- Times], Degrees = [degrees_from_seconds(X) || X <- Seconds], Average = mean_angle:from_degrees( Degrees ), time_from_seconds( seconds_from_degrees(Average) ).

task() -> Times = ["23:00:17", "23:40:20", "00:12:45", "00:17:19"], io:fwrite( "The mean time of ~p is: ~p~n", [Times, from_times(Times)] ).


degrees_from_seconds( Seconds ) when Seconds < (24 * 3600) -> (Seconds * 360) / (24 * 3600).

seconds_from_degrees( Degrees ) when Degrees < 0 -> seconds_from_degrees( Degrees + 360 ); seconds_from_degrees( Degrees ) when Degrees < 360 -> (Degrees * 24 * 3600) / 360.

seconds_from_time( Time ) -> {ok, [Hours, Minutes, Seconds], _Rest} = io_lib:fread( "~d:~d:~d", Time ), Hours * 3600 + Minutes * 60 + Seconds.

time_from_seconds( Seconds_float ) -> Seconds = erlang:round( Seconds_float ), Hours = Seconds div 3600, Minutes = (Seconds - (Hours * 3600)) div 60, Secs = Seconds - (Hours * 3600) - (Minutes * 60), lists:flatten( io_lib:format("~2.10.0B:~2.10.0B:~2.10.0B", [Hours, Minutes, Secs]) ). </lang>

Output:
78> mean_time_of_day:task().
"23:48:00"

Go

<lang go>package main

import (

   "errors"
   "fmt"
   "log"
   "math"
   "time"

)

var inputs = []string{"23:00:17", "23:40:20", "00:12:45", "00:17:19"}

func main() {

   tList := make([]time.Time, len(inputs))
   const clockFmt = "15:04:05"
   var err error
   for i, s := range inputs {
       tList[i], err = time.Parse(clockFmt, s)
       if err != nil {
           log.Fatal(err)
       }
   }
   mean, err := meanTime(tList)
   if err != nil {
       log.Fatal(err)
   }
   fmt.Println(mean.Format(clockFmt))

}

func meanTime(times []time.Time) (mean time.Time, err error) {

   if len(times) == 0 {
       err = errors.New("meanTime: no times specified")
       return
   }
   var ssum, csum float64
   for _, t := range times {
       h, m, s := t.Clock()
       n := t.Nanosecond()
       fSec := (float64((h*60+m)*60+s) + float64(n)*1e-9)
       sin, cos := math.Sincos(fSec * math.Pi / (12 * 60 * 60))
       ssum += sin
       csum += cos
   }
   if ssum == 0 && csum == 0 {
       err = errors.New("meanTime: mean undefined")
       return
   }
   _, dayFrac := math.Modf(1 + math.Atan2(ssum, csum)/(2*math.Pi))
   return mean.Add(time.Duration(dayFrac * 24 * float64(time.Hour))), nil

}</lang>

Output:
23:47:43

J

use avgAngleR from Averages/Mean angle#J <lang J>require 'types/datetime' parseTimes=: ([: _&".;._2 ,&':');._2 secsFromTime=: 24 60 60 #. ] NB. convert from time to seconds rft=: 2r86400p1 * secsFromTime NB. convert from time to radians meanTime=: 'hh:mm:ss' fmtTime [: secsFromTime [: avgAngleR&.rft parseTimes</lang>

Example Use:

<lang J> meanTime '23:00:17 23:40:20 00:12:45 00:17:19 ' 23:47:43</lang>

Mathematica

<lang mathematica>meanTime[list_] :=

 StringJoin@
  Riffle[ToString /@ 
      Floor@{Mod[24 #, 24], Mod[24*60 #, 60], Mod[24*60*60 #, 60]} &[
    Arg[Mean[
       Exp[FromDigits[ToExpression@StringSplit[#, ":"], 60] & /@ 
           list/(24*60*60) 2 Pi I]]]/(2 Pi)], ":"];

meanTime[{"23:00:17", "23:40:20", "00:12:45", "00:17:19"}]</lang>

Output:
23:47:43

MATLAB / Octave

<lang MATLAB>function t = mean_time_of_day(t)

   c = pi/(12*60*60);
   for k=1:length(t)

a = sscanf(t{k},'%d:%d:%d'); phi(k) = (a(1)*3600+a(2)*60+a(3));

   end;
   d = angle(mean(exp(i*phi*c)))/(2*pi); % days 
   if (d<0) d += 1;
   t = datestr(d,"HH:MM:SS");

end; </lang>

mean_time_of_day({'23:00:17', '23:40:20', '00:12:45', '00:17:19'})
ans = 23:47:43

OCaml

<lang ocaml>let pi_twice = 2.0 *. 3.14159_26535_89793_23846_2643 let day = float (24 * 60 * 60)

let rad_of_time t =

 t *. pi_twice /. day

let time_of_rad r =

 r *. day /. pi_twice

let mean_angle angles =

 let sum_sin = List.fold_left (fun sum a -> sum +. sin a) 0.0 angles
 and sum_cos = List.fold_left (fun sum a -> sum +. cos a) 0.0 angles in
 atan2 sum_sin sum_cos

let mean_time times =

 let angles = List.map rad_of_time times in
 let t = time_of_rad (mean_angle angles) in
 if t < 0.0 then t +. day else t

let parse_time t =

 Scanf.sscanf t "%d:%d:%d" (fun h m s -> float (s + m * 60 + h * 3600))

let round x = int_of_float (floor (x +. 0.5))

let string_of_time t =

 let t = round t in
 let h = t / 3600 in
 let rem = t mod 3600 in
 let m = rem / 60 in
 let s = rem mod 60 in
 Printf.sprintf "%d:%d:%d" h m s

let () =

 let times = ["23:00:17"; "23:40:20"; "00:12:45"; "00:17:19"] in
 Printf.printf "The mean time of [%s] is: %s\n"
   (String.concat "; " times)
   (string_of_time (mean_time (List.map parse_time times)))</lang>
Output:
The mean time of [23:00:17; 23:40:20; 00:12:45; 00:17:19] is: 23:47:43

PARI/GP

<lang parigp>meanAngle(v)=atan(sum(i=1,#v,sin(v[i]))/sum(i=1,#v,cos(v[i])))%(2*Pi) meanTime(v)=my(x=meanAngle(2*Pi*apply(u->u[1]/24+u[2]/1440+u[3]/86400, v))*12/Pi); [x\1, 60*(x-=x\1)\1, 60*(60*x-60*x\1)] meanTime([[23,0,17], [23,40,20], [0,12,45], [0,17,19]])</lang>

Output:
[23, 47, 43.361528520325019522213261334501251061]

Perl 6

<lang perl6>sub tod2rad($_) { [+](.comb(/\d+/) Z* 3600,60,1) * pi / 43200 }

sub rad2tod ($r) {

   my $x = $r * 43200 / pi;
   (($x xx 3 Z/ 3600,60,1) Z% 24,60,60).fmt('%02d',':');

}

sub phase ($c) { $c.polar[1] }

sub mean-time (@t) { rad2tod phase [+] map { cis tod2rad $_ }, @t }

say mean-time($_).fmt("%s is the mean time of "), $_ for

   ["23:00:17", "23:40:20", "00:12:45", "00:17:19"];</lang>
Output:
23:47:43 is the mean time of 23:00:17 23:40:20 00:12:45 00:17:19

PicoLisp

<lang PicoLisp>(load "@lib/math.l")

(de meanTime (Lst)

  (let Tim
     (*/
        (atan2
           (sum '((S) (sin (*/ ($tim S) pi 43200))) Lst)
           (sum '((S) (cos (*/ ($tim S) pi 43200))) Lst) )
        43200 pi )
     (tim$ (% (+ Tim 86400) 86400) T) ) )</lang>
Test:

<lang PicoLisp>: (meanTime '("23:00:17" "23:40:20" "00:12:45" "00:17:19")) -> "23:47:43"</lang>

Python

<lang python>from cmath import rect, phase from math import radians, degrees


def mean_angle(deg):

   return degrees(phase(sum(rect(1, radians(d)) for d in deg)/len(deg)))

def mean_time(times):

   t = (time.split(':') for time in times)
   seconds = ((float(s) + int(m) * 60 + int(h) * 3600) 
              for h, m, s in t)
   day = 24 * 60 * 60
   to_angles = [s * 360. / day for s in seconds]
   mean_as_angle = mean_angle(to_angles)
   mean_seconds = mean_as_angle * day / 360.
   if mean_seconds < 0:
       mean_seconds += day
   h, m = divmod(mean_seconds, 3600)
   m, s = divmod(m, 60)
   return '%02i:%02i:%02i' % (h, m, s)


if __name__ == '__main__':

   print( mean_time(["23:00:17", "23:40:20", "00:12:45", "00:17:19"]) )</lang>
Output:
23:47:43

Racket

<lang racket>

  1. lang racket

(define (mean-angle/radians as)

 (define n (length as))
 (atan (* (/ 1 n) (for/sum ([αj as]) (sin αj)))
       (* (/ 1 n) (for/sum ([αj as]) (cos αj)))))

(define (mean-time times)

 (define secs/day (* 60 60 24))
 (define (time->deg time)
   (/ (for/fold ([sum 0]) ([t (map string->number (string-split time ":"))])
        (+ (* 60 sum) t))
      secs/day 1/360 (/ 180 pi)))
 (define secs
   (modulo (inexact->exact (round (* (mean-angle/radians (map time->deg times))
                                     (/ 180 pi) 1/360 secs/day)))
           secs/day))
 (let loop ([s secs] [ts '()])
   (if (zero? s) (string-join ts ":")
       (let-values ([(q r) (quotient/remainder s 60)])
         (loop q (cons (~r r #:min-width 2 #:pad-string "0") ts))))))

(mean-time '("23:00:17" "23:40:20" "00:12:45" "00:17:19")) </lang>

Output:
"23:47:43"

Tcl

<lang tcl>proc meanTime {times} {

   set secsPerRad [expr {60 * 60 * 12 / atan2(0,-1)}]
   set sumSin [set sumCos 0.0]
   foreach t $times {

# Convert time to count of seconds from midnight scan $t "%02d:%02d:%02d" h m s incr s [expr {[incr m [expr {$h * 60}]] * 60}] # Feed into averaging set sumSin [expr {$sumSin + sin($s / $secsPerRad)}] set sumCos [expr {$sumCos + cos($s / $secsPerRad)}]

   }
   # Don't need to divide by counts; atan2() cancels that out
   set a [expr {int(atan2($sumSin, $sumCos) * $secsPerRad)}]
   # Convert back to human-readable
   format "%02d:%02d:%02d" [expr {$a / 60 / 60 % 24}] [expr {$a / 60 % 60}] [expr {$a % 60}]

}

puts [meanTime {23:00:17 23:40:20 00:12:45 00:17:19}]</lang>

Output:
23:47:44

XPL0

<lang XPL0>include c:\cxpl\codes;

proc NumOut(N); \Display 2-digit N with leading zero int N; [if N<10 then ChOut(0, ^0); IntOut(0, N); ];

proc TimeOut(Sec); \Display real seconds as HH:MM:SS real Sec; [NumOut(fix(Sec)/3600); ChOut(0, ^:);

NumOut(rem(0)/60);      ChOut(0, ^:);
NumOut(rem(0));

];

func real HMS2Sec(H, M, S); \Convert hours, minutes, seconds to real seconds int H, M, S; return float(((H*60 + M)*60) + S);

func real MeanTime(A); \Return the mean of the given list of times int A; real X, Y, Sec; int I; def Pi = 3.14159265358979323846; def S2R = Pi/(12.*60.*60.); \coefficient to convert seconds to radians [X:= 0.0; Y:= 0.0; for I:= 1 to A(0) do

   [Sec:= HMS2Sec(A(I,0), A(I,1), A(I,2));
   X:= X + Cos(Sec*S2R);
   Y:= Y + Sin(Sec*S2R);
   ];

Sec:= ATan2(Y,X)/S2R; if Sec < 0.0 then Sec:= Sec + 24.*60.*60.; return Sec; ];

TimeOut(MeanTime([4, [23,00,17], [23,40,20], [00,12,45], [00,17,19]]))</lang>

Output:
23:47:43