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
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
<lang c>#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;
}</lang>
Fortran
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>
OCaml
<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
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
<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
<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
<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
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
<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
<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