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\$ 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\$ Feb 13, 2023 at 20:33
  • \$\begingroup\$ @GregMartin Sexagesimal originated with the Sumerians. \$\endgroup\$ 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\$ 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\$
    – ovs
    Feb 13, 2023 at 12:53
  • 1
    \$\begingroup\$ 51 bytes \$\endgroup\$
    – att
    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\$
    – Neil
    Feb 12, 2023 at 10:58
  • \$\begingroup\$ Actually that was just one example; there are still five other cases. \$\endgroup\$
    – Neil
    Feb 12, 2023 at 13:54
  • \$\begingroup\$ @Neil I've rewritten the f function to only handle integers. Does this look fine now? \$\endgroup\$
    – The Thonnu
    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\$
    – Neil
    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\$
    – Neil
    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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.