Horizontal sundial calculations

From Rosetta Code
Revision as of 17:10, 17 December 2010 by rosettacode>Gerard Schildberger (→‎{{header|REXX}}: corrected spelling error.)
Task
Horizontal sundial calculations
You are encouraged to solve this task according to the task description, using any language you may know.

A program that calculates the hour, sun hour angle, dial hour line angle from 6am to 6pm for an operator entered location.

As the example the user is prompted for a location and inputs the latitude and longitude 4°57′S 150°30′W (4.95°S 150.5°W) of Jules Verne's Lincoln Island, aka Ernest Legouve Reef). With a legal meridian of 150°W.

Wikipedia: A sundial is a device that measures time by the position of the Sun. In common designs such as the horizontal sundial, the sun casts a shadow from its style (also called its Gnomon, a thin rod or a sharp, straight edge) onto a flat surface marked with lines indicating the hours of the day. As the sun moves across the sky, the shadow-edge progressively aligns with different hour-lines on the plate. Such designs rely on the style being aligned with the axis of the Earth's rotation. Hence, if such a sundial is to tell the correct time, the style must point towards true north (not the north or south magnetic pole) and the style's angle with horizontal must equal the sundial's geographical latitude.

ALGOL 68

Works with: ALGOL 68 version Revision 1 - no extensions to language used
Works with: ALGOL 68G version Any - tested with release 1.18.0-9h.tiny
Works with: ELLA ALGOL 68 version Any (with appropriate job cards) - tested with release 1.8-8d

Example extracted - with permission for a GPL - from Simon Wheaton-Smith's Illustrating Time's Shadow web page. <lang algol68>BEGIN

 REAL lat, slat, lng, ref;
 print ( "Enter latitude       => " ); read (lat);
 print ( "Enter longitude      => " ); read (lng);
 print ( "Enter legal meridian => " ); read (ref);
 new line(stand out);
 slat := sin(lat*2*pi/360) ;
 print ( ("    sine of latitude:   ", float(slat,8,2,1), new line ) );
 print ( ("    diff longitude:     ", fixed((lng - ref),0,3), new line, new line ) );
 print ( ("Hour, sun hour angle, dial hour line angle from 6am to 6pm", new line ));
 FOR h FROM -6 TO 6
 DO
    REAL hra , hla ;              # define hour angle and hour line angle #
    hra := 15 * h ;               # hour angle is 15 times the hour #
    hra := hra - (lng - ref);     # but correct for longitude difference #
    hla := arc tan ( slat * tan(hra*2*pi/360) ) * 360 / ( 2*pi) ;
    # page 132 of a68gdoc.pdf documentationfile #
    print ("HR="+whole(h,3)+"; HRA="+fixed(hra,8,3)+"; HLA="+fixed(hla,8,3));
    new line(stand out)
 OD

END</lang> Output:

Enter latitude       => -4.95
Enter longitude      => -150.5
Enter legal meridian => -150  

    sine of latitude:   -86.3e-3
    diff longitude:     -.500

Hour, sun hour angle, dial hour line angle from 6am to 6pm
HR= -6; HRA= -89.500; HLA= +84.225
HR= -5; HRA= -74.500; HLA= +17.283
HR= -4; HRA= -59.500; HLA=  +8.334
HR= -3; HRA= -44.500; HLA=  +4.847
HR= -2; HRA= -29.500; HLA=  +2.795
HR= -1; HRA= -14.500; HLA=  +1.278
HR= +0; HRA=  +0.500; HLA=  -0.043
HR= +1; HRA= +15.500; HLA=  -1.371
HR= +2; HRA= +30.500; HLA=  -2.910
HR= +3; HRA= +45.500; HLA=  -5.018
HR= +4; HRA= +60.500; HLA=  -8.671
HR= +5; HRA= +75.500; HLA= -18.451
HR= +6; HRA= +90.500; HLA= +84.225

C

Translation of: ALGOL 68

<lang c>#include <stdio.h>

  1. include <math.h>
  1. define PICKVALUE(TXT, VM) do { \
   printf("%s: ", TXT);			\
   scanf("%lf", &VM);				\
 } while(0);
  1. if !defined(M_PI)
  2. define M_PI 3.14159265358979323846
  3. endif
  1. define DR(X) ((X)*M_PI/180.0)
  2. define RD(X) ((X)*180.0/M_PI)

int main() {

 double lat, slat, lng, ref;
 int h;
 
 PICKVALUE("Enter latitude", lat);
 PICKVALUE("Enter longitude", lng);
 PICKVALUE("Enter legal meridian", ref);
 printf("\n");
 slat = sin(DR(lat));
 printf("sine of latitude: %.3f\n", slat);
 printf("diff longitude: %.3f\n\n", lng - ref);
 
 printf("Hour, sun hour angle, dial hour line angle from 6am to 6pm\n");
 
 for(h = -6; h <= 6; h++)
 {
   double hla, hra;
   hra = 15.0*h;
   hra = hra - lng + ref;
   hla = RD(atan(slat * tan(DR(hra))));
   printf("HR= %3d;  \t  HRA=%7.3f;  \t  HLA= %7.3f\n",

h, hra, hla);

 }
 return 0;

}</lang>

D

Translation of: Python

<lang d>import std.stdio: write, writeln, writefln, readln; import std.math: sin, tan, atan, PI; import std.conv: to; import std.string: strip;

double radians(double x) { return x * (PI/180); } double degrees(double x) { return x / (PI/180); }

T input(T)(string msg) {

   write(msg);
   return to!T(readln().strip());

}

void main() {

   double lat = input!double("Enter latitude       => ");
   double lng = input!double("Enter longitude      => ");
   double lme = input!double("Enter legal meridian => ");
   writeln();
   double slat = sin(radians(lat));
   writefln("    sine of latitude:   %.3f", slat);
   writefln("    diff longitude:     %.3f", lng-lme);
   writeln();
   writeln("Hour, sun hour angle, dial hour line angle from 6am to 6pm");
   foreach (h; -6 .. 7) {
       double hra = 15 * h;
       hra -= (lng - lme);
       double hla = degrees(atan(slat * tan(radians(hra))));
       writefln("HR=%3d; HRA=%7.3f; HLA=%7.3f", h, hra, hla);
   }

}</lang> Example run:

Enter latitude       => -4.95
Enter longitude      => -150.5
Enter legal meridian => -150

    sine of latitude:   -0.086
    diff longitude:     -0.500

Hour, sun hour angle, dial hour line angle from 6am to 6pm
HR= -6; HRA=-89.500; HLA= 84.225
HR= -5; HRA=-74.500; HLA= 17.283
HR= -4; HRA=-59.500; HLA=  8.334
HR= -3; HRA=-44.500; HLA=  4.847
HR= -2; HRA=-29.500; HLA=  2.795
HR= -1; HRA=-14.500; HLA=  1.278
HR=  0; HRA=  0.500; HLA= -0.043
HR=  1; HRA= 15.500; HLA= -1.371
HR=  2; HRA= 30.500; HLA= -2.910
HR=  3; HRA= 45.500; HLA= -5.018
HR=  4; HRA= 60.500; HLA= -8.671
HR=  5; HRA= 75.500; HLA=-18.451
HR=  6; HRA= 90.500; HLA= 84.225

Forth

<lang forth>: faccept ( -- f )

 pad 32 accept pad swap >float 0= throw ;
>radians ( deg -- rad ) 180e f/ pi f* ;
>degrees ( rad -- deg ) pi f/ 180e f* ;
sundial
 cr ." Enter latitude: "
 faccept >radians fsin
 cr ." Enter longitude: "
 faccept
 cr ." Enter legal meridian: "
 faccept f-   ( sin[latitude] longitude )
 
 cr ." Hour : HourAngle , DialAngle"
 7 -6 do
   cr i . ." : "
   fover fover fnegate i 15 * s>d d>f f+
   fdup f. ." , "
   >radians ftan f* fatan >degrees f.
 loop fdrop fdrop ;</lang>

Fortran

Works with: gfortran

with -fbackslash option

<lang fortran>program SunDial

 real    :: lat, slat, lng, ref
 real    :: hra, hla
 integer :: h
 real, parameter :: pi = 3.14159265358979323846
 print *, "Enter latitude"
 read *, lat
 print *, "Enter longitude"
 read *, lng
 print *, "Enter legal meridian"
 read *, ref
 print *
 slat = sin(dr(lat))
 write(*, '(A,1F6.3)') "sine of latitude: ", slat
 write(*, '(A,1F6.3)') "diff longitude: ", lng - ref
 print *, "Hour, sun hour angle, dial hour line angle from 6am to 6pm"
 do h = -6, 6
    hra = 15.0*h
    hra = hra - lng + ref
    hla = rd( atan( slat * tan( dr(hra) ) ) )
    write(*, '(" HR= ",I3,";  \t  HRA=",F7.3,";  \t  HLA= ", F7.3)'), h, hra, hla
 end do

contains

 function dr(angle)
   real :: dr
   real, intent(in) :: angle
   dr = angle*pi/180.0
 end function dr
 function rd(angle)
   real :: rd
   real, intent(in) :: angle
   rd = angle*180.0/pi
 end function rd

end program SunDial</lang>

Haskell

<lang haskell>module Rosetta.HorSunDial where

roundDec :: Int -> Double -> Double roundDec d = (/10.0^d). fromIntegral. round. (*10.0^d)

radToDegr = ((180/pi)*) degrToRad = ((pi/180)*)

main = do

 let lat        = -4.95
     long       = -150.5
     legalMerid = -150
     sinOfLat   = sin $ degrToRad lat
     diff       = legalMerid - long
 
 putStrLn $ "Latitude         " ++ show lat
 putStrLn $ "Longitude        " ++ show long
 putStrLn $ "Legal meridian   " ++ show legalMerid
 putStrLn $ "Sine of latitude " ++ show (roundDec 6 sinOfLat)
 putStrLn $ "Diff longitude   " ++ show (-diff)
 putStrLn "hour   sun hour angle   dial hour  line angle"
 mapM_ (\h -> 

let sha = diff + 15*h dhla = radToDegr . atan. (sinOfLat *). tan $ degrToRad sha in putStrLn $ take 7 (show h ++ repeat ' ') ++ take 16 (show (roundDec 3 sha) ++ repeat ' ' ) ++ " " ++ show (roundDec 3 dhla) ) [-6,-5..6]</lang> Output:

*Rosetta.HorSunDial> main
Latitude         -4.95
Longitude        -150.5
Legal meridian   -150.0
Sine of latitude -8.6286e-2
Diff longitude   -0.5
hour   sun hour angle   dial hour  line angle
-6.0   -89.5            84.225
-5.0   -74.5            17.283
-4.0   -59.5            8.334
-3.0   -44.5            4.847
-2.0   -29.5            2.795
-1.0   -14.5            1.278
0.0    0.5              -4.3e-2
1.0    15.5             -1.371
2.0    30.5             -2.91
3.0    45.5             -5.018
4.0    60.5             -8.671
5.0    75.5             -18.451
6.0    90.5             84.225

J

<lang j>require 'trig'

horiz=: verb define

 'lat lng ref'=. y
 out=. smoutput@,&":
 'Latitude         ' out lat
 'Longitude        ' out lng
 'Legal meridian   ' out ref
 'Sine of latitude ' out slat=. sin rfd lat
 'Diff longitude   ' out -diff=. ref - lng
 lbl=.'hour  ';'sun hour angle  ';'dial hour line angle'
 r=.((,. (,. *&slat&.tan&.rfd)) diff + 15&*) i:6
 smoutput lbl ,: ('3.0';'7.3';'7.3') 8!:1 r

)</lang>

Example:

<lang j> horiz _4.95 _150.5 _150 Latitude _4.95 Longitude _150.5 Legal meridian _150 Sine of latitude _0.0862864 Diff longitude _0.5 ┌──────┬────────────────┬────────────────────┐ │hour │sun hour angle │dial hour line angle│ ├──────┼────────────────┼────────────────────┤ │ -6 │-89.500 │ 84.225 │ │ -5 │-74.500 │ 17.283 │ │ -4 │-59.500 │ 8.334 │ │ -3 │-44.500 │ 4.847 │ │ -2 │-29.500 │ 2.795 │ │ -1 │-14.500 │ 1.278 │ │ 0 │ 0.500 │ -0.043 │ │ 1 │ 15.500 │ -1.371 │ │ 2 │ 30.500 │ -2.910 │ │ 3 │ 45.500 │ -5.018 │ │ 4 │ 60.500 │ -8.671 │ │ 5 │ 75.500 │-18.451 │ │ 6 │ 90.500 │ 84.225 │ └──────┴────────────────┴────────────────────┘</lang>

Java

Translation of: C

<lang java>import java.util.Scanner; public class Sundial {

   public static void main(String[] args) {
       double lat, slat, lng, ref;
       Scanner sc = new Scanner(System.in);
       System.out.print("Enter latitude: ");
       lat = sc.nextDouble();
       System.out.print("Enter longitude: ");
       lng = sc.nextDouble();
       System.out.print("Enter legal meridian: ");
       ref = sc.nextDouble();
       System.out.println();
       slat = Math.sin(degToRad(lat));
       System.out.printf("sine of latitude: %.3f\n", slat);
       System.out.printf("diff longitude: %.3f\n\n", lng - ref);
       System.out.printf("Hour, sun hour angle, dial hour line angle from 6am to 6pm\n");
       for (int h = -6; h <= 6; h++) {
           double hla, hra;
           hra = 15.0 * h;
           hra = hra - lng + ref;
           hla = radToDeg(Math.atan(slat * Math.tan(degToRad(hra))));
           System.out.printf("HR= %3d;  \t  HRA=%7.3f;  \t  HLA= %7.3f\n",
                   h, hra, hla);
       }
   }
   private static double degToRad(double deg) {
       return deg * Math.PI / 180;
   }
   private static double radToDeg(double rad) {
       return rad * 180 / Math.PI;
   }

}</lang> Output:

Enter latitude: -4.95
Enter longitude: -150.5
Enter legal meridian: -150

sine of latitude: -0.086
diff longitude: -0.500

Hour, sun hour angle, dial hour line angle from 6am to 6pm
HR=  -6;            HRA=-89.500;            HLA=  84.225
HR=  -5;            HRA=-74.500;            HLA=  17.283
HR=  -4;            HRA=-59.500;            HLA=   8.334
HR=  -3;            HRA=-44.500;            HLA=   4.847
HR=  -2;            HRA=-29.500;            HLA=   2.795
HR=  -1;            HRA=-14.500;            HLA=   1.278
HR=   0;            HRA=  0.500;            HLA=  -0.043
HR=   1;            HRA= 15.500;            HLA=  -1.371
HR=   2;            HRA= 30.500;            HLA=  -2.910
HR=   3;            HRA= 45.500;            HLA=  -5.018
HR=   4;            HRA= 60.500;            HLA=  -8.671
HR=   5;            HRA= 75.500;            HLA= -18.451
HR=   6;            HRA= 90.500;            HLA=  84.225

<lang logo>type "|Enter latitude: | make "lat readword type "|Enter longitude: | make "long readword type "|Enter legal meridian: | make "long :long - readword

print [Hour : HourAngle , DialAngle] for [hour -6 6] [

  make "hra 15 * :hour - :long
  make "hla arctan product sin :lat quotient sin :hra cos :hra
  print (sentence "hour :hour ": :hra ", :hla)

]</lang>

OCaml

Translation of: ALGOL 68

<lang ocaml>let () =

 let pi = 4. *. atan 1. in
 print_endline "Enter latitude		=> ";
 let lat = read_float () in
 print_endline "Enter longitude	=> ";
 let lng = read_float () in
 print_endline "Enter legal meridian	=> ";
 let ref = read_float () in
 print_newline ();
 
 let slat = sin (lat *. 2. *. pi /. 360.) in
 Printf.printf "    sine of latitude:   %.3f\n" slat;
 Printf.printf "    diff longitude:     %.3f\n" (lng -. ref);
 print_newline ();
 
 print_endline "Hour, sun hour angle, dial hour line angle from 6am to 6pm";
 
 for h = -6 to 6 do
   let hra = 15. *. float h in
   let hra = hra -. (lng -. ref) in
   let hla = atan (slat *. tan (hra *. 2. *. pi /. 360.)) *. 360. /. (2. *. pi) in
   Printf.printf "HR= %3d;  \t  HRA=%7.3f;  \t  HLA= %7.3f\n" h hra hla;
 done

</lang>

Output:

Enter latitude		=> 
-4.95
Enter longitude	=> 
-150.5
Enter legal meridian	=> 
-150.

    sine of latitude:   -0.086
    diff longitude:     -0.500

Hour, sun hour angle, dial hour line angle from 6am to 6pm
HR=  -6;  	  HRA=-89.500;  	  HLA=  84.225
HR=  -5;  	  HRA=-74.500;  	  HLA=  17.283
HR=  -4;  	  HRA=-59.500;  	  HLA=   8.334
HR=  -3;  	  HRA=-44.500;  	  HLA=   4.847
HR=  -2;  	  HRA=-29.500;  	  HLA=   2.795
HR=  -1;  	  HRA=-14.500;  	  HLA=   1.278
HR=   0;  	  HRA=  0.500;  	  HLA=  -0.043
HR=   1;  	  HRA= 15.500;  	  HLA=  -1.371
HR=   2;  	  HRA= 30.500;  	  HLA=  -2.910
HR=   3;  	  HRA= 45.500;  	  HLA=  -5.018
HR=   4;  	  HRA= 60.500;  	  HLA=  -8.671
HR=   5;  	  HRA= 75.500;  	  HLA= -18.451
HR=   6;  	  HRA= 90.500;  	  HLA=  84.225

Octave

<lang octave>lat = input("Enter latitude: "); lng = input("Enter longitude: "); ref = input("Enter legal meridian: "); slat = sind(lat); printf("sine of latitude: %.3f\n", slat); printf("diff longitude: %.3f\n\n", lng - ref); printf("Hour, sun hour angle, dial hour line angle from 6am to 6pm\n");

hras = [-6:6] .* 15.0 .- lng .+ ref; hlas = atand( tand(hras) .* slat ); printf("HR= %3d; \t HRA=%7.3f; \t HLA= %7.3f\n",

      [ [-6:6]; hras; hlas] );</lang>

Pascal

<lang pascal>Program SunDial;

Const

  pi  = 3.14159265358979323846;
  dr  = pi/180.0;
  rd  = 180.0/pi;
  tab =  chr(9);

Var

  lat, slat, lng, ref : Real;
  hla, hra	       : Real;
  h		       : Integer;

function tan(val : Real) : Real; begin

  tan := sin(val)/cos(val)

end;

Begin

  Write('Enter latitude: '); Read(lat);
  Write('Enter longitude: '); Read(lng);
  Write('Enter legal meridian: '); Read(ref);
  WriteLn;
  slat := sin(lat * dr);
  WriteLn('sine of latitude: ', slat);
  WriteLn('diff longitude: ', lng - ref);
  WriteLn('Hour, sun hour angle, dial hour line angle from 6am to 6pm');
  for h := -6 to 6 do begin
     hra := 15.0 * h;
     hra := hra - lng + ref;
     hla := arctan(slat * tan(hra * dr)) * rd;
     WriteLn('HR= ', h:3, ';  ',

tab, ' HRA= ', hra:7:3, '; ', tab, ' HLA= ', hla:7:3)

  end

end.</lang>

PicoLisp

Translation of: ALGOL 68

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

(de prompt (Str . Arg)

  (prin Str " => ")
  (set (car Arg) (in NIL (read))) )

(use (Lat Lng Ref)

  (prompt "Enter latitude      " Lat)
  (prompt "Enter longitude     " Lng)
  (prompt "Enter legal meridian" Ref)
  (prinl)
  (let Slat (sin (*/ Lat pi 180.0))
     (prinl "    sine of latitude:   " (round Slat 3))
     (prinl "    diff longitude:     " (round (- Lng Ref) 3))
     (prinl)
     (prinl "Hour, sun hour angle, dial hour line angle from 6am to 6pm")
     (for H (range -6 6)
        (let Hra (- (* 15.0 H) (- Lng Ref))
           (let Hla (*/ (atan (*/ Slat (tan (*/ Hra pi 180.0)) 1.0)) 180.0 pi)
              (prinl
                 "HR="
                 (align 3 H)
                 "; HRA="
                 (align 8 (round Hra 3))
                 "; HLA="
                 (align 8 (round Hla 3)) ) ) ) ) ) )</lang>

Output:

Enter latitude       => -4.95
Enter longitude      => -150.5
Enter legal meridian => -150.          # Don't omit the '.' here

    sine of latitude:   -0.086
    diff longitude:     -0.500

Hour, sun hour angle, dial hour line angle from 6am to 6pm
HR= -6; HRA= -89.500; HLA=  84.225
HR= -5; HRA= -74.500; HLA=  17.283
HR= -4; HRA= -59.500; HLA=   8.334
HR= -3; HRA= -44.500; HLA=   4.847
HR= -2; HRA= -29.500; HLA=   2.795
HR= -1; HRA= -14.500; HLA=   1.278
HR=  0; HRA=   0.500; HLA=  -0.043
HR=  1; HRA=  15.500; HLA=  -1.371
HR=  2; HRA=  30.500; HLA=  -2.910
HR=  3; HRA=  45.500; HLA=  -5.018
HR=  4; HRA=  60.500; HLA=  -8.671
HR=  5; HRA=  75.500; HLA= -18.451
HR=  6; HRA=  90.500; HLA=  84.225

PureBasic

Translation of: ALGOL 68

<lang PureBasic>If OpenConsole()

 Define.f lat, slat, lng, ref
 Define.i h
 Print("Enter latitude       => "): lat=ValF(Input())
 Print("Enter longitude      => "): lng=ValF(Input())
 Print("Enter legal meridian => "): ref=ValF(Input())
 PrintN("")
 
 slat=Sin(lat*2*#PI/360)
 PrintN("    sine of latitude:   "+StrF(slat,3))
 PrintN("    diff longitude:     "+StrF((lng-ref),3)+#CRLF$)
 PrintN("Hour, sun hour angle, dial hour line angle from 6am to 6pm")
 
 For h=-6 To 6
   Define.f hra, hla
   hra=15*h
   hra=hra-(lng-ref)
   hla=ATan(slat*Tan(hra*2*#PI/360))*360/(2*#PI)
   PrintN("HR="+RSet(Str(h),3)+"; HRA="+RSet(StrF(hra,3),7)+"; HLA="+RSet(StrF(hla,3),7))
 Next
 

EndIf</lang>

Enter latitude       => -4.95
Enter longitude      => -150.5
Enter legal meridian => -150

    sine of latitude:   -0.086
    diff longitude:     -0.500

Hour, sun hour angle, dial hour line angle from 6am to 6pm
HR= -6; HRA=-89.500; HLA= 84.225
HR= -5; HRA=-74.500; HLA= 17.283
HR= -4; HRA=-59.500; HLA=  8.334
HR= -3; HRA=-44.500; HLA=  4.847
HR= -2; HRA=-29.500; HLA=  2.795
HR= -1; HRA=-14.500; HLA=  1.278
HR=  0; HRA=  0.500; HLA= -0.043
HR=  1; HRA= 15.500; HLA= -1.371
HR=  2; HRA= 30.500; HLA= -2.910
HR=  3; HRA= 45.500; HLA= -5.018
HR=  4; HRA= 60.500; HLA= -8.671
HR=  5; HRA= 75.500; HLA=-18.451
HR=  6; HRA= 90.500; HLA= 84.225

Python

Translation of: ALGOL 68

<lang python>from __future__ import print_function import math try: raw_input except: raw_input = input

lat = float(raw_input("Enter latitude => ")) lng = float(raw_input("Enter longitude => ")) ref = float(raw_input("Enter legal meridian => ")) print()

slat = math.sin(math.radians(lat)) print(" sine of latitude:  %.3f" % slat) print(" diff longitude:  %.3f" % (lng-ref)) print() print("Hour, sun hour angle, dial hour line angle from 6am to 6pm")

for h in range(-6, 7):

 hra = 15 * h
 hra -= lng - ref
 hla = math.degrees(math.atan(slat * math.tan(math.radians(hra))))
 print("HR=%3d; HRA=%7.3f; HLA=%7.3f" % (h, hra, hla))</lang>
Enter latitude       => -4.95
Enter longitude      => -150.5
Enter legal meridian => -150

    sine of latitude:   -0.086
    diff longitude:     -0.500

Hour, sun hour angle, dial hour line angle from 6am to 6pm
HR= -6; HRA=-89.500; HLA= 84.225
HR= -5; HRA=-74.500; HLA= 17.283
HR= -4; HRA=-59.500; HLA=  8.334
HR= -3; HRA=-44.500; HLA=  4.847
HR= -2; HRA=-29.500; HLA=  2.795
HR= -1; HRA=-14.500; HLA=  1.278
HR=  0; HRA=  0.500; HLA= -0.043
HR=  1; HRA= 15.500; HLA= -1.371
HR=  2; HRA= 30.500; HLA= -2.910
HR=  3; HRA= 45.500; HLA= -5.018
HR=  4; HRA= 60.500; HLA= -8.671
HR=  5; HRA= 75.500; HLA=-18.451
HR=  6; HRA= 90.500; HLA= 84.225

REXX

REXX doesn't have the usual trig functions, nor for that matter, a SQRT (square root) function, so these as well as PI were added to this program.

No attempt was made to explain the inner workings of these functions. <lang rexx>/*REXX program shows hour/sun hour angle/dial hour line angle, 6am->6pm.*/

numeric digits 60 /*better overkill then underkill. */

parse arg lat lng mer . /*get the arguments (if any). */

                                     /*If none specified, then use the */
                                     /*default of Jules Verne's Lincoln*/
                                     /*Island, aka Ernest Legouve Reef.*/

if lat== | lat==',' then lat=-4.95 /*No argument? Then use default.*/ if lng== | lng==',' then lng=-150.5 /*No argument? Then use default.*/ if mer== | mer==',' then mer=-150 /*No argument? Then use default.*/ L=max(length(lat),length(lng),length(mer)) say; say ' latitude:' right(lat,L)

     say '      longitude:' right(lng,L)
     say ' legal meridian:' right(mer,L);  say;  say

sineLat=sin(d2r(lat)) w1=max(length('hour'),length('midnight'))+2 w2=max(length('sun hour') ,length('angle'))+2 w3=max(length('dial hour'),length('line angle'))+2 indent=left(,25) /*make presentation prettier. */ say indent center(' ',w1) center('sun hour',w2) center('dial hour' ,w3) say indent center('hour',w1) center('angle' ,w2) center('line angle',w3) call sep /*add seperator line for eyeballs*/

     do h=-6 to 6                     /*Okey dokey then, let's get busy*/
          select
          when abs(h)==12 then hc='midnight'    /*above artic circle ? */
          when h<0  then hc=-h 'am'   /*convert hour for human beans.  */
          when h==0 then hc='noon'    /*  ... easy to understand now.  */
          when h>0  then hc=h 'pm'    /*  ... even meaningfull.        */
          end
     hra=15*h-lng+mer
     hla=r2d(Atan(sineLat*tan(d2r(hra))))
     say indent center(hc,w1) right(format(hra,,1),w2) right(format(hla,,1),w3)
     end

call sep exit

/*looking at subroutines is like looking at saugages being made. Don't.*/

/*─────────────────────────────────────subroutines──────────────────────*/ sep: say indent copies('=',w1) copies('=',w2) copies('=',w3); return

pi: return, /*a bit of overkill, but hey !! */ 3.1415926535897932384626433832795028841971693993751058209749445923078164062862

                                      /*Note:  the real  PI  subroutine*/ 
                                      /*returns the number of digits   */
                                      /*that matches the current       */
                                      /*NUMERIC DIGITS     ----- up to */    
                                      /*1 million+  digits.  Past that,*/
                                      /*it calculates more digits via  */
                                      /*John Machin's formula.         */

d2d: return arg(1)//360 /*normalize degrees►1 unit circle*/ d2r: return r2r(arg(1)*pi()/180) /*convert degrees ──► radians. */ r2d: return d2d((arg(1)*180/pi())) /*convert radians ──► degrees. */ r2r: return arg(1)//(2*pi()) /*normalize radians►1 unit circle*/ tan: procedure; arg x; _=cos(x); if _=0 then call tanErr; return sin(x)/_ tanErr: call tellErr 'tan('||x") causes division by zero, X="||x tellErr: say; say '*** error! ***'; say; say arg(1); say; exit 13 AsinErr: call tellErr 'Asin(x), X must be in the range of -1 --> +1, X='||x sqrtErr: call tellErr "sqrt(x), X can't be negative, X="||x AcosErr: call tellErr 'Acos(x), X must be in the range of -1 --> +1, X='||x Acos: procedure; arg x; if x<-1|x>1 then call AcosErr; return .5*pi()-Asin(x)

Atan: procedure; arg x; if abs(x)=1 then return pi()/4*sign(x)

                                        return Asin(x/sqrt(1+x**2))

sin: procedure; arg x; x=r2r(x); numeric fuzz min(5,digits()-3);

               if abs(x)=pi() then return 0;   return sinCos(x,x,1)

cos: procedure; arg x; x=r2r(x); a=abs(x); numeric fuzz min(9,digits()-9);

               if a=pi() then return -1; if a=pi()/2 | a=2*pi() then return 0;
               if a=pi()/3 then return .5; if a=2*pi()/3 then return -.5;
               return sincos(1,1,-1)

sinCos: parse arg z,_,i; x=x*x; p=z;

       do k=2 by 2; _=-_*x/(k*(k+i));z=z+_; if z=p then leave;p=z;end; return z

Asin: procedure; arg x; if x<-1 | x>1 then call AsinErr; s=x*x;

     if abs(x)>=.7 then return sign(x)*Acos(sqrt(1-s));  z=x;  o=x;  p=z;
     do j=2 by 2; o=o*s*(j-1)/j; z=z+o/(j+1); if z=p then leave; p=z; end;
     return z

sqrt: procedure; parse arg x; if x=0 then return 0;d=digits();numeric digits 11;

     g=sqrtGuess();       do j=0 while p>9;  m.j=p;  p=p%2+1;   end;
     do k=j+5 to 0 by -1; if m.k>11 then numeric digits m.k; g=.5*(g+x/g); end;
     numeric digits d;  return g/1

sqrtGuess: if x<0 then call sqrtErr; numeric form scientific; m.=11; p=d+d%4+2;

          parse value format(x,2,1,,0) 'E0' with g 'E' _ .;   return g*.5'E'_%2</lang>

Output:

       latitude:  -4.95
      longitude: -150.5
 legal meridian:   -150


                                      sun hour   dial hour
                             hour      angle     line angle
                          ========== ========== ============
                             6 am         -89.5         84.2
                             5 am         -74.5         17.3
                             4 am         -59.5          8.3
                             3 am         -44.5          4.8
                             2 am         -29.5          2.8
                             1 am         -14.5          1.3
                             noon           0.5          0.0
                             1 pm          15.5         -1.4
                             2 pm          30.5         -2.9
                             3 pm          45.5         -5.0
                             4 pm          60.5         -8.7
                             5 pm          75.5        -18.5
                             6 pm          90.5         84.2
                          ========== ========== ============

Ruby

Translation of: ALGOL 68
Translation of: Python

<lang ruby>include Math DtoR = PI/180

print 'Enter latitude: ' lat = Float( gets ) print 'Enter longitude: ' lng = Float( gets ) print 'Enter legal meridian: ' ref = Float( gets ) puts

slat = sin( lat * DtoR )

puts " sine of latitude:  %.3f"% slat puts " diff longitude:  %.3f"% (lng-ref) puts puts 'Hour, sun hour angle, dial hour line angle from 6am to 6pm' -6.upto(6) do |h|

 hra = 15 * h
 hra -= lng - ref
 hla =  atan( slat * tan( hra * DtoR ))/ DtoR 
 puts "HR =%3d; HRA =%7.3f; HLA =%7.3f" % [h, hra, hla]

end</lang>

Enter latitude: -4.95
Enter longitude: -150.5
Enter legal meridian: -150

    sine of latitude:  -0.086
    diff longitude:    -0.500

Hour, sun hour angle, dial hour line angle from 6am to 6pm
HR = -6; HRA =-89.500; HLA = 84.225
HR = -5; HRA =-74.500; HLA = 17.283
HR = -4; HRA =-59.500; HLA =  8.334
HR = -3; HRA =-44.500; HLA =  4.847
HR = -2; HRA =-29.500; HLA =  2.795
HR = -1; HRA =-14.500; HLA =  1.278
HR =  0; HRA =  0.500; HLA = -0.043
HR =  1; HRA = 15.500; HLA = -1.371
HR =  2; HRA = 30.500; HLA = -2.910
HR =  3; HRA = 45.500; HLA = -5.018
HR =  4; HRA = 60.500; HLA = -8.671
HR =  5; HRA = 75.500; HLA =-18.451
HR =  6; HRA = 90.500; HLA = 84.225

Sather

<lang sather>class MAIN is

 getvalue(s:STR):FLT is
   #OUT + s + ": ";
   return #FLT(#IN.get_line.str);
 end;
 dr(a:FLT):FLT is
   return a * FLT::pi / 180.0;
 end;
 rd(a:FLT):FLT is
   return a * 180.0 / FLT::pi;
 end;
 main is
   lat ::= getvalue("Enter latitude");
   lng ::= getvalue("Enter longitude");
   ref ::= getvalue("Enter legal meridian");
   #OUT + "\n";
   slat ::= dr(lat).sin;
   #OUT + "sine of latitude: " + #FMT("%.3f\n", slat);
   #OUT + "diff longitude: " + #FMT("%.3f\n\n", lng - ref);
   #OUT + "Hour, sun hour angle, dial hour line angle from 6am to 6pm\n";
   loop h ::= (-6).upto!(6);
     hra ::= 15.0 * h.flt;
     hra := hra - lng + ref;
     hla ::= rd((dr(hra).tan * slat).atan);
     #OUT + #FMT("HR = %3d;  \t  HRA=%7.3f;  \t  HLA= %7.3f\n", h, hra, hla);
   end;
 end;

end;</lang>

Smalltalk

Works with: GNU Smalltalk

<lang smalltalk>|lat slat lng ref hra hla pi| pi := 1 arcTan * 4. 'Enter latitude: ' display. lat := stdin nextLine asNumber. 'Enter longitude: ' display. lng := stdin nextLine asNumber. 'Enter legal meridian: ' display. ref := stdin nextLine asNumber. slat := lat degreesToRadians sin. ('sine of latitude: %1' % { slat }) displayNl. ('diff longitude: %1' % { lng - ref }) displayNl.

'Hour, sun hour angle, dial hour line angle from 6am to 6pm' displayNl.

-6 to: 6 do: [ :h |

 hra := 15.0 * h.
 hra := hra - lng + ref.
 hla := (hra degreesToRadians tan * slat) arcTan radiansToDegrees.
 ('HR= %1;  %4  HRA=%2;  %4  HLA= %3' % { h. hra. hla. $<9> }) displayNl.

]</lang>

Tcl

Translation of: ALGOL 68

<lang tcl>set PI 3.1415927 fconfigure stdout -buffering none puts -nonewline "Enter latitude => "; gets stdin lat puts -nonewline "Enter longitude => "; gets stdin lng puts -nonewline "Enter legal meridian => "; gets stdin ref puts ""

set slat [expr {sin($lat*$PI/180)}] puts [format " sine of latitude: %8g" $slat] puts [format " diff longitude: %3.3f" [expr {$lng - $ref}]] puts "" puts "Hour, sun hour angle, dial hour line angle from 6am to 6pm"

for {set h -6} {$h<=6} {incr h} {

   set hra [expr {15.0 * $h}];      # hour angle is 15 times the hour #
   set hra [expr {$hra-$lng+$ref}]; # but correct for longitude difference #
   set hla [expr {atan($slat * tan($hra*$PI/180)) * 180/$PI}]
   puts [format "HR=%+3d; HRA=%+8.3f; HLA=%+8.3f" $h $hra $hla]

}</lang> Sample output:

Enter latitude       => -4.95
Enter longitude      => -150.5
Enter legal meridian => -150

    sine of latitude:   -0.0862864
    diff longitude:     -0.500

Hour, sun hour angle, dial hour line angle from 6am to 6pm
HR= -6; HRA= -89.500; HLA= +84.225
HR= -5; HRA= -74.500; HLA= +17.283
HR= -4; HRA= -59.500; HLA=  +8.334
HR= -3; HRA= -44.500; HLA=  +4.847
HR= -2; HRA= -29.500; HLA=  +2.795
HR= -1; HRA= -14.500; HLA=  +1.278
HR= +0; HRA=  +0.500; HLA=  -0.043
HR= +1; HRA= +15.500; HLA=  -1.371
HR= +2; HRA= +30.500; HLA=  -2.910
HR= +3; HRA= +45.500; HLA=  -5.018
HR= +4; HRA= +60.500; HLA=  -8.671
HR= +5; HRA= +75.500; HLA= -18.451
HR= +6; HRA= +90.500; HLA= +84.225

x86 Assembly

Works with: nasm
Library: libc

It must be linked with the C standard library and startup code.

<lang asm> global main extern printf, scanf

section .text

getvalue: push edx push eax call printf add esp, 4 push in_ft call scanf add esp, 8 ret

st0dr: fld qword [drfact] fmul ret


main: lea eax, [lat_t] lea edx, [lat] call getvalue lea eax, [lng_t] lea edx, [lng] call getvalue lea eax, [ref_t] lea edx, [ref] call getvalue

push newline call printf add esp, 4

fld qword [lat] call st0dr fsin fst qword [slat]

sub esp, 8 fstp qword [esp] push sin_ft call printf add esp, 12

fld qword [lng] fld qword [ref] fsubr st0, st1 sub esp, 8 fstp qword [esp] push diff_ft call printf add esp, 12

push tab_t call printf add esp, 4

mov ecx, -6 .loop: cmp ecx, 6 jg .endloop

push ecx fild dword [esp] fld qword [xv] fmulp fld qword [lng] fsubp fld qword [ref] faddp pop ecx

sub esp, 20 mov dword [esp], ecx fst qword [esp+4]

call st0dr

fptan fxch fld qword [slat] fmulp fxch fpatan

fld qword [rdinv] fmul

fstp qword [esp+12]

push o_ft call printf mov ecx, [esp+4] add esp, 24

inc ecx jmp .loop .endloop:

xor eax, eax ret


section .data

lat: dq 0.0 lng: dq 0.0 ref: dq 0.0 xv: dq 15.0 slat: dq 0.0 drfact: dq 0.01745329251994329576 rdinv: dq 57.29577951308232090712


section .rodata

lat_t: db "Enter latitude: ", 0 lng_t: db "Enter longitude: ", 0 ref_t: db "Enter legal meridian: ", 0

in_ft: db "%lf", 0 newline: db 10, 0

sin_ft: db "sine of latitude: %.3f", 10, 0 diff_ft: db "diff longitude: %.3f", 10, 10, 0

tab_t: db "Hour, sun hour angle, dial hour line angle from 6am to 6pm", 10, 0

o_ft: db "HR= %3d; ",9," HRA=%7.3f; ",9," HLA= %7.3f", 10, 0</lang>