Functions for working with the idealized calendar of Planet Xhilr
Revisión | 5f908f8d9d9f68d8867420bbd572154aeed29b73 (tree) |
---|---|
Tiempo | 2017-06-13 17:22:28 |
Autor | Joel Matthew Rees <joel.rees@gmai...> |
Commiter | Joel Matthew Rees |
shifting to period code
@@ -0,0 +1,275 @@ | ||
1 | +( | |
2 | +// Forth program for calculating idealized lengths of months | |
3 | +// relative to skip years | |
4 | +// for the world of Bobbie, Karel, Dan, and Kristie, | |
5 | +// | |
6 | +// by Joel Matthew Rees, winter/spring 2017. | |
7 | +// Copyright 2017, Joel Matthew Rees | |
8 | +// | |
9 | +// Permission granted to use for personal entertainment only. | |
10 | +// -- You really shouldn't write programs like this on modern computers. | |
11 | +// | |
12 | +// http://joel-rees-economics.blogspot.com/2017/03/soc500-03-08-calendar-math.html | |
13 | +// http://joel-rees-economics.blogspot.com/2017/03/soc500-03-09-calculating-skip-years.html | |
14 | +// | |
15 | +// Novel here: | |
16 | +// http://joel-rees-economics.blogspot.com/2017/01/soc500-00-00-toc.html | |
17 | +// | |
18 | +// | |
19 | +// Save as "econcalcmonth.fs" | |
20 | +// | |
21 | +// In gforth and most modern or emulated environments, | |
22 | +// just paste it into the terminal of a running Forth session. | |
23 | +// | |
24 | +// Run it with | |
25 | +// 7 SHOWMONTHS | |
26 | +// for seven years, etc. | |
27 | +) | |
28 | + | |
29 | +( Using integer math. ) | |
30 | +( Forth expression syntax is mostly postfix. ) | |
31 | +( Only the definition syntax is prefix or infix. ) | |
32 | +( I've added comments with equivalent infix expressions to help those unfamiliar with Forth. ) | |
33 | + | |
34 | + | |
35 | +( Using baroque identifiers for ancient Forths. ) | |
36 | +( fig-Forth used first three character significant symbol tables. ) | |
37 | + | |
38 | + | |
39 | +( For ancient, especially pre-1983 fig, Forths: ) | |
40 | +( Do not use these in modern Forths like gforth. ) | |
41 | +: UM* U* ; | |
42 | +: FM/MOD M/MOD DROP ; ( Cheat! Behavior is not well defined for negative numbers. ) | |
43 | +( This is just renaming in a sloppy fashion, ) | |
44 | +( to accomodate the difference between ancient fig-Forths and modern Forths. ) | |
45 | +( Showing it in infix won't help. ) | |
46 | + | |
47 | +( Semi-simulate local variables. ) | |
48 | +SP@ SP@ - ABS CONSTANT CELLWIDTH | |
49 | +( Infix won't help here, either, but I can try to explain: ) | |
50 | +( CELLWIDTH = absolute-value-of difference-between SP-without-pointer and SP-with-pointer. ) | |
51 | + | |
52 | +( Infix will be confusing here, too. ) | |
53 | +: LC@ ( index -- sp[ix] ) ( 0 is top. PICK is available on many modern Forths. ) | |
54 | + 1 + CELLWIDTH * ( Skip over the stack address on stack. ) | |
55 | + SP@ + @ ( Assumes push-down stack. Will fail on push-up. ) | |
56 | +; | |
57 | + | |
58 | +( Infix will be confusing here, too. ) | |
59 | +: LC! ( n index -- ) ( 0 is top. Just store. This is not ROLL. ) | |
60 | + 2 + CELLWIDTH * ( Index and stack address are extra on stack during calculation. ) | |
61 | + SP@ + ( Assumes push-down stack. ) | |
62 | + ! ( *** Will fail in MISERABLE ways on push-up stacks! *** ) | |
63 | +; | |
64 | + | |
65 | +( Make things easier to read. ) | |
66 | +( Infix will be confusing here, too. ) | |
67 | + | |
68 | +: PRCH EMIT ; | |
69 | + | |
70 | +: COMMA 44 PRCH ; | |
71 | +: COLON 58 PRCH ; | |
72 | +: POINT 46 PRCH ; | |
73 | +: LPAREN 40 PRCH ; | |
74 | +: RPAREN 41 PRCH ; | |
75 | + | |
76 | +( No trailing space. ) | |
77 | +: PSNUM ( number -- ) | |
78 | + 0 .R ; | |
79 | + | |
80 | + | |
81 | +( Watch limits on 16 bit processors. ) | |
82 | +( Do it in integers! ) | |
83 | + | |
84 | +7 CONSTANT SCYCLE ( years in short cycle ) | |
85 | +( SCYCLE = 7 ) | |
86 | + | |
87 | +7 2 * CONSTANT SPMCYC ( short cycles in medium cycle ) | |
88 | +( SPMCYC = 7 × 2 ) | |
89 | + | |
90 | +SCYCLE SPMCYC * CONSTANT MCYCLE ( years in medium cycle, should be 98 ) | |
91 | +( MCYCLE = SCYCLE × SPMCYC ) | |
92 | + | |
93 | +7 7 * CONSTANT SPLCYC ( short cycles in single long cycle ) | |
94 | +( SPLCYC = 7 × 7 ) | |
95 | + | |
96 | +SCYCLE SPLCYC * CONSTANT LCYCLE ( years in single long cycle, should be 343 ) | |
97 | +( LCYCLE = SCYCLE × SPLCYC ) | |
98 | + | |
99 | +7 CONSTANT MP2LCYC ( medium cycles in double long cycle ) | |
100 | +( MP2LCYC = 7 ) | |
101 | +( MPLCYC would not be an integer: 3 1/2 ) | |
102 | + | |
103 | +MCYCLE MP2LCYC * CONSTANT 2LCYCLE ( years in double long cycle, should be 686 ) | |
104 | +( 2LCYCLE = MCYCLE × MP2LCYC ) | |
105 | + | |
106 | +352 CONSTANT DPSKIPYEAR ( floor of days per year ) | |
107 | + | |
108 | + | |
109 | +5 CONSTANT RDSCYCLE ( remainder days in short cycle ) | |
110 | + | |
111 | +DPSKIPYEAR SCYCLE * RDSCYCLE + CONSTANT DPSCYCLE ( whole days per 7 year cycle ) | |
112 | +( DPSCYCLE = DPSKIPYEAR × SCYCLE + RDSCYCLE ) | |
113 | +( DPMCYCLE and DP2LCYCLE would overflow on 16 bit math CPUs. ) | |
114 | + | |
115 | +RDSCYCLE SPMCYC * 1 - CONSTANT RDMCYCLE ( remainder days in medium cycle ) | |
116 | +( RDMCYCLE = RDSCYCLE × SPMCYC - 1 ) | |
117 | + | |
118 | +RDMCYCLE MP2LCYC * 2 + CONSTANT RD2LCYCLE ( remainder days in double long cycle -- odd number ) | |
119 | +( RD2LCYCLE = RDMCYCLE × MP2LCYC + 2 ) | |
120 | +( RD2LCYCLE / 2LCYCLE is fractional part of year. ) | |
121 | +( Ergo, length of year is DPSKIPYEAR + RD2LCYCLE / 2LCYCLE, ) | |
122 | +( or 352 485/686 days. ) | |
123 | + | |
124 | +12 CONSTANT MPYEAR ( months per year ) | |
125 | + | |
126 | +DPSKIPYEAR MPYEAR /MOD CONSTANT FDMONTH ( floor of days per month ) | |
127 | +( FDMONTH = DPSKIPYEAR / MPYEAR ) | |
128 | +CONSTANT FRMONTH ( floored minimum remainder days per month ) | |
129 | +( FRMONTH = DPSKIPYEAR MOD MPYEAR ) | |
130 | + | |
131 | +2LCYCLE MPYEAR * CONSTANT MDENOMINATOR ( denominator of month fractional part ) | |
132 | +( MDENOMINATOR = 2LCYCLE × MPYEAR ) | |
133 | + | |
134 | +FRMONTH 2LCYCLE * RD2LCYCLE + CONSTANT MNUMERATOR ( numerator of month fractional part ) | |
135 | +( MNUMERATOR = FRMONTH × 2LCYCLE + RD2LCYCLE ) | |
136 | +( Ergo, length of month is FDMONTH + MNUMERATOR / MDENOMINATOR, ) | |
137 | +( or 29 3229/8232 days. ) | |
138 | + | |
139 | +MDENOMINATOR 2 / CONSTANT MROUNDFUDGE | |
140 | + | |
141 | +( Infix will be confusing below here, as well. ) | |
142 | +( Hopefully, the comments and explanations will provide enough clues. ) | |
143 | + | |
144 | +( Sum up the days of the months in a year. ) | |
145 | +: SU1MONTH ( startfractional startdays -- endfractional enddays ) | |
146 | + 29 + ( Add the whole part. ) | |
147 | + SWAP ( Make the fractional part available to work on. ) | |
148 | + MNUMERATOR + ( Add the fractional part. ) | |
149 | + DUP MDENOMINATOR < ( Have we got a whole day yet? ) | |
150 | + IF | |
151 | + SWAP ( No, restore stack order for next pass. ) | |
152 | + ELSE | |
153 | + MDENOMINATOR - ( Take one whole day from the fractional part. ) | |
154 | + SWAP 1+ ( Restore stack and add the day carried in. ) | |
155 | + ENDIF | |
156 | +; | |
157 | + | |
158 | +: PRMONTH ( fractional days -- fractional days ) | |
159 | + SPACE DUP PSNUM POINT ( whole days ) | |
160 | + OVER 1000 UM* ( Fake three digits of decimal precision. ) | |
161 | + MROUNDFUDGE 0 D+ ( Round the bottom digit. ) | |
162 | + MDENOMINATOR FM/MOD ( Divide, or evaluate the fraction. ) | |
163 | + 0 <# # # # #> ( Formatting puts most significant digits in buffer first. ) | |
164 | + TYPE ( Fake decimal output. ) | |
165 | + DROP SPACE | |
166 | +; | |
167 | + | |
168 | +: SH1YEAR ( year daysmemory fractional days -- year daysmemory fractional days ) | |
169 | + CR | |
170 | + 12 0 DO | |
171 | + 3 LC@ PSNUM SPACE ( year ) | |
172 | + I PSNUM COLON SPACE | |
173 | + SU1MONTH | |
174 | + DUP 3 LC@ - ( difference in days ) | |
175 | + 2 LC@ ( ceiling ) IF 1+ ENDIF | |
176 | + DUP PSNUM SPACE ( show theoretical days in month ) | |
177 | + 3 LC@ + ( sum of days ) | |
178 | + LPAREN DUP PSNUM COMMA SPACE | |
179 | + 2 LC! ( update ) | |
180 | + PRMONTH RPAREN CR | |
181 | + LOOP | |
182 | +; | |
183 | + | |
184 | +: SHOWMONTHS ( years -- ) | |
185 | + >R | |
186 | + 0 0 0 0 ( year, daysmemory, fractional, days ) | |
187 | + R> 0 DO | |
188 | + CR | |
189 | + SH1YEAR | |
190 | + 3 LC@ 1+ 3 LC! | |
191 | + LOOP | |
192 | + DROP DROP DROP DROP | |
193 | +; | |
194 | + | |
195 | + | |
196 | +( Below here is scratch work I'm leaving for my notes. ) | |
197 | +( It can be deleted. ) | |
198 | + | |
199 | +: V2-SHOWMONTHS ( years -- ) | |
200 | + >R | |
201 | + 0 0 0 ( daysmemory, fractional, days ) | |
202 | + R> 0 DO | |
203 | + CR | |
204 | + 12 0 DO | |
205 | + J PSNUM SPACE ( year ) | |
206 | + I PSNUM COLON SPACE | |
207 | + SU1MONTH | |
208 | + DUP 3 LC@ - ( difference in days ) | |
209 | + 2 LC@ ( ceiling ) IF 1+ ENDIF | |
210 | + DUP PSNUM SPACE ( show theoretical days in month ) | |
211 | + 3 LC@ + ( sum of days ) | |
212 | + LPAREN DUP PSNUM COMMA SPACE | |
213 | + 2 LC! ( update ) | |
214 | + PRMONTH RPAREN CR | |
215 | + LOOP | |
216 | + LOOP | |
217 | + DROP DROP DROP | |
218 | +; | |
219 | + | |
220 | + | |
221 | +: NUMERATORS ( count -- ) | |
222 | +DUP 1+ 0 DO | |
223 | + I PSNUM COLON SPACE | |
224 | + I 1000 * OVER / PSNUM COMMA ( 1000 times I divided by count ) | |
225 | + SPACE LOOP | |
226 | +DROP ; | |
227 | + | |
228 | +: FRACTIONS ( count -- ) | |
229 | +1 DO | |
230 | + I NUMERATORS CR | |
231 | +LOOP ; | |
232 | + | |
233 | +( : ABS number -- absolute-value *** built in! *** | |
234 | +DUP 0< IF NEGATE THEN ; ) | |
235 | + | |
236 | +: WITHIN1 ( n1 n2 -- flag ) | |
237 | + - ABS 1 <= ; ( n1 and n2 are within 1 of each other ) | |
238 | + | |
239 | +( Negatives end in division by zero or infinite loop. ) | |
240 | +: SQRT ( number -- square-root ) | |
241 | +DUP IF ( square root of zero is zero. ) | |
242 | + ABS | |
243 | + 2 ( initial guess ) | |
244 | + BEGIN | |
245 | + OVER OVER / ( test guess by divide ) | |
246 | + OVER OVER - ABS 1 <= ( number guess quotient flag ) | |
247 | + IF ( number guess quotient ) | |
248 | + MIN -1 ( number result flag ) | |
249 | + ELSE | |
250 | + OVER + 2 / ( number guess avg ) | |
251 | + SWAP OVER ( number avg guess avg ) | |
252 | + - 1 <= ( number avg flag ) ( Integer average will always be floored. ) | |
253 | + ENDIF | |
254 | + UNTIL ( number result ) | |
255 | + SWAP DROP | |
256 | +ENDIF ; | |
257 | + | |
258 | + | |
259 | +353 CONSTANT DPYEAR ( nominal days per year ) | |
260 | + | |
261 | +7 CONSTANT 7YEARS | |
262 | + | |
263 | +2 CONSTANT DS7CYCLE ( days short in seven year cycle ) | |
264 | + | |
265 | +DPYEAR 7YEARS * DS7CYCLE - CONSTANT DP7YEAR ( whole days per 7 year cycle ) | |
266 | + | |
267 | +7YEARS 7 2 * * CONSTANT 98YEARS | |
268 | + | |
269 | +98YEARS 7YEARS / DS7CYCLE * 1 + CONSTANT DS98CYCLE ( days short in 98 year cycle ) | |
270 | + | |
271 | +98YEARS 7 * CONSTANT 686YEARS | |
272 | + | |
273 | +686YEARS 98YEARS / DS98CYCLE * 2 - CONSTANT DS686CYCLE ( days short in 686 year cycle ) | |
274 | + | |
275 | + |