Task: Horizontal sundial calculations


C++: #include <cmath>
#include <iostream>
#include <numbers>


static const double DegreesPerHour = 15.0;
static const double DegreesPerRadian = 180.0 * std::numbers::inv_pi;


struct SundialCalculation
{
  double HourAngle;
  double HourLineAngle;
};


class Sundial
{
  
  double m_sinLatitude;
  double m_timeZoneCorrection;
    
public:
  Sundial(double latitude, double longitude, double legalMeridian) noexcept
    : m_sinLatitude(sin(latitude / DegreesPerRadian))
    , m_timeZoneCorrection(legalMeridian - longitude) {}

  SundialCalculation CalculateShadow(double hoursSinceNoon) const noexcept
  {
    double hourAngle = hoursSinceNoon * DegreesPerHour + m_timeZoneCorrection;
    double hourAngleRad = hourAngle / DegreesPerRadian;
    double hlaRad = atan2(m_sinLatitude * sin(hourAngleRad), cos(hourAngleRad));
    double hourLineAngle = hlaRad * DegreesPerRadian;
    return SundialCalculation {hourAngle, hourLineAngle};
  }
};

int main()
{
  double latitude, longitude, legalMeridian;
  std::cout << "Enter latitude:";
  std::cin >> latitude;
  std::cout << "Enter longitude:";
  std::cin >> longitude;
  std::cout << "Enter legal meridian:";
  std::cin >> legalMeridian;
  
  
  const Sundial sundial(latitude, longitude, legalMeridian);
  for(int hour = -6; hour < 7; ++hour)
  {
    
    auto result = sundial.CalculateShadow(hour);

    
    auto amOrPm = hour < 0 ? "am" : "pm";
    auto hourString = std::to_string(hour < 1 ? 12 + hour : hour);
    std::cout << hourString << amOrPm << 
    " - sun hour angle:" << result.HourAngle <<
    ", dial hour line angle:" << result.HourLineAngle << "\n";
  }
}








COBOL: PROGRAM-ID. horizontal-sundial-calc.

DATA DIVISION.
WORKING-STORAGE SECTION.
01  latitude                       PIC S9(3)V9(5) COMP.
01  longitude                      PIC S9(3)V9(5) COMP.
01  legal-meridian                 PIC S9(3)V9(5) COMP.

01  lat-sine                       PIC S9(3)V9(5) COMP.
01  diff-longitude                 PIC S9(3)V9(5) COMP. 

01  lat-sine-disp                  PIC -(3)9.9(5).
01  diff-longitude-disp            PIC -(3)9.9(5).

01  hour                           PIC S9 COMP.
01  sun-hour-angle                 PIC S9(3)V9(5) COMP.
01  dial-hour-line-angle           PIC S9(3)V9(5) COMP. 

01  hour-disp                      PIC 99.
01  sun-hour-angle-disp            PIC -(3)9.9(5).
01  dial-hour-line-angle-disp      PIC -(3)9.9(5).

PROCEDURE DIVISION.
    DISPLAY "Enter latitude: " NO ADVANCING
    ACCEPT latitude
    DISPLAY "Enter longitude: " NO ADVANCING
    ACCEPT longitude
    DISPLAY "Enter legal meridian: " NO ADVANCING
    ACCEPT legal-meridian
    DISPLAY SPACE
    
    COMPUTE lat-sine, lat-sine-disp ROUNDED =
        FUNCTION SIN(latitude * 2 * FUNCTION PI / 360)
    DISPLAY "Sine of latitude: " FUNCTION TRIM(lat-sine-disp)

    SUBTRACT legal-meridian FROM longitude
        GIVING diff-longitude, diff-longitude-disp
    DISPLAY "Diff longitude: " FUNCTION TRIM(diff-longitude-disp)
    DISPLAY SPACE

    DISPLAY "Time   Sun hour angle  Dial hour line angle"
    PERFORM VARYING hour FROM -6 BY 1 UNTIL hour > 6
        COMPUTE sun-hour-angle ROUNDED = hour * 15 - diff-longitude
        COMPUTE dial-hour-line-angle ROUNDED = FUNCTION ATAN(lat-sine
            * FUNCTION TAN(sun-hour-angle * 2 * FUNCTION PI / 360))
            * 360 / (2 * FUNCTION PI)

        ADD 12 TO hour GIVING hour-disp
        MOVE sun-hour-angle TO sun-hour-angle-disp
        MOVE dial-hour-line-angle TO dial-hour-line-angle-disp
        DISPLAY hour-disp ":00 " sun-hour-angle-disp "      "
            dial-hour-line-angle-disp
    END-PERFORM
    .