Horizontal sundial calculations: Difference between revisions
Thundergnat (talk | contribs) (→{{header|Perl 6}}: Add Perl 6 example) |
m (→{{header|Perl 6}}: comments were backwards) |
||
Line 816: | Line 816: | ||
=={{header|Perl 6}}== |
=={{header|Perl 6}}== |
||
<lang perl6>sub postfix:<°> ($a) { $a * pi / 180 } # |
<lang perl6>sub postfix:<°> ($a) { $a * pi / 180 } # degrees to radians |
||
sub postfix:<®> ($a) { $a * 180 / pi } # |
sub postfix:<®> ($a) { $a * 180 / pi } # radians to degrees |
||
my $latitude = prompt 'Enter latitude => '; |
my $latitude = prompt 'Enter latitude => '; |
Revision as of 05:17, 30 July 2011
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.
Ada
sundial.adb: <lang Ada>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;</lang>
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
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
BBC BASIC
<lang bbcbasic> 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</lang>
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
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>
C#
<lang csharp>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); } } }
}</lang>
D
<lang d>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); }
}</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
F#
<lang fsharp> // 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
</lang> 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...
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
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>
Go
<lang 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.Atof64(strings.TrimSpace(s)) 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) }
}</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' 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
)</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 │-95.775 │ └──────┴────────────────┴────────────────────┘</lang>
Java
(Substitutes in atan2 for the hour line angle calculation)
<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; hraRad = degToRad(hra); hla = radToDeg(Math.atan2(Math.sin(hraRad)*Math.sin(degToRad(lat)), Math.cos(hraRad))); 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= -95.775
Liberty BASIC
Based on Algol & BBC BASIC versions. Note Liberty BASIC works in radians.
<lang lb> 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 </lang>
Logo
<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
<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>
Perl 6
<lang perl6>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;
}</lang> 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
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)) (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)) ) ) ) ) ) )</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
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 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; 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
<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
<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
x86 Assembly
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>