Horizontal sundial calculations

From Rosetta Code
Jump to: navigation, search
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.

Contents

[edit] Ada

Translation of: ALGOL 68

sundial.adb:

with Ada.Text_IO;
with Ada.Numerics.Elementary_Functions;
procedure Sundial is
use Ada.Numerics.Elementary_Functions;
use Ada.Numerics;
package Float_IO is new Ada.Text_IO.Float_IO (Float);
 
Latitude, Longitude, Meridian : Float;
Latitude_Sine  : Float;
begin
Ada.Text_IO.Put ("Enter latitude: ");
Float_IO.Get (Latitude);
Ada.Text_IO.Put ("Enter longitude: ");
Float_IO.Get (Longitude);
Ada.Text_IO.Put ("Enter legal meridian: ");
Float_IO.Get (Meridian);
Ada.Text_IO.New_Line;
 
Latitude_Sine := Sin (Latitude * Pi / 180.0);
Ada.Text_IO.Put_Line
(" sine of latitude:" & Float'Image (Latitude_Sine));
Ada.Text_IO.Put_Line
(" diff longitude:" & Float'Image (Longitude - Meridian));
Ada.Text_IO.New_Line;
 
Ada.Text_IO.Put_Line
("hour, sun hour angle, dial hour line angle from 6am to 6pm");
for H in -6 .. 6 loop
declare
Hour_Angle : constant Float :=
15.0 * Float (H) - (Longitude - Meridian);
Line_Angle : constant Float :=
Arctan (Latitude_Sine * Tan (Hour_Angle * Pi / 180.0)) * 180.0 /
Pi;
begin
Ada.Text_IO.Put_Line
("HR=" &
Integer'Image (H) &
"; HRA=" &
Float'Image (Hour_Angle) &
"; HLA=" &
Float'Image (Line_Angle));
end;
end loop;
end Sundial;
Output:
Enter latitude:       -4.95
Enter longitude:      -150.5
Enter legal meridian: -150

   sine of latitude:-8.62864E-02
   diff longitude:-5.00000E-01

hour, sun hour angle, dial hour line angle from 6am to 6pm
HR=-6; HRA=-8.95000E+01; HLA= 8.42248E+01
HR=-5; HRA=-7.45000E+01; HLA= 1.72829E+01
HR=-4; HRA=-5.95000E+01; HLA= 8.33371E+00
HR=-3; HRA=-4.45000E+01; HLA= 4.84671E+00
HR=-2; HRA=-2.95000E+01; HLA= 2.79487E+00
HR=-1; HRA=-1.45000E+01; HLA= 1.27835E+00
HR= 0; HRA= 5.00000E-01; HLA=-4.31443E-02
HR= 1; HRA= 1.55000E+01; HLA=-1.37079E+00
HR= 2; HRA= 3.05000E+01; HLA=-2.90964E+00
HR= 3; HRA= 4.55000E+01; HLA=-5.01802E+00
HR= 4; HRA= 6.05000E+01; HLA=-8.67140E+00
HR= 5; HRA= 7.55000E+01; HLA=-1.84510E+01
HR= 6; HRA= 9.05000E+01; HLA= 8.42248E+01

[edit] 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.

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
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

[edit] AutoHotkey

Translation of: F#

AutoHotkey is not a command-line programming language, let me make that clear. However, in translating the F# I found that the command line really is best for this type of app. The first 3 comments in the script describe the workarounds used to interface with the commandline.

DllCall("AllocConsole")  ; Open a console window for this application
Pi := 4*ATan(1)
,Degrees := Pi/180
 
FileAppend, Enter Latitude: , CONOUT$ ; write to stdout
FileReadLine, latitude, CONIN$, 1 ; read from stdin
 
FileAppend, Enter Longitude: , CONOUT$
FileReadLine, longitude, CONIN$, 1
 
FileAppend, Enter Legal meridian: , CONOUT$
FileReadLine, meridian, CONIN$, 1
 
sineLatitude := Sin(latitude*Degrees)
FileAppend, `n, CONOUT$
FileAppend, Sine of latitude: %sineLatitude%`n, CONOUT$
FileAppend, % "Difference of Longitudes (given longitude - meridian): " . longitude-meridian . "`n", CONOUT$
FileAppend, `n, CONOUT$
 
FileAppend, Numbers from 6 AM to 6 PM:`n, CONOUT$
FileAppend, Hour`t`tSun Hour Angle`t Dial hour line angle`n, CONOUT$
 
 
hour := -7
While (++hour < 7)
{
clockHour := hour < 0 ? abs(hour) . "AM" : hour . "PM"
shr := RTrim("" . (15.0*hour - (longitude-meridian)), "0") ; RTrim() removes trailing zeroes
dhla := Atan(sineLatitude*Tan(shr*degrees))/Degrees
FileAppend, %clockhour%`t`t%shr%`t`t%dhla%`n, CONOUT$
}
MsgBox close me when done.
Output:
Enter Latitude:-4.95
Enter Longitude:-150.5
Enter Legal meridian:-150

Sine of latitude: -0.086286
Difference of Longitudes (given longitude - meridian): -0.500000

Numbers from 6 AM to 6 PM:
Hour            Sun Hour Angle   Dial hour line angle
6AM             -89.5           84.224833
5AM             -74.5           17.282934
4AM             -59.5           8.333712
3AM             -44.5           4.846709
2AM             -29.5           2.794874
1AM             -14.5           1.278353
0PM             0.5             -0.043144
1PM             15.5            -1.370788
2PM             30.5            -2.909643
3PM             45.5            -5.018023
4PM             60.5            -8.671397
5PM             75.5            -18.450999
6PM             90.5            84.224833

[edit] BBC BASIC

      INSTALL @lib$+"FNUSING"
 
INPUT "Enter latitude (degrees)  : " latitude
INPUT "Enter longitude (degrees)  : " longitude
INPUT "Enter legal meridian (degrees): " meridian
 
PRINT '" Time", "Sun hour angle", "Dial hour line angle"
 
FOR hour = 6 TO 18
hra = 15*hour - longitude + meridian - 180
hla = DEG(ATN(SIN(RAD(latitude)) * TAN(RAD(hra))))
IF ABS(hra) > 90 hla += 180 * SGN(hra * latitude)
PRINT FNusing("##.##", hour), FNusing(" ####.### ", hra), FNusing(" ####.###", hla)
NEXT hour
Output:

(note the correct negative value for time 18:00)

Enter latitude (degrees)      : -4.95
Enter longitude (degrees)     : -150.5
Enter legal meridian (degrees): -150.0

 Time     Sun hour angle      Dial hour line angle
 6.00        -89.500              84.225
 7.00        -74.500              17.283
 8.00        -59.500               8.334
 9.00        -44.500               4.847
10.00        -29.500               2.795
11.00        -14.500               1.278
12.00          0.500              -0.043
13.00         15.500              -1.371
14.00         30.500              -2.910
15.00         45.500              -5.018
16.00         60.500              -8.671
17.00         75.500             -18.451
18.00         90.500             -95.775

[edit] C

Translation of: ALGOL 68
#include <stdio.h>
#include <math.h>
 
#define PICKVALUE(TXT, VM) do { \
printf("%s: ", TXT); \
scanf("%lf", &VM); \
} while(0);

 
#if !defined(M_PI)
#define M_PI 3.14159265358979323846
#endif
 
#define DR(X) ((X)*M_PI/180.0)
#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;
}

[edit] C#

using System;
 
namespace RosettaCode
{
internal sealed class Program
{
private static void Main()
{
Func<double> getDouble = () => Convert.ToDouble(Console.ReadLine());
double h = 0, lat, lng, lme, slat, hra, hla;
 
Console.Write("Enter latitude => ");
lat = getDouble();
Console.Write("Enter longitude => ");
lng = getDouble();
Console.Write("Enter legal meridian => ");
lme = getDouble();
 
slat = Math.Sin(lat*2*Math.PI/360);
Console.WriteLine("\n sine of latitude: {0:0.000}", slat);
Console.WriteLine(" diff longitude: {0:0.000}\n", lng-lme);
Console.WriteLine("Hour, sun hour angle, dial hour line angle from 6am to 6pm");
for (h = -6; h<6; h++)
{
hra = 15*h;
hra -= lng-lme;
hla = Math.Atan(slat*Math.Tan(hra*2*Math.PI/360))*360/(2*Math.PI);
Console.WriteLine("HR= {0,7:0.000}; HRA {1,7:0.000}; HLA= {2,7:0.000}", h, hra, hla);
}
}
}
}

[edit] D

Translation of: Python
import std.stdio, std.math, std.conv, std.string;
 
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);
}
}
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

[edit] DWScript

Translation of: Java
procedure PrintSundial(lat, lng, lme : Float);
begin
PrintLn(Format('latitude:  %7.2f', [lat]));
PrintLn(Format('longitude:  %7.2f', [lng]));
PrintLn(Format('legal meridian:  %7.2f', [lme]));
 
var slat := Sin(DegToRad(lat));
 
PrintLn(Format('sine of latitude: %.3f', [slat]));
PrintLn(Format('diff longitude:  %.3f', [lng-lme]));
PrintLn('');
PrintLn('Hour, sun hour angle, dial hour line angle from 6am to 6pm');
 
var h : Integer;
for h:=-6 to 6 do begin
var hra := 15 * h - (lng - lme);
var hraRad := DegToRad(hra);
var hla :=RadToDeg(ArcTan2(Sin(hraRad)*slat, Cos(hraRad)));
PrintLn(Format('HR=%3d; HRA=%7.3f; HLA=%7.3f', [h, hra, hla]));
end
end;
 
PrintSundial(-4.95, -150.5, -150);
Output:
latitude:          -4.95
longitude:       -150.50
legal meridian:  -150.00
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=-95.775

[edit] F#

Translation of: C#
// Learn more about F# at http://fsharp.net
 
open System
 
//(degree measure)*Degrees => Radian measure
//(radian measure)/Degrees => Degree measure
let Degrees = Math.PI / 180.0
 
Console.Write("Enter latitude: ")
let latitude = Console.ReadLine() |> Double.Parse
 
Console.Write("Enter longitude: ")
let longitude = Console.ReadLine() |> Double.Parse
 
Console.Write("Enter legal meridian: ")
let meridian = Console.ReadLine() |> Double.Parse
 
let sineLatitude = Math.Sin(latitude * Degrees)
Console.WriteLine()
Console.WriteLine("Sine of latitude: {0}",sineLatitude)
Console.WriteLine("Difference of Longitudes (given longitude - meridian): {0}",longitude-meridian)
Console.WriteLine()
 
printfn "Numbers from 6 AM to 6 PM: "
printfn "Hour\t\tSun hour angle\t Dial hour line angle"
 
for hour in -6..6 do
let clockHour = if hour < 0 then String.Format("{0}AM",Math.Abs(hour)) else String.Format("{0}PM",hour)
let shr = 15.0*(float)hour - (longitude - meridian)
let dhla = Math.Atan(sineLatitude*Math.Tan(shr*Degrees))/Degrees;
Console.WriteLine("{0}\t\t{1}\t\t{2:0.000}",clockHour,shr,dhla)
done
 
//To keep the console window open, can be omitted with block comment (" (* comment *) ")
Console.WriteLine("Press any key to continue...")
Console.ReadKey() |> ignore
Example output:
Enter latitude: -4.95
Enter longitude: -150.5
Enter legal meridian: -150

Sine of latitude: -0.0862863657979234
Difference of Longitudes (given longitude - meridian): -0.5

Numbers from 6 AM to 6 PM:
Hour            Sun hour angle   Dial hour line angle
6AM             -89.5           84.225
5AM             -74.5           17.283
4AM             -59.5           8.334
3AM             -44.5           4.847
2AM             -29.5           2.795
1AM             -14.5           1.278
0PM             0.5             -0.043
1PM             15.5            -1.371
2PM             30.5            -2.910
3PM             45.5            -5.018
4PM             60.5            -8.671
5PM             75.5            -18.451
6PM             90.5            84.225
Press any key to continue...

[edit] 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 ;

[edit] Fortran

Works with: gfortran
with -fbackslash option
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

[edit] Go

package main
 
import (
"bufio"
"fmt"
"math"
"os"
"strconv"
"strings"
)
 
func getnum(prompt string) (r float64) {
in := bufio.NewReader(os.Stdin)
for {
fmt.Print(prompt)
s, err := in.ReadString('\n')
if err != nil {
fmt.Println(err)
os.Exit(-1)
}
r, err = strconv.ParseFloat(strings.TrimSpace(s), 64)
if err == nil {
break
}
fmt.Println(err)
}
return
}
 
func main() {
lat := getnum("Enter latitude => ")
lng := getnum("Enter longitude => ")
ref := getnum("Enter legal meridian => ")
slat := math.Sin(lat * math.Pi / 180)
diff := lng - ref
fmt.Println("\n sine of latitude: ", slat)
fmt.Println(" diff longitude: ", diff)
fmt.Println("\nHour, sun hour angle, dial hour line angle from 6am to 6pm")
for h := -6.; h <= 6; h++ {
hra := 15*h - diff
hla := math.Atan(slat*math.Tan(hra*math.Pi/180)) * 180 / math.Pi
fmt.Printf("%2.0f %8.3f %8.3f\n", h, hra, hla)
}
}
Output:
Enter latitude       => -4.95
Enter longitude      => -150.5
Enter legal meridian => -150

    sine of latitude:    -0.08628636579792338
    diff longitude:      -0.5

Hour, sun hour angle, dial hour line angle from 6am to 6pm
-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

[edit] 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]
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

[edit] Icon and Unicon

procedure main()
PrintSundial(-4.95, -150.5, -150);
end
 
procedure PrintSundial(lat, lng, mer )
write("latitude: ", lat,
"\nlongitude: ", lng,
"\nlegal meridian: ", mer)
 
slat := sin(dtor(lat))
 
write("sine of latitude: ",slat,
"\ndiff longitude: ", lng-mer)
write("\nHour, sun hour angle, dial hour line angle from 6am to 6pm")
 
every h := -6 to 6 do {
hraRad := dtor(hra := 15 * h - (lng - mer))
hla :=rtod(atan(sin(hraRad)*slat, cos(hraRad)))
write("HR=",
right(if h <= 0 then 12+h else h,2),
if h < 0 then "am" else "pm",
" HRA=",hra,", HLA=",hla)
}
end
Output:
latitude:        -4.95
longitude:       -150.5
legal meridian:  -150
sine of latitude: -0.08628636579792337
diff longitude:   -0.5

Hour, sun hour angle, dial hour line angle from 6am to 6pm
HR= 6am HRA=-89.5, HLA=84.22483260136025
HR= 7am HRA=-74.5, HLA=17.2829335027853
HR= 8am HRA=-59.5, HLA=8.333711921468083
HR= 9am HRA=-44.5, HLA=4.846708924373172
HR=10am HRA=-29.5, HLA=2.794873809318642
HR=11am HRA=-14.5, HLA=1.278352980919063
HR=12pm HRA=0.5, HLA=-0.04314426995813971
HR= 1pm HRA=15.5, HLA=-1.370787843187052
HR= 2pm HRA=30.5, HLA=-2.909643210076617
HR= 3pm HRA=45.5, HLA=-5.018023174356126
HR= 4pm HRA=60.5, HLA=-8.671396957302381
HR= 5pm HRA=75.5, HLA=-18.45099922256532
HR= 6pm HRA=90.5, HLA=-95.77516739863968

[edit] J

require 'trig'
atan2=: {:@*.@j. NB. arc tangent of y divided by x
 
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=.((,. (,. (atan2 *&slat)/@+.@r.&.rfd)) diff + 15&*) i:6
smoutput lbl ,: ('3.0';'7.3';'7.3') 8!:1 r
)
Example:
   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.50084.225
│ -5 │-74.50017.283
│ -4 │-59.5008.334
│ -3 │-44.5004.847
│ -2 │-29.5002.795
│ -1 │-14.5001.278
00.500 │ -0.043
115.500 │ -1.371
230.500 │ -2.910
345.500 │ -5.018
460.500 │ -8.671
575.500 │-18.451
690.500 │-95.775
└──────┴────────────────┴────────────────────┘

[edit] Java

Translation of: C
(Substitutes in atan2 for the hour line angle calculation)
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(Math.toRadians(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;
hraRad = Math.toRadians(hra);
hla = Math.toDegrees(Math.atan2(Math.sin(hraRad)*Math.sin(Math.toRadians(lat)), Math.cos(hraRad)));
System.out.printf("HR= %3d; \t HRA=%7.3f; \t HLA= %7.3f\n",
h, hra, hla);
}
}
}
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= -95.775

[edit] Liberty BASIC

Based on Algol & BBC BASIC versions. Note Liberty BASIC works in radians.

global pi
pi =3.14159265
 
input "Enter latitude (degrees)  : "; latitude ' -4.95
input "Enter longitude (degrees)  : "; longitude ' -150.5
input "Enter legal meridian (degrees): "; meridian ' -150.0
 
print
print "Time Sun hour angle Dial hour line angle"
 
for hour = 6 TO 18
hra =15 *hour - longitude +meridian -180
hla =rad2deg( atn( sin( deg2rad( latitude)) *tan( deg2rad( hra))))
if abs( hra) >90 then hla =hla +180 *sgn( hra *latitude)
print using( "##.##", hour), using("####.### ", hra), using("####.###", hla)
next hour
 
function rad2deg( theta)
rad2deg =theta *180 /pi
end function
 
function deg2rad( theta)
deg2rad =theta *pi /180
end function
 
function sgn( x)
if x >0 then sgn =1 else sgn =-1
end function
 
end

[edit]

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)
]

[edit] OCaml

Translation of: ALGOL 68
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
 
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

[edit] 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] );

[edit] 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.

[edit] Perl 6

sub postfix:<°> ($a) { $a * pi / 180 } # degrees to radians
sub postfix:<®> ($a) { $a * 180 / pi } # radians to degrees
 
my $latitude = prompt 'Enter latitude => ';
my $longitude = prompt 'Enter longitude => ';
my $meridian = prompt 'Enter legal meridian => ';
 
my $lat_sin = sin( $latitude° );
say 'Sine of latitude: ', $lat_sin.fmt("%.4f");
say 'Longitude offset: ', my $offset = $meridian - $longitude;
say '=' x 48;
say ' Hour  : Sun hour angle° : Dial hour line angle°';
 
for -6 .. 6 -> $hour {
my $sun_deg = $hour * 15 + $offset;
my $line_deg = atan2( ( sin($sun_deg°) * $lat_sin ), cos($sun_deg°) )®;
printf "%2d %s  %7.3f  %7.3f\n",
($hour + 12) % 12 || 12, ($hour < 0 ?? 'AM' !! 'PM'), $sun_deg, $line_deg;
}
Example output:
Enter latitude       => -4.95
Enter longitude      => -150.5
Enter legal meridian => -150
Sine of latitude: -0.0863
Longitude offset: 0.5
================================================
 Hour  : Sun hour angle° : Dial hour line angle°
 6 AM      -89.500              84.225
 7 AM      -74.500              17.283
 8 AM      -59.500               8.334
 9 AM      -44.500               4.847
10 AM      -29.500               2.795
11 AM      -14.500               1.278
12 PM        0.500              -0.043
 1 PM       15.500              -1.371
 2 PM       30.500              -2.910
 3 PM       45.500              -5.018
 4 PM       60.500              -8.671
 5 PM       75.500             -18.451
 6 PM       90.500             -95.775

[edit] PicoLisp

Translation of: ALGOL 68
(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))
(prinl " diff longitude: " (round (- Lng Ref)))
(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))
"; HLA="
(align 8 (round Hla)) ) ) ) ) ) )
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

[edit] PureBasic

Translation of: ALGOL 68
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
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

[edit] Python

Translation of: ALGOL 68
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))
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

[edit] Racket

Translation of: ALGOL 68

I must say, I'm a bit astonished by the fact that no one is bothered by the atan problem (HLA=84.225) that appears in the ALGOL 68 solution and all of the ones derived from it. Composing tan & atan produces the identity only in the range [-90,90], and you have to correct for angles outside of this.

Also, I apologize for the length; I added quite a bit of commenting, and I peeled things out into functions so I could test them. Hopefully, the result--though longer--is also more readable.

#lang racket
 
;; print the table for a given latitude and longitude-offset,
;; given in degrees
(define (print-table lat long-offset)
 ;; print the table header
(display
(~a " sine of latitude: "
(~r (sin (deg->rad lat)) #:precision '(= 3))
"\n"
" diff longitude: "
(~r long-offset #:precision '(= 3))
"\n\nHour, sun hour angle, dial hour line angle "
"from 6am to 6pm\n"))
 ;; print the table
(for ([h (in-range -6 7)])
(define hra (- (* 15 h) long-offset))
(define hla (to-hla lat hra))
(display (~a "HR="(pad-to 3 (~a h))"; "
"HRA="(pad-to 7 (~r hra #:precision '(= 3)))"; "
"HLA="(pad-to 7 (~r hla #:precision '(= 3)))"\n"))))
 
 
;; compute the angle on the gnomon corresponding to a
;; given angle of the sun (angles given and returned in degrees)
(define (to-hla lat ang)
(define lat-sign (cond [(< lat 0) -1] [else 1]))
 ;; move to the right quadrant for
 ;; angles outside [-90,90]
(define correction (* (cond [(< ang -90) -180]
[(> ang 90) 180]
[else 0])
lat-sign))
(+ (rad->deg (atan (* (sin (deg->rad lat))
(tan (deg->rad ang)))))
correction))
 
;; write the prompt, return the entered number
(define (prompt->num p)
(printf "~a" p)
(string->number (read-line)))
 
;; translate degrees to radians
(define (deg->rad d) (* 2 pi (/ d 360)))
 
;; translate radians to degrees
(define (rad->deg r) (* 360 (/ r (* 2 pi))))
 
;; add spaces to reach given length
(define (pad-to cols str)
(define spaces-needed (max 0 (- cols (string-length str))))
(string-append
(list->string (for/list ([i spaces-needed]) #\space))
str))
 
 
;; INPUT PARAMETERS, PRINT TABLE:
(define lat (prompt->num "Enter latitude => "))
(define lng (prompt->num "Enter longitude => "))
(define ref (prompt->num "Enter legal meridian => "))
 
(print-table lat (- lng ref))
 
;; test cases for angle conversion
(require rackunit)
(check < (to-hla 30 89) 90)
(check-= (to-hla 30 90) 90 1e-5)
(check > (to-hla 30 91) 90)
(check > (to-hla 30 -89) -90)
(check-= (to-hla 30 90) 90 1e-5)
(check < (to-hla 30 -91) -90)
(check < (to-hla -30 -89) 90)
(check-= (to-hla -30 -90) 90 1e-5)
(check > (to-hla -30 -91) 90)
(check > (to-hla -30 89) -90)
(check-= (to-hla -30 90) -90 1e-5)
(check < (to-hla -30 91) -90)
 
Output:
Welcome to DrRacket, version 5.3.3.5--2013-02-20(5eddac74/d) [3m].
Language: racket; memory limit: 512 MB.
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=-95.775
> 

[edit] 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 the trigonometric functions.

/*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 ' latitude:' right(lat,L)
say ' longitude:' right(lng,L)
say ' legal meridian:' right(mer,L)
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('',30) /*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 separator 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 /*select*/
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 /*h*/
 
call sep
exit /*stick a fork in it, we're done.*/
 
/*──────────────────────────────────subroutines─────────────────────────*/
/*looking at subroutines is like looking at saugages being made. Don't.*/
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 PI's accuracy that */
/*matches the current NUMERIC DIGITS, up to 1 million digits.*/
/*John Machin's formula is used for calculating more digits. */
 
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; parse 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
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
                               ══════════ ══════════ ════════════

[edit] Ruby

Translation of: ALGOL 68
Translation of: Python
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
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

[edit] Run BASIC

global pi
pi = 22 / 7
 
print "Enter latitude (degrees)  : "; :input latitude ' -4.95
print "Enter longitude (degrees)  : "; :input longitude ' -150.5
print "Enter legal meridian (degrees): "; :input meridian ' -150.0
 
print
print "Time Sun hour angle Dial hour line angle"
 
for hour = 6 TO 18
hra = (15 * hour) - longitude + meridian -180
hla =rad2deg( atn( sin( deg2rad( latitude)) *tan( deg2rad( hra))))
if abs( hra) >90 then hla =hla +180 *sgn( hra *latitude)
print using( "##", hour);" ";using("####.##", hra);" ";using("####.###", hla)
next hour
 
function rad2deg( theta)
rad2deg =theta *180 /pi
end function
 
function deg2rad( theta)
deg2rad =theta *pi /180
end function
 
function sgn( x)
if x >0 then sgn =1 else sgn =-1
end function
end
Output:
Enter latitude: -4.95
Enter longitude: -150.5
Enter legal meridian: -150

Time     Sun hour angle   Dial hour line angle
 6          -89.50           84.606
 7          -74.50           17.316
 8          -59.50            8.342
 9          -44.50            4.850
10          -29.50            2.796
11          -14.50            1.279
12            0.50           -0.043
13           15.50           -1.371
14           30.50           -2.911
15           45.50           -5.021
16           60.50           -8.680
17           75.50          -18.488
18           90.50          -96.224

[edit] 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;

[edit] Seed7

$ include "seed7_05.s7i";
include "float.s7i";
include "math.s7i";
 
const float: radianToDegrees is 57.295779513082320876798154814114;
const float: degreesToRadian is 0.017453292519943295769236907684883;
 
const proc: main is func
local
var float: lat is 0.0;
var float: slat is 0.0;
var float: lng is 0.0;
var float: meridian is 0.0;
var float: hla is 0.0;
var float: hra is 0.0;
var integer: h is 0;
begin
write("Enter latitude: ");
readln(lat);
write("Enter longitude: ");
readln(lng);
write("Enter legal meridian: ");
readln(meridian);
writeln;
slat := sin(degreesToRadian * lat);
writeln("sine of latitude: " <& slat digits 3);
writeln("diff longitude: " <& lng - meridian digits 3);
writeln;
writeln("Hour, sun hour angle, dial hour line angle from 6am to 6pm");
for h range -6 to 6 do
hra := 15.0 * flt(h);
hra := hra - lng + meridian;
hla := radianToDegrees * atan(slat * tan(degreesToRadian * hra));
writeln("HR= " <& h lpad 2 <& "; HRA= " <& hra digits 3 lpad 7 <&
"; HLA= " <& hla digits 3 lpad 7);
end for;
end func;
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

[edit] Smalltalk

Works with: GNU 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.
]

[edit] Tcl

Translation of: ALGOL 68
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]
}
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

[edit] x86 Assembly

Works with: nasm
Library: libc

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

	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
Personal tools
Namespaces

Variants
Actions
Community
Explore
Misc
Toolbox