Task: Averages_Mean time of day


C++: #include <iomanip>
#include <iostream>
#include <vector>

#define _USE_MATH_DEFINES
#include <math.h>

struct Time {
    int hour, minute, second;

    friend std::ostream &operator<<(std::ostream &, const Time &);
};

std::ostream &operator<<(std::ostream &os, const Time &t) {
    return os << std::setfill('0')
        << std::setw(2) << t.hour << ':'
        << std::setw(2) << t.minute << ':'
        << std::setw(2) << t.second;
}

double timeToDegrees(Time &&t) {
    return 360.0 * t.hour / 24.0
        + 360.0 * t.minute / (24 * 60.0)
        + 360.0 * t.second / (24 * 3600.0);
}

Time degreesToTime(double angle) {
    while (angle < 0.0) {
        angle += 360.0;
    }
    while (angle > 360.0) {
        angle -= 360.0;
    }

    double totalSeconds = 24.0 * 60 * 60 * angle / 360;
    Time t;

    t.second = (int)totalSeconds % 60;
    t.minute = ((int)totalSeconds % 3600 - t.second) / 60;
    t.hour = (int)totalSeconds / 3600;

    return t;
}

double meanAngle(const std::vector<double> &angles) {
    double yPart = 0.0, xPart = 0.0;
    for (auto a : angles) {
        xPart += cos(a * M_PI / 180);
        yPart += sin(a * M_PI / 180);
    }
    return atan2(yPart / angles.size(), xPart / angles.size()) * 180 / M_PI;
}

int main() {
    std::vector<double> tv;
    tv.push_back(timeToDegrees({ 23, 0, 17 }));
    tv.push_back(timeToDegrees({ 23, 40, 20 }));
    tv.push_back(timeToDegrees({ 0, 12, 45 }));
    tv.push_back(timeToDegrees({ 0, 17, 19 }));

    double ma = meanAngle(tv);
    auto mt = degreesToTime(ma);
    std::cout << mt << '\n';

    return 0;
}









Fortran: program mean_time_of_day
  implicit none
  integer(kind=4), parameter :: dp = kind(0.0d0)

  type time_t
    integer(kind=4) :: hours, minutes, seconds
  end type

  character(len=8), dimension(4), parameter :: times = &
    (/ '23:00:17', '23:40:20', '00:12:45', '00:17:19' /)
  real(kind=dp), dimension(size(times)) :: angles
  real(kind=dp) :: mean

  angles = time_to_angle(str_to_time(times))
  mean = mean_angle(angles)
  if (mean < 0) mean = 360 + mean

  write(*, fmt='(I2.2, '':'', I2.2, '':'', I2.2)') angle_to_time(mean)
contains
  real(kind=dp) function mean_angle(angles)
    real(kind=dp), dimension(:), intent (in) :: angles
    real(kind=dp) :: x, y

    x = sum(sin(radians(angles)))/size(angles)
    y = sum(cos(radians(angles)))/size(angles)

    mean_angle = degrees(atan2(x, y))
  end function

  elemental real(kind=dp) function radians(angle)
    real(kind=dp), intent (in) :: angle
    real(kind=dp), parameter :: pi = 4d0*atan(1d0)
    radians = angle/180*pi
  end function

  elemental real(kind=dp) function degrees(angle)
    real(kind=dp), intent (in) :: angle
    real(kind=dp), parameter :: pi = 4d0*atan(1d0)
    degrees = 180*angle/pi
  end function

  elemental type(time_t) function str_to_time(str)
    character(len=*), intent (in) :: str
    
    read(str, fmt='(I2, 1X, I2, 1X, I2)') str_to_time
  end function

  elemental real(kind=dp) function time_to_angle(time) result (res)
    type(time_t), intent (in) :: time

    real(kind=dp) :: seconds
    real(kind=dp), parameter :: seconds_in_day = 24*60*60

    seconds = time%seconds + 60*time%minutes + 60*60*time%hours
    res = 360*seconds/seconds_in_day
  end function

  elemental type(time_t) function angle_to_time(angle)
    real(kind=dp), intent (in) :: angle

    real(kind=dp) :: seconds
    real(kind=dp), parameter :: seconds_in_day = 24*60*60

    seconds = seconds_in_day*angle/360d0
    angle_to_time%hours = int(seconds/60d0/60d0)
    seconds = mod(seconds, 60d0*60d0)
    angle_to_time%minutes = int(seconds/60d0)
    angle_to_time%seconds = mod(seconds, 60d0)
  end function
end program