15
\$\begingroup\$

Ptolemy's Almagest contains a table of chords that effectively served as the world's only comprehensive trigonometric table for over a millennium. In modern form it looks like this:

\begin{array}{|l|rrr|rrr|} \hline {}\,\,\,\,\,\,\,\,\,\, \tfrac12 & 0 & 31 & 25 & 1 & 2 & 50 \\ {}\,\,\,\,\,\,\, 1 & 1 & 2 & 50 & 1 & 2 & 50 \\ {}\,\,\,\,\,\,\, 1\tfrac12 & 1 & 34 & 15 & 1 & 2 & 50 \\ {}\,\,\,\,\,\,\, \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots \\ 109 & 97 & 41 & 38 & 0 & 36 & 23 \\ 109\tfrac12 & 97 & 59 & 49 & 0 & 36 & 9 \\ 110 & 98 & 17 & 54 & 0 & 35 & 56 \\ 110\tfrac12 & 98 & 35 & 52 & 0 & 35 & 42\\ 111 & 98 & 53 & 43 & 0 & 35 & 29 \\ 111\tfrac12 & 99 & 11 & 27 & 0 & 35 & 15 \\ 112 & 99 & 29 & 5 & 0 & 35 & 1\\ 112\tfrac12 & 99 & 46 & 35 & 0 & 34 & 48 \\ 113 & 100 & 3 & 59 & 0 & 34 & 34 \\ {}\,\,\,\,\,\,\, \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots \\ 179 & 119 & 59 & 44 & 0 & 0 & 25 \\ 179\frac12 & 119 & 59 & 56 & 0 & 0 & 9 \\ 180 & 120 & 0 & 0 & 0 & 0 & 0 \\ \hline \end{array}

The table has 360 lines, each in the following format:

  • An angle \$\theta\$ in degrees, ranging from ½° to 180° inclusive in ½° increments.
  • The chord length subtended by \$\theta\$ in a circle of radius 60. This length is equal to \$c(\theta)=120\sin\frac\theta2\$ and is given as three numbers: the integer part comes first and the first and second sexagesimal (base 60) digits follow.
  • A "sixtieths" column used for linear interpolation, giving \$\frac{c(\theta+1/2^\circ)-c(\theta)}{30}\$. This follows a similar format to the chords column but lists three sexagesimal digits; the integer part is always 0 and has been omitted in the table above for brevity (it was written out in the original). Also note that 0 appears in this column at 180° instead of a negative value as the formula would imply.

Task

Output all 360 lines of the table, each containing seven numbers – without the zero integer parts of the sixtieths column – as described above:

0.5 [0, 31, 25] [1, 2, 50]
1.0 [1, 2, 50] [1, 2, 50]
1.5 [1, 34, 15] [1, 2, 49]
2.0 [2, 5, 39] [1, 2, 49]
2.5 [2, 37, 4] [1, 2, 49]
3.0 [3, 8, 28] [1, 2, 48]
3.5 [3, 39, 53] [1, 2, 48]
4.0 [4, 11, 17] [1, 2, 47]
4.5 [4, 42, 40] [1, 2, 47]
5.0 [5, 14, 4] [1, 2, 46]
5.5 [5, 45, 27] [1, 2, 45]
6.0 [6, 16, 49] [1, 2, 44]
6.5 [6, 48, 11] [1, 2, 43]
7.0 [7, 19, 33] [1, 2, 42]
7.5 [7, 50, 54] [1, 2, 41]
8.0 [8, 22, 15] [1, 2, 40]
8.5 [8, 53, 35] [1, 2, 39]
9.0 [9, 24, 54] [1, 2, 38]
9.5 [9, 56, 13] [1, 2, 36]
10.0 [10, 27, 31] [1, 2, 35]
10.5 [10, 58, 49] [1, 2, 33]
11.0 [11, 30, 5] [1, 2, 32]
11.5 [12, 1, 21] [1, 2, 30]
12.0 [12, 32, 36] [1, 2, 28]
12.5 [13, 3, 50] [1, 2, 27]
13.0 [13, 35, 4] [1, 2, 25]
13.5 [14, 6, 16] [1, 2, 23]
14.0 [14, 37, 28] [1, 2, 21]
14.5 [15, 8, 38] [1, 2, 19]
15.0 [15, 39, 47] [1, 2, 17]
15.5 [16, 10, 56] [1, 2, 14]
16.0 [16, 42, 3] [1, 2, 12]
16.5 [17, 13, 9] [1, 2, 10]
17.0 [17, 44, 14] [1, 2, 7]
17.5 [18, 15, 17] [1, 2, 5]
18.0 [18, 46, 20] [1, 2, 2]
18.5 [19, 17, 21] [1, 2, 0]
19.0 [19, 48, 21] [1, 1, 57]
19.5 [20, 19, 19] [1, 1, 54]
20.0 [20, 50, 16] [1, 1, 51]
20.5 [21, 21, 12] [1, 1, 48]
21.0 [21, 52, 6] [1, 1, 45]
21.5 [22, 22, 58] [1, 1, 42]
22.0 [22, 53, 49] [1, 1, 39]
22.5 [23, 24, 39] [1, 1, 36]
23.0 [23, 55, 27] [1, 1, 33]
23.5 [24, 26, 13] [1, 1, 29]
24.0 [24, 56, 58] [1, 1, 26]
24.5 [25, 27, 41] [1, 1, 22]
25.0 [25, 58, 22] [1, 1, 19]
25.5 [26, 29, 1] [1, 1, 15]
26.0 [26, 59, 39] [1, 1, 11]
26.5 [27, 30, 15] [1, 1, 8]
27.0 [28, 0, 48] [1, 1, 4]
27.5 [28, 31, 20] [1, 1, 0]
28.0 [29, 1, 50] [1, 0, 56]
28.5 [29, 32, 18] [1, 0, 52]
29.0 [30, 2, 44] [1, 0, 48]
29.5 [30, 33, 8] [1, 0, 44]
30.0 [31, 3, 30] [1, 0, 39]
30.5 [31, 33, 49] [1, 0, 35]
31.0 [32, 4, 7] [1, 0, 31]
31.5 [32, 34, 22] [1, 0, 26]
32.0 [33, 4, 35] [1, 0, 22]
32.5 [33, 34, 46] [1, 0, 17]
33.0 [34, 4, 55] [1, 0, 12]
33.5 [34, 35, 1] [1, 0, 8]
34.0 [35, 5, 5] [1, 0, 3]
34.5 [35, 35, 6] [0, 59, 58]
35.0 [36, 5, 5] [0, 59, 53]
35.5 [36, 35, 1] [0, 59, 48]
36.0 [37, 4, 55] [0, 59, 43]
36.5 [37, 34, 47] [0, 59, 38]
37.0 [38, 4, 36] [0, 59, 32]
37.5 [38, 34, 22] [0, 59, 27]
38.0 [39, 4, 5] [0, 59, 22]
38.5 [39, 33, 46] [0, 59, 16]
39.0 [40, 3, 25] [0, 59, 11]
39.5 [40, 33, 0] [0, 59, 5]
40.0 [41, 2, 33] [0, 59, 0]
40.5 [41, 32, 3] [0, 58, 54]
41.0 [42, 1, 30] [0, 58, 48]
41.5 [42, 30, 54] [0, 58, 42]
42.0 [43, 0, 15] [0, 58, 37]
42.5 [43, 29, 33] [0, 58, 31]
43.0 [43, 58, 49] [0, 58, 25]
43.5 [44, 28, 1] [0, 58, 18]
44.0 [44, 57, 10] [0, 58, 12]
44.5 [45, 26, 16] [0, 58, 6]
45.0 [45, 55, 19] [0, 58, 0]
45.5 [46, 24, 19] [0, 57, 53]
46.0 [46, 53, 16] [0, 57, 47]
46.5 [47, 22, 9] [0, 57, 41]
47.0 [47, 51, 0] [0, 57, 34]
47.5 [48, 19, 47] [0, 57, 27]
48.0 [48, 48, 30] [0, 57, 21]
48.5 [49, 17, 11] [0, 57, 14]
49.0 [49, 45, 47] [0, 57, 7]
49.5 [50, 14, 21] [0, 57, 0]
50.0 [50, 42, 51] [0, 56, 53]
50.5 [51, 11, 18] [0, 56, 46]
51.0 [51, 39, 41] [0, 56, 39]
51.5 [52, 8, 0] [0, 56, 32]
52.0 [52, 36, 16] [0, 56, 25]
52.5 [53, 4, 29] [0, 56, 17]
53.0 [53, 32, 37] [0, 56, 10]
53.5 [54, 0, 43] [0, 56, 3]
54.0 [54, 28, 44] [0, 55, 55]
54.5 [54, 56, 42] [0, 55, 48]
55.0 [55, 24, 35] [0, 55, 40]
55.5 [55, 52, 25] [0, 55, 32]
56.0 [56, 20, 12] [0, 55, 25]
56.5 [56, 47, 54] [0, 55, 17]
57.0 [57, 15, 33] [0, 55, 9]
57.5 [57, 43, 7] [0, 55, 1]
58.0 [58, 10, 38] [0, 54, 53]
58.5 [58, 38, 4] [0, 54, 45]
59.0 [59, 5, 27] [0, 54, 37]
59.5 [59, 32, 46] [0, 54, 29]
60.0 [60, 0, 0] [0, 54, 21]
60.5 [60, 27, 10] [0, 54, 12]
61.0 [60, 54, 17] [0, 54, 4]
61.5 [61, 21, 19] [0, 53, 56]
62.0 [61, 48, 16] [0, 53, 47]
62.5 [62, 15, 10] [0, 53, 39]
63.0 [62, 41, 59] [0, 53, 30]
63.5 [63, 8, 44] [0, 53, 21]
64.0 [63, 35, 25] [0, 53, 13]
64.5 [64, 2, 1] [0, 53, 4]
65.0 [64, 28, 33] [0, 52, 55]
65.5 [64, 55, 1] [0, 52, 46]
66.0 [65, 21, 24] [0, 52, 37]
66.5 [65, 47, 43] [0, 52, 28]
67.0 [66, 13, 57] [0, 52, 19]
67.5 [66, 40, 6] [0, 52, 10]
68.0 [67, 6, 11] [0, 52, 1]
68.5 [67, 32, 12] [0, 51, 52]
69.0 [67, 58, 7] [0, 51, 42]
69.5 [68, 23, 59] [0, 51, 33]
70.0 [68, 49, 45] [0, 51, 23]
70.5 [69, 15, 27] [0, 51, 14]
71.0 [69, 41, 4] [0, 51, 4]
71.5 [70, 6, 36] [0, 50, 55]
72.0 [70, 32, 3] [0, 50, 45]
72.5 [70, 57, 26] [0, 50, 35]
73.0 [71, 22, 43] [0, 50, 26]
73.5 [71, 47, 56] [0, 50, 16]
74.0 [72, 13, 4] [0, 50, 6]
74.5 [72, 38, 7] [0, 49, 56]
75.0 [73, 3, 5] [0, 49, 46]
75.5 [73, 27, 58] [0, 49, 36]
76.0 [73, 52, 46] [0, 49, 26]
76.5 [74, 17, 29] [0, 49, 15]
77.0 [74, 42, 6] [0, 49, 5]
77.5 [75, 6, 39] [0, 48, 55]
78.0 [75, 31, 6] [0, 48, 45]
78.5 [75, 55, 29] [0, 48, 34]
79.0 [76, 19, 46] [0, 48, 24]
79.5 [76, 43, 58] [0, 48, 13]
80.0 [77, 8, 4] [0, 48, 3]
80.5 [77, 32, 6] [0, 47, 52]
81.0 [77, 56, 2] [0, 47, 41]
81.5 [78, 19, 52] [0, 47, 31]
82.0 [78, 43, 38] [0, 47, 20]
82.5 [79, 7, 17] [0, 47, 9]
83.0 [79, 30, 52] [0, 46, 58]
83.5 [79, 54, 21] [0, 46, 47]
84.0 [80, 17, 44] [0, 46, 36]
84.5 [80, 41, 2] [0, 46, 25]
85.0 [81, 4, 15] [0, 46, 14]
85.5 [81, 27, 22] [0, 46, 3]
86.0 [81, 50, 23] [0, 45, 52]
86.5 [82, 13, 19] [0, 45, 40]
87.0 [82, 36, 9] [0, 45, 29]
87.5 [82, 58, 54] [0, 45, 18]
88.0 [83, 21, 32] [0, 45, 6]
88.5 [83, 44, 5] [0, 44, 55]
89.0 [84, 6, 33] [0, 44, 43]
89.5 [84, 28, 54] [0, 44, 32]
90.0 [84, 51, 10] [0, 44, 20]
90.5 [85, 13, 20] [0, 44, 8]
91.0 [85, 35, 24] [0, 43, 56]
91.5 [85, 57, 22] [0, 43, 45]
92.0 [86, 19, 15] [0, 43, 33]
92.5 [86, 41, 1] [0, 43, 21]
93.0 [87, 2, 42] [0, 43, 9]
93.5 [87, 24, 16] [0, 42, 57]
94.0 [87, 45, 45] [0, 42, 45]
94.5 [88, 7, 7] [0, 42, 33]
95.0 [88, 28, 24] [0, 42, 21]
95.5 [88, 49, 34] [0, 42, 9]
96.0 [89, 10, 39] [0, 41, 56]
96.5 [89, 31, 37] [0, 41, 44]
97.0 [89, 52, 29] [0, 41, 32]
97.5 [90, 13, 15] [0, 41, 19]
98.0 [90, 33, 55] [0, 41, 7]
98.5 [90, 54, 28] [0, 40, 55]
99.0 [91, 14, 55] [0, 40, 42]
99.5 [91, 35, 16] [0, 40, 30]
100.0 [91, 55, 31] [0, 40, 17]
100.5 [92, 15, 40] [0, 40, 4]
101.0 [92, 35, 42] [0, 39, 52]
101.5 [92, 55, 38] [0, 39, 39]
102.0 [93, 15, 27] [0, 39, 26]
102.5 [93, 35, 10] [0, 39, 13]
103.0 [93, 54, 47] [0, 39, 0]
103.5 [94, 14, 17] [0, 38, 47]
104.0 [94, 33, 41] [0, 38, 35]
104.5 [94, 52, 58] [0, 38, 21]
105.0 [95, 12, 9] [0, 38, 8]
105.5 [95, 31, 13] [0, 37, 55]
106.0 [95, 50, 11] [0, 37, 42]
106.5 [96, 9, 2] [0, 37, 29]
107.0 [96, 27, 46] [0, 37, 16]
107.5 [96, 46, 24] [0, 37, 3]
108.0 [97, 4, 55] [0, 36, 49]
108.5 [97, 23, 20] [0, 36, 36]
109.0 [97, 41, 38] [0, 36, 22]
109.5 [97, 59, 49] [0, 36, 9]
110.0 [98, 17, 54] [0, 35, 56]
110.5 [98, 35, 51] [0, 35, 42]
111.0 [98, 53, 43] [0, 35, 29]
111.5 [99, 11, 27] [0, 35, 15]
112.0 [99, 29, 4] [0, 35, 1]
112.5 [99, 46, 35] [0, 34, 48]
113.0 [100, 3, 59] [0, 34, 34]
113.5 [100, 21, 16] [0, 34, 20]
114.0 [100, 38, 26] [0, 34, 6]
114.5 [100, 55, 29] [0, 33, 53]
115.0 [101, 12, 25] [0, 33, 39]
115.5 [101, 29, 14] [0, 33, 25]
116.0 [101, 45, 57] [0, 33, 11]
116.5 [102, 2, 32] [0, 32, 57]
117.0 [102, 19, 1] [0, 32, 43]
117.5 [102, 35, 22] [0, 32, 29]
118.0 [102, 51, 36] [0, 32, 15]
118.5 [103, 7, 44] [0, 32, 0]
119.0 [103, 23, 44] [0, 31, 46]
119.5 [103, 39, 37] [0, 31, 32]
120.0 [103, 55, 23] [0, 31, 18]
120.5 [104, 11, 2] [0, 31, 4]
121.0 [104, 26, 34] [0, 30, 49]
121.5 [104, 41, 58] [0, 30, 35]
122.0 [104, 57, 16] [0, 30, 20]
122.5 [105, 12, 26] [0, 30, 6]
123.0 [105, 27, 29] [0, 29, 52]
123.5 [105, 42, 25] [0, 29, 37]
124.0 [105, 57, 13] [0, 29, 23]
124.5 [106, 11, 55] [0, 29, 8]
125.0 [106, 26, 29] [0, 28, 53]
125.5 [106, 40, 55] [0, 28, 39]
126.0 [106, 55, 15] [0, 28, 24]
126.5 [107, 9, 27] [0, 28, 9]
127.0 [107, 23, 32] [0, 27, 55]
127.5 [107, 37, 29] [0, 27, 40]
128.0 [107, 51, 19] [0, 27, 25]
128.5 [108, 5, 2] [0, 27, 10]
129.0 [108, 18, 37] [0, 26, 56]
129.5 [108, 32, 5] [0, 26, 41]
130.0 [108, 45, 25] [0, 26, 26]
130.5 [108, 58, 38] [0, 26, 11]
131.0 [109, 11, 43] [0, 25, 56]
131.5 [109, 24, 41] [0, 25, 41]
132.0 [109, 37, 32] [0, 25, 26]
132.5 [109, 50, 15] [0, 25, 11]
133.0 [110, 2, 50] [0, 24, 56]
133.5 [110, 15, 18] [0, 24, 41]
134.0 [110, 27, 38] [0, 24, 25]
134.5 [110, 39, 51] [0, 24, 10]
135.0 [110, 51, 56] [0, 23, 55]
135.5 [111, 3, 53] [0, 23, 40]
136.0 [111, 15, 43] [0, 23, 25]
136.5 [111, 27, 26] [0, 23, 9]
137.0 [111, 39, 0] [0, 22, 54]
137.5 [111, 50, 27] [0, 22, 39]
138.0 [112, 1, 47] [0, 22, 23]
138.5 [112, 12, 58] [0, 22, 8]
139.0 [112, 24, 2] [0, 21, 53]
139.5 [112, 34, 59] [0, 21, 37]
140.0 [112, 45, 47] [0, 21, 22]
140.5 [112, 56, 28] [0, 21, 6]
141.0 [113, 7, 1] [0, 20, 51]
141.5 [113, 17, 26] [0, 20, 35]
142.0 [113, 27, 44] [0, 20, 20]
142.5 [113, 37, 54] [0, 20, 4]
143.0 [113, 47, 56] [0, 19, 48]
143.5 [113, 57, 50] [0, 19, 33]
144.0 [114, 7, 36] [0, 19, 17]
144.5 [114, 17, 15] [0, 19, 1]
145.0 [114, 26, 46] [0, 18, 46]
145.5 [114, 36, 9] [0, 18, 30]
146.0 [114, 45, 24] [0, 18, 14]
146.5 [114, 54, 31] [0, 17, 59]
147.0 [115, 3, 30] [0, 17, 43]
147.5 [115, 12, 22] [0, 17, 27]
148.0 [115, 21, 5] [0, 17, 11]
148.5 [115, 29, 41] [0, 16, 55]
149.0 [115, 38, 8] [0, 16, 40]
149.5 [115, 46, 28] [0, 16, 24]
150.0 [115, 54, 40] [0, 16, 8]
150.5 [116, 2, 44] [0, 15, 52]
151.0 [116, 10, 40] [0, 15, 36]
151.5 [116, 18, 28] [0, 15, 20]
152.0 [116, 26, 8] [0, 15, 4]
152.5 [116, 33, 40] [0, 14, 48]
153.0 [116, 41, 4] [0, 14, 32]
153.5 [116, 48, 20] [0, 14, 16]
154.0 [116, 55, 28] [0, 14, 0]
154.5 [117, 2, 28] [0, 13, 44]
155.0 [117, 9, 20] [0, 13, 28]
155.5 [117, 16, 4] [0, 13, 12]
156.0 [117, 22, 40] [0, 12, 56]
156.5 [117, 29, 8] [0, 12, 40]
157.0 [117, 35, 27] [0, 12, 24]
157.5 [117, 41, 39] [0, 12, 7]
158.0 [117, 47, 43] [0, 11, 51]
158.5 [117, 53, 39] [0, 11, 35]
159.0 [117, 59, 26] [0, 11, 19]
159.5 [118, 5, 6] [0, 11, 3]
160.0 [118, 10, 37] [0, 10, 47]
160.5 [118, 16, 0] [0, 10, 30]
161.0 [118, 21, 15] [0, 10, 14]
161.5 [118, 26, 22] [0, 9, 58]
162.0 [118, 31, 21] [0, 9, 42]
162.5 [118, 36, 12] [0, 9, 25]
163.0 [118, 40, 55] [0, 9, 9]
163.5 [118, 45, 29] [0, 8, 53]
164.0 [118, 49, 56] [0, 8, 37]
164.5 [118, 54, 14] [0, 8, 20]
165.0 [118, 58, 24] [0, 8, 4]
165.5 [119, 2, 26] [0, 7, 48]
166.0 [119, 6, 20] [0, 7, 31]
166.5 [119, 10, 6] [0, 7, 15]
167.0 [119, 13, 43] [0, 6, 59]
167.5 [119, 17, 12] [0, 6, 42]
168.0 [119, 20, 33] [0, 6, 26]
168.5 [119, 23, 46] [0, 6, 10]
169.0 [119, 26, 51] [0, 5, 53]
169.5 [119, 29, 48] [0, 5, 37]
170.0 [119, 32, 36] [0, 5, 20]
170.5 [119, 35, 16] [0, 5, 4]
171.0 [119, 37, 48] [0, 4, 48]
171.5 [119, 40, 12] [0, 4, 31]
172.0 [119, 42, 28] [0, 4, 15]
172.5 [119, 44, 35] [0, 3, 58]
173.0 [119, 46, 34] [0, 3, 42]
173.5 [119, 48, 25] [0, 3, 26]
174.0 [119, 50, 8] [0, 3, 9]
174.5 [119, 51, 43] [0, 2, 53]
175.0 [119, 53, 9] [0, 2, 36]
175.5 [119, 54, 27] [0, 2, 20]
176.0 [119, 55, 37] [0, 2, 3]
176.5 [119, 56, 39] [0, 1, 47]
177.0 [119, 57, 32] [0, 1, 30]
177.5 [119, 58, 17] [0, 1, 14]
178.0 [119, 58, 54] [0, 0, 58]
178.5 [119, 59, 23] [0, 0, 41]
179.0 [119, 59, 44] [0, 0, 25]
179.5 [119, 59, 56] [0, 0, 8]
180.0 [120, 0, 0] [0, 0, 0]

The separation between lines and between numbers in a line must be clear, but is otherwise unrestricted. Rounding in the last sexagesimal place should be to the nearest integer – this makes the table to be output here not exactly correspond with Ptolemy's original, i.e. the table should match the code block above.

This is ; fewest bytes wins.

\$\endgroup\$
1
  • \$\begingroup\$ Very interesting question! I have translated Ptolemy’s Almagest to French and created a website, almageste.ca, featuring my translation. I would have loved to have (yet upcoming) answers to this question to lighten my code! \$\endgroup\$ Commented Feb 12, 2023 at 3:40

9 Answers 9

6
\$\begingroup\$

Wolfram Language (Mathematica), 71 78 bytes

+7 fix a bug noted by Arnauld

#/2|Ramp[DMSList/@Round[{c@#,2c[1+#]-2c@#},60^-2]]&~Array~360
c=120Sin[#/4°]&

Try it online!

Yields a list of rows expressed as θ | {{chord...}, {sixtieths...}}.

DMSList conveniently converts a number into its integer part and two sexagesimal places. We can multiply the sixtieths by 60 to extract its three parts using the same function.

\$\endgroup\$
2
  • \$\begingroup\$ Oh my, DMSList is a [chef's kiss] find. And even better, this ancient sexagesimal system (Babylonian in origin I believe) is ultimately why our clocks have 60 seconds/minute and 60 minutes/hour anyway—so the function is actually completely on topic! \$\endgroup\$ Commented Feb 13, 2023 at 20:33
  • \$\begingroup\$ @GregMartin Sexagesimal originated with the Sumerians. \$\endgroup\$ Commented Feb 14, 2023 at 0:30
6
\$\begingroup\$

JavaScript (V8), 126 bytes

for(v=10/573,a=1,F=q=>[q*60|0,(q=q*216e3+.5|0)/60%60|0,q>0?q%60:a=0];a;)print(a/2,F(v/2),F(-v+(v=4*Math.sin(++a/229.183118))))

Try it online!

Or try this version with a custom print for easier comparison with the table provided in the challenge.

Commented

for(                 // loop:
  v = 10 / 573,      //   good enough approximation of 4 * sin(pi / 720)
  a = 1,             //   angle in half degrees
  F = q =>           //   helper function taking a value q in [0,2]
    [                //   and returning a triplet consisting of:
      q * 60 | 0,    //   - the integer part of q * 60
      ( q =          //   - the first sexagesimal place, obtained by
          q * 216e3  //     updating q to floor(q * 60 ** 3 + 0.5),
          + .5 | 0   //
      ) / 60 % 60    //     dividing by 60, reducing modulo 60
      | 0,           //     and rounding towards 0
      q > 0 ? q % 60 //   - the 2nd sexagesimal place, which is
            : a = 0  //     max(q mod 60, 0) (the max() is needed for
    ];               //     the last line of the table)
  a;                 //   stop when a = 0
)                    //
print(               // print:
  a / 2,             //   the angle in degrees
  F(v / 2),          //   followed by the 1st triplet, using v / 2
  F(                 //   followed by the 2nd triplet:
    -v +             //     subtract the current value of v and add
    ( v =            //     the new value of v defined as:
      4 * Math.sin(  //       4 times the sine of:
        ++a /        //         increment a and divide it by a good
        229.183118   //         enough approximation of 720 / pi
      )              //
    )                //
  )                  //   end of 2nd call to F
)                    // end of print()
\$\endgroup\$
3
\$\begingroup\$

APL (Dyalog Unicode), 56 55 54 bytes

A full program printing the table

d,0 60 60∘⊤¨⌊.5+↑c,¨2×0,⍨¯2-/c←432e3×1○360÷⍨○d←2÷⍨⍳360

Try it online!

d←2÷⍨⍳360 all the angles \$\theta\$ from 0.5 to 180.
1○ Sine of 360÷⍨○ \$\theta \over 2\$ in radians.
432e3× Multiply by \$432000 = 60×60×120\$. This gives the chord length adjusted such that both sexagesimal digits are in the integer part.

¯2-/ Differences of adjacent values, for the "sixtieths" column.
0,⍨ Append a 0, this hardcodes the sixtieths for 180°.
Multiply each value by \$2 = 60 ÷ 30\$.

↑c,¨ Pair up each chord length with corresponding sixtieths value. This results in a matrix with two columns.
⌊.5+ Round all values to the nearest integer.
0 60 60∘⊤¨ Convert each value from "base 60", where the first of three digit is unbounded.

d, prepend the angles on the left of the table.

\$\endgroup\$
3
  • \$\begingroup\$ While it's not required, it's generally appreciated if you present a decomposition and explanation, much like the answers in Vyxal and 05AB1E. \$\endgroup\$ Commented Feb 13, 2023 at 12:35
  • \$\begingroup\$ @JeffZeitlin Added some text, this is a very literal implementation of the challenge specification, just with some of the constants combined. \$\endgroup\$ Commented Feb 13, 2023 at 12:53
  • 1
    \$\begingroup\$ 51 bytes \$\endgroup\$ Commented Feb 14, 2023 at 1:25
2
\$\begingroup\$

Python, 204 210 202 191 208 206 194 190 188 180 166 147 bytes

from math import*;j=0
while j<360:C=pi/720;j+=1;p=sin(C*j);print(j/2,*[[(x:=round(432e3*y))//3600,x//60%60,x%60]for y in[p,max(sin(C*-~j)-p,0)*2]])

Attempt This Online! or see it in a nicer format.

Thanks to @Neil for pointing out a bug and saving 2 14 16 bytes.
Thanks to @pan for saving 8 bytes.
Thanks to @xnor for saving 14 33 bytes.

\$\endgroup\$
15
  • 2
    \$\begingroup\$ I'm pretty sure 60.0 should be [60, 0, 0], not [59, 59, 60]. \$\endgroup\$ Commented Feb 12, 2023 at 10:58
  • \$\begingroup\$ Actually that was just one example; there are still five other cases. \$\endgroup\$ Commented Feb 12, 2023 at 13:54
  • \$\begingroup\$ @Neil I've rewritten the f function to only handle integers. Does this look fine now? \$\endgroup\$ Commented Feb 12, 2023 at 14:21
  • \$\begingroup\$ I think you can write g=lambda x:120*sin(radians(x/2))*a and then the last line can be golfed to end print(j,f(round(g(j))),f(round(max(g(j+.5)-g(j),0)*2))). \$\endgroup\$ Commented Feb 12, 2023 at 14:52
  • 1
    \$\begingroup\$ @xnor Heh, your previous version calculated x%3600%60, fortunately your 147-byte version simplifies that. \$\endgroup\$ Commented Feb 13, 2023 at 17:44
2
\$\begingroup\$

Vyxal , 38 bytes

kRɾ½:½∆R∆s»⟇₀¨»*:¯d0JZƛƛṙ2(60ḋ÷$)^W;;Z

Try it Online!

Outputs as a list of [a,[[b,c,d],[d,e,f]]]. The online interpreter times out after about outputting about half of the table.

First get the lengths a list of angles and the lengths of chord of the unit circle.

kR         # push 360
  ɾ        # inclusive 1 range
   ½       # halve
    :      # duplicate
     ½     # halve
      ∆R   # convert to radians
        ∆s # sine

Get the numbers in the second and third column multiplied by 3600.

»⟇₀¨»        # push 60*60*120
     *       # multiply
      :      # duplicate
       ¯     # consecutive differences
        d    # double
         0J  # append 0
           Z # zip

Convert to base sixty and zip with angles

ƛƛ               # map map:
  ṙ              #   round
   2(            #   for n in range(2):
     60ḋ         #     div mod by 60
        ÷        #     push each to stack
         $       #     swap
          )      #   end for
           ^W    #   reverse stack and wrap it in a list
             ;;  # end map end map
               Z # zip
\$\endgroup\$
2
\$\begingroup\$

Charcoal, 73 70 bytes

≔⁶⁰θ⊞υ²⮌E³⁶⁰⪫⁺⟦∕⁻³⁶⁰κ²⟧E⁺·⁵×Xθ³⁺υ⊗⁻⊟υ⊞Oυ↔⊕XI1j∕ι¹⁸⁰⟦÷⌊λ×θθ﹪÷⌊λθθ﹪⌊λθ⟧ 

Attempt This Online! Link is to verbose version of code. Explanation:

≔⁶⁰θ

Assign \$60\$ to a variable because it gets used enough times to make it worthwhile.

⊞υ²

Set the "next" chord to \$2\$, so that the linear interpolation values for \$180°\$ become zero.

⮌E³⁶⁰⪫⁺

Map downwards from \$180°\$ to \$0.5°\$, with the final output reversed, joining together...

⟦∕⁻³⁶⁰κ²⟧

... the angle, and, ...

E⁺·⁵×Xθ³⁺υ⊗⁻⊟υ⊞Oυ↔⊕XI1j∕ι¹⁸⁰

...mapping over the current chord and the difference between the previous and the current chord, ...

⟦÷⌊λ×θθ﹪÷⌊λθθ﹪⌊λθ⟧

... convert to sexagesimal.

Chords are calculated by using the identity \$2|\sin(45x°)|=|i^{2-x}+1|\$ . Note that the although the variable containing the current chord is referenced before the actual calculation, it's actually a list and gets mutated to the correct value before it is mapped over.

\$\endgroup\$
1
\$\begingroup\$

05AB1E, 62 61 42 bytes

360©L;Džq*®/Ž•6¥U•*D¥0ª·øòεε2F60‰`s})R]‚ø

-19 bytes porting the approaches used in @AndrovT's Vyxal and @ovs' APL answers, which is also much faster, so make sure to upvote both of them as well!

Outputs as a list of [a,[[b,c,d],[e,f,g]]].

Try it online or verify everything is correct.

Original 62 61 bytes answer:

360©>L;ü2εžq*®/ŽƵJ*Ć`-30/‚T.òεU59ÝNÌãXïδšΣ®ćÝm/OXα}нNi¦}}yнš

Outputs as a list of [a,[b,c,d],[e,f,g]].

Extremely slow.. It's barely fast enough to output the first result.

(Don't) try it online.

Instead:

Explanation:

360              # Push 360
   ©             # Store it in variable `®` (without popping)
    L            # Pop and push a list in the range [1,360]
     ;           # Halve each to [0.5,180.0] in 0.5 increments
D                # Duplicate this [0.5,180.0]-list
 žq*             # Multiply each by PI (3.141592653589793)
    ®/           # Divide each by the 360 from variable `®`
      Ž         # Take the sine of each
        •6¥U•*   # Multiply each by compressed 432000 (60*60*120)
D                # Duplicate this list
 ¥               # Get the deltas / forward-differences of this copy
  0ª             # Append a 0
    ·            # Double each
     ø           # Zip it with the duplicated list to create pairs
ò                # Round each decimal value to the nearest integer
 ε               # Map over each pair:
  ε              #  Map over both integers in this pair:
   2F            #   Loop 2 times:
     60‰         #    Divmod the integer at the top of the stack by 60
        `        #    Pop and push y//60 and y%60 separated to the stack
         s       #    Swap so the y//60 is at the top of the stack
    }            #   After the inner loop:
     )           #   Wrap the three values on the stack into a list
      R          #   Reverse it
 ]               # Close the nested maps
  ‚ø             # Pair and zip it with the duplicated [0.5,180.0]-list
                 # (after which the result is output implicitly as result)
360              # Push 360
   ©             # Store it in variable `®` (without popping)
    >            # Increase it by 1: 361
     L           # Pop and push a list in the range [1,361]
      ;          # Halve each to [0.5,180.5] in 0.5 increments
       ü2        # Get it's overlapping pairs: [[0.5,1.0],[1.0,1.5],...,[180.0,180.5]]
ε                # Map over each pair `y`:
 žq*             #  Multiply each by PI (3.141592653589793)
    ®/           #  Divide each by the 360 from variable `®`
      Ž         #  Take the sine of each
        ƵJ*      #  Multiply each by a compressed 120
 Ć               #  Enclose; append its own head
  `              #  Pop and push all three values to the stack
   -             #  Subtract the top two
    30/          #  Divide it by 30
       ‚         #  Pair it back together with the third value
        T.ò      #  Round each to 10 decimals (work-around for 59.999... → 60)
 ε               #  Inner map over this pair:
  U              #   Pop and store the current value in variable `X`
  59Ý            #   Push a list in the range [0,59]
     NÌ          #   Push the 0-based index + 2 (1st iteration = 2; 2nd iteration = 3)
       ã         #   Get the cartesian power to create all possible pairs/triplets
        Xï       #   Push value `X` and floor it to an integer
          δ      #   Map over each pair/triplet with this integer as argument
           š     #    Prepend it in front of each pair/triplet
  Σ              #   Sort this list of triplets/quadruplets by:
   ®             #    Push 360 from variable `®`
    ć            #    Head extracted; push 60 and 3 separated to the stack
     Ý           #    Pop and push a list in the range [0,3]
      m          #    Take 60 to the power each: [1,60,360,216000]
       /         #    Divide the values in the triplet/quadruplet by this
                 #    (the 216000 is ignored when dividing the triplet)
        O        #    Sum them together
         Xα      #    Get the absolute difference with value `X`
  }н             #   After the sort-by: pop and leave the first/closest
    Ni }         #   If the 0-based map-index is 1 (second iteration):
      ¦          #    Remove the leading 0
}                #  Close the outer map
 yн              #  Push the first item of pair `y`
   š             #  Prepend it to the pair of triplets
                 # (after which the result is output implicitly)

See this 05AB1E tip of mine (section How to compress large integers?) to understand why •6¥U• is 432000 and ƵJ is 120 (and why 360 isn't shorter when compressed).

\$\endgroup\$
0
\$\begingroup\$

Perl 5, 163 bytes

sub h{120*sin+(pop//$_)/229.183118}$d=' [%d, %d, %d]';printf"%.1f$d$d\n",$_/2,map{$x=1/7200+$_,60*($x-int$x),$x<0?0:60*($x*60-int$x*60)}(h,(h($_+1)-h)*2)for 1..360

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Raku, 141 bytes

{($_».polymod(60,60)Z(((.[1..*]Z-$_)Xmax
0)X*2)».polymod(60 xx 3)).map:{++$
/2,|$_».round»[2...0]}}([(1..361).map((*/720*π).sin*432e3)])

Try it online!

  • The initial sine values are generated by (1..361).map((* / 720 * π).sin * 432e3). The values are scaled up by an additional factor of 3,600 so that they can be fed to the polymod methods later.
  • $_».polymod(60, 60) generates columns 2-4.
  • .[1..*] Z- $_ zips the tail of the list with the full list using subtraction.
  • Xmax 0 makes each number zero if it's negative.
  • X* 2 doubles each number. 2 here is the multiplicative factor of 60 for feeding to polymod, divided by the 30 from the interpolation formula.
  • ».polymod(60 xx 3) generates columns 5-7.
  • The map generates the final list. ++$ / 2 is the first column, increasing by one half each iteration, and the two polymod list results are rounded and shown in order of the indices 2, 1, 0.
\$\endgroup\$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.