Functions for working with the idealized calendar of Planet Xhilr
修訂 | ae9ce3df9af333a1c470db29d89f666cf1bbfea4 (tree) |
---|---|
時間 | 2017-06-13 17:58:44 |
作者 | Joel Matthew Rees <joel.rees@gmai...> |
Commiter | Joel Matthew Rees |
progress, corrections, and a detour in C
@@ -70,35 +70,83 @@ | ||
70 | 70 | ( fig-Forth used first three character + length significance in symbol tables. ) |
71 | 71 | |
72 | 72 | |
73 | -( UM*, FM/MOD, S>D, 2DUP, and D- are already there in most modern Forths. ) | |
73 | +( UM*, UM/MOD, S>D, 2DUP, and D- are already there in most modern Forths. ) | |
74 | 74 | ( These definitions are only for ancient Forths, without the full set loaded, ) |
75 | 75 | ( especially pre-1983 fig and bif-c. ) |
76 | 76 | ( Un-comment them if you see errors like ) |
77 | 77 | ( UM* ? err # 0 ) |
78 | 78 | ( from PRMONTH or thereabouts. ) |
79 | 79 | |
80 | -: UM* U* ; ( modern name for unsigned mixed multiply ) | |
80 | +: UM* U* ; ( u u --- ud : modern name for unsigned mixed multiply ) | |
81 | 81 | |
82 | -( This is a cheat! Behavior is not well defined for negative numbers, ) | |
83 | -( but we don't do negatives here. ) | |
84 | 82 | ( So this is just sloppy renaming in a sloppy fashion: ) |
85 | -: FM/MOD M/MOD DROP ; ( unsigned division with modulo remainder ) | |
83 | +( unsigned division with modulo remainder ) | |
84 | +: UM/MOD U/ ; ( uddividend udivisor --- uremainder uquotient : If this doesn't work try M/MOD DROP: ) | |
85 | +( : UM/MOD M/MOD DROP ; ( uddividend udivisor --- uremainder uquotient ) | |
86 | 86 | |
87 | -: S>D S->D ; ( Modern name for single-to-double. ) | |
87 | +: S>D S->D ; ( n --- d : Modern name for single-to-double. ) | |
88 | +: NEGATE MINUS ; ( n --- -n : Modern name for single-to-double. ) | |
89 | +: DNEGATE DMINUS ; ( d --- -d : Modern name for single-to-double. ) | |
88 | 90 | |
89 | -: 2DUP OVER OVER ; ( d --- d d : DUPlicate top double word on stack. ) | |
91 | +: 2DUP OVER OVER ; ( d --- d d : DUPlicate top double cell on stack. ) | |
90 | 92 | |
91 | 93 | : 2DROP DROP DROP ; ( d --- : DROP a double, for readability. ) |
92 | 94 | |
93 | -: D- DMINUS D+ ; ( d1 d2 --- d : Difference of two doubles. ) | |
94 | -( : D- DNEGATE D+ ( d1 d2 --- d : Difference of two doubles, if no DMINUS. ) | |
95 | +: D- DNEGATE D+ ; ( d1 d2 --- d : Difference of two doubles. ) | |
96 | + | |
97 | +: 2SWAP ROT >R ROT R> ; ( d1 d2 --- d2 d1 : Swap top two doubles ) | |
98 | + | |
99 | +: 2ROT >R >R 2SWAP R> R> 2SWAP ; ( d0 d1 d2 --- d1 d2 d0 ) | |
100 | + | |
101 | +: 2OVER >R >R 2DUP R> R> 2SWAP ; ( d0 d1 --- d0 d1 d0 ) | |
102 | + | |
103 | +: D0= OR 0= ; ( d0 --- f : Test top double. ) | |
104 | + | |
105 | +: D0< SWAP DROP 0< ; ( d0 --- f : Test top double sign. ) | |
106 | + | |
107 | +: D= D- D0= ; ( d1 d2 --- f : Test the top two doubles for equality. ) | |
108 | + | |
109 | +: D< D- D0< ; ( d1 d2 --- f : Test the top two doubles for left being less. ) | |
110 | + | |
111 | +: 2>R SWAP >R >R ; ( Save a double away in true order, high word handy. ) | |
112 | + | |
113 | +: 2R> R> R> SWAP ; ( Bring back saved double. ) | |
114 | + | |
115 | +: 4DUP 2OVER 2OVER ; ( q --- q q : DUPlicate the top four cells on stack. ) | |
116 | + | |
117 | +: DMAX ( d1 d2 --- d : Leave larger of top two. ) | |
118 | + 4DUP D< IF 2SWAP 2DROP ELSE 2DROP THEN ; | |
119 | + | |
120 | +: DMIN ( d1 d2 --- d : Leave smaller of top two. ) | |
121 | + 4DUP D< IF 2DROP ELSE 2SWAP 2DROP THEN ; | |
122 | + | |
123 | +( 2/ and d2/ requires words which have various names -- u/, etc., ) | |
124 | +( and are very slow. ) | |
125 | +( Just best to do in assembler, along with UD* and UQD/MOD . ) | |
126 | +( : 2* DUP + ; ( u1 --- u2 : Double the top cell. Not fastest. ) | |
127 | + | |
128 | +( : D2* 2DUP D+ ; ( ud1 --- ud2 : Double the top double cell. Not fastest. ) | |
129 | + | |
130 | +( Do it in assembler instead! ) | |
131 | +( : 2/ 0 2 UM/MOD SWAP DROP ; ( u1 --- u2 : Halve the top cell. SLOW! ) | |
132 | + | |
133 | +( Do it in assembler instead! ) | |
134 | +( : D2/ 2 M/MOD ROT DROP ; ( uD1 --- uD2 : Halve the top cell. SLOW! ) | |
95 | 135 | |
96 | 136 | ( : R@ R ; ( Modern name for copy top of return stack. ) |
97 | 137 | |
138 | +( Showing the above in infix won't help. ) | |
139 | + | |
98 | 140 | |
99 | 141 | ( From here, we should load okay in modern Forths. ) |
142 | +( Most of the doubles handling will be faster at assembler level ) | |
143 | +( -- even if all you have is the bit math. ) | |
100 | 144 | |
101 | -( Showing the above in infix won't help. ) | |
145 | + | |
146 | +( Already there as M/MOD in some Forths: ) | |
147 | +( : JM/MOD M/MOD ; ( uddividend udivisor -- uremainder udquotient ) | |
148 | +: JM/MOD ( uddividend udivisor -- uremainder udquotient ) | |
149 | + >R 0 R> DUP >R UM/MOD R> SWAP >R UM/MOD R> ; | |
102 | 150 | |
103 | 151 | SP@ SP@ - ABS CONSTANT CELLWIDTH |
104 | 152 | ( Infix won't help here, either, but I can try to explain: ) |
@@ -144,6 +192,142 @@ SP@ SP@ - ABS CONSTANT CELLWIDTH | ||
144 | 192 | D! ( *** Will fail in MISERABLE ways on push-up stacks! *** ) |
145 | 193 | ; |
146 | 194 | |
195 | +( This probably isn't really a good idea. Much better to just implement UMD* in assembler. ) | |
196 | +( AL AH B --- QL QML QMH : unsigned double by unsigned single yielding three-cell unsigned ) | |
197 | +: UDS* ( ud u --- uhq ) | |
198 | + DUP >R SWAP >R | |
199 | + ( AL B ) UM* | |
200 | + 0 ( ready to sum into ) | |
201 | + R> R> | |
202 | + ( AH B ) UM* | |
203 | + D+ | |
204 | +; | |
205 | + | |
206 | +( only for stealing by U3S/MOD and UQS/MOD ! ) | |
207 | +( Should actually be in a private vocabulary, but old Forths and new Forths do those differently. ) | |
208 | +: (HIDDEN3S/MOD) ( uq u --- uremainder uhquotient ) | |
209 | + DUP >R JM/MOD DROP ( AL AM R QMH ) ( B ) | |
210 | + R> SWAP >R ( AL AM R B ) ( QMH ) | |
211 | + DUP >R JM/MOD DROP ( AL R QML ) ( QMH B ) | |
212 | + R> SWAP >R ( AL R B ) ( QMH QML ) | |
213 | + JM/MOD DROP ( R QL ) ( QMH QML ) | |
214 | + R> R> ( R QL QML QMH ) | |
215 | +; | |
216 | + | |
217 | +( AL AML AMH B --- R QL QML QMH : unsigned 3-cell by unsigned single yielding 3-cell unsigned ) | |
218 | +: U3S/MOD ( uhq u --- uremainder uhqquotient ) | |
219 | + 0 SWAP ( AL AM AH 0 B ) ( Prime the chain. ) | |
220 | + (HIDDEN3S/MOD) | |
221 | +; | |
222 | +( You want to know why this is okay. ) | |
223 | +( For the intuitive approach, ) | |
224 | +( consider the cell lower in order than the current cell ) | |
225 | +( as on the other side of the effective fraction point. ) | |
226 | +( Now consider that the lower order cell cannot be as large as 1 in the current cell. ) | |
227 | +( The remainder cannot be as large as the divisor. | |
228 | +( Added together, they still cannot be as large as the divisor. ) | |
229 | +( Therefore, once you prime the chain with a zero in the cell above, ) | |
230 | +( the result cannot overfow into the higher order cell of the double dividend. ) | |
231 | + | |
232 | +( AL AML AMH AH B --- R QL QML QMH QH : unsigned 4-cell by unsigned single yielding 4-cell unsigned ) | |
233 | +: UQS/MOD ( uqdividend udivisor --- uremainder uqquotient ) | |
234 | + 0 SWAP ( AL AML AMH AH 0 B ) ( Prime the chain. ) | |
235 | + DUP >R JM/MOD DROP ( AL AML AMH R QH ) ( B ) | |
236 | + R> SWAP >R ( AL AML AMH R B ) ( QH ) | |
237 | + (HIDDEN3S/MOD) | |
238 | +( DUP >R JM/MOD DROP -- AL AML R QMH ) ( QH B ) | |
239 | +( R> SWAP >R -- AL AML R B ) ( QH QMH ) | |
240 | +( DUP >R JM/MOD DROP -- AL R QML ) ( QH QMH B ) | |
241 | +( R> SWAP >R -- AL R B ) ( QH QMH QML ) | |
242 | +( JM/MOD DROP -- R QL ) ( QH QMH QML ) | |
243 | +( R> R> ) | |
244 | + R> ( R QL QML QMH ) | |
245 | +; | |
246 | + | |
247 | +( Given AABB / EEFF == SSTT rem MMNN, ) | |
248 | +( AA/EE == RR rem LL is an approximation, iff EE is not zero. ) | |
249 | +( But EE == 00 => use AABB / FF. ) | |
250 | +( For EE > 0, RR * EE + LL == AA, or [ RR + LL / EE ] * EE == AA ) | |
251 | +( But LL / EE < 1, or [ LL / EE ] * 100 < 100 ) | |
252 | +( { [ RR + LL / EE ] * EE } * 100 == AA * 100 } ) | |
253 | +( { [ RR * EE ] * 100 + LL * 100 } < { AA * 100 + BB } ) | |
254 | +( Thus, { RR * EE00 + LL00 } < AABB ) | |
255 | +( Now, BB < 100, so ) | |
256 | +( { [ RR * EE + 1 ] * 100 + LL * 100 } > { AA * 100 + BB } ) | |
257 | +( or AABB < { [ RR + 1 ] * EE00 + LL00 } | |
258 | +( This gives us some confidence that ) | |
259 | +( { [ RR - 1 ] * EEFF } <= AABB <= { [ RR + 1 ] * EEFF } ) | |
260 | +( which means that a trial division should be easy to restore to the true result. ) | |
261 | +( But we want to know for sure. ) | |
262 | +( { RR * EE00 + LL00 } == AA00 ) | |
263 | +( { RR * EE00 + LL00 + BB } == AABB ) | |
264 | +( { RR * [ EE00 + FF ] + LL00 + BB } > AABB ) | |
265 | +( { RR * EE00 + RR * FF + LL00 + BB } > AABB ) | |
266 | +( { RR * EE00 + RR * FF + LL00 + BB } == { AABB + RR * FF } ) | |
267 | +( { RR * EE00 + RR * FF + LL00 + BB } == { AA00 + BB + RR * FF } ) | |
268 | +( Good thing we checked. ) | |
269 | +( The closer BB -LL gets to FF, the harder it is to recover. ) | |
270 | +( Pathological case, hexadecimal - 32FF / 1FF in byte columns: ) | |
271 | +( 32FF / 100 == 32rFF, 32 * 1FF == 63CE. ) | |
272 | +( 32FF / 1FF is almost 32FF / 200: 19r177. ) | |
273 | +( In sixteen bits, not useful. ) | |
274 | +( In eight bits, better, but still not very useful. ) | |
275 | + | |
276 | +( Starting from scratch: ) | |
277 | +( A/B == CrD => C * B + D == A, D < B ) | |
278 | +( B can be expressed in terms of the magnitude of the columns: ) | |
279 | +( If B < Radix R, or the magnitude of the columns, use UQS/MOD. ) | |
280 | +( If B == Magnitude of the columns, shift A. ) | |
281 | +( B > Radix R, B/R == PrL, ) | |
282 | +( B == P*R + L, P == [B-L]/R ) | |
283 | +( L == B - P*R ) | |
284 | +( Then, ) | |
285 | +( A == C * [ P*R + L] + D ) | |
286 | +( A == CPR + CL + D ) | |
287 | +( A / [P*R] == C + CL/[P*R] + D/[P*R] ) | |
288 | +( A / [P*R] == C * [1 + L/[P*R]] + D/[P*R] This goes in a circle. ) | |
289 | +( A == C * [PR + L] + D ) | |
290 | +( A / [PR + L] == C + D / [PR + L] , 0 <= D < B or 0 <= D < PR + L ) | |
291 | +( C <= A / [PR + L] < C + 1 , which isn't all that useful, either. ) | |
292 | +( But 0 <= L < R, so ) | |
293 | +( A / {[P + 1] * R} < A / [PR + L] <= A / PR , which restates the above. ) | |
294 | + | |
295 | +( Asking at comp.lang.forth produced this suggestion from Andrew Haley: ) | |
296 | +( http://surface.syr.edu/cgi/viewcontent.cgi?article=1162&context=eecs_techreports ) | |
297 | +( And from Rudy Velthius -- also mentions divmnu.c ) | |
298 | +( https://github.com/rvelthuis/BigNumbers ) | |
299 | +( It pretty much agrees with what I'm seeing above. ) | |
300 | +( Doing it in binary math is the right way for this. ) | |
301 | + | |
302 | + | |
303 | +( AL AH BL BH --- QL QML QMH QH : unsigned double by unsigned double yielding unsigned quad ) | |
304 | +: UMD* ( ud1 ud2 --- uq ) | |
305 | + ( AL ) 3 LC@ ( BL ) 2 LC@ UM* 0 ( QL QML QMH : low cells product, ready to sum into QML QMH ) | |
306 | + ( AH ) 5 LC@ ( BL ) 5 LC@ UM* >R 0 D+ ( inner product low int QML and carry ) | |
307 | + ( AL ) 6 LC@ ( BH ) 4 LC@ UM* >R 0 D+ ( again, QML complete. ) | |
308 | + 0 ( zero to QH, ready to sum into QMH QH ) | |
309 | + R> 0 D+ R> 0 D+ ( QL QML QMH QH : inner product high into QMH and carry ) | |
310 | + ( AH ) 6 LC@ ( BH ) 5 LC@ UM* D+ ( Product complete, now store it. ) | |
311 | + 3 LC! 3 LC! 3 LC! 3 LC! | |
312 | +; | |
313 | + | |
314 | +( Scaling, to keep the steps time-bounded, is going to leave me at the binary long division ) | |
315 | +( unless I use tables. Tables will not fit in a 16-bit address space. ) | |
316 | +( AL AML AMH AH BL BH --- QL QML QMH QH : unsigned 4-cell by unsigned double yielding 4-cell unsigned ) | |
317 | +( : UQD/MOD ( uqdividend uddivisor --- udremainder uhqquotient ) | |
318 | +( DUP 0= IF ) | |
319 | +( DROP UQS/MOD ( Get divisor high word 0 case out of the way. ) | |
320 | +( ELSE ) | |
321 | +( 2>R ( Divisor high byte handy. ) | |
322 | +( DUP 0 R> DUP >R JM/MOD ( Trial division for guess. ) | |
323 | +( ROT DROP 2R> 2DUP 2>R UMD* ) | |
324 | +( ) | |
325 | +( THEN ) | |
326 | +( ; ) | |
327 | + | |
328 | +( : UMQ* ( uqdividend uddivisor --- udremainder uqquotient ) | |
329 | +( 0. 2SWAP ) | |
330 | + | |
147 | 331 | ( Make things easier to read. ) |
148 | 332 | ( Infix will be confusing here, too. ) |
149 | 333 |
@@ -195,28 +379,38 @@ MCYCLE MP2LCYC * CONSTANT 2LCYCLE ( years in double long cycle, should be 686 ) | ||
195 | 379 | |
196 | 380 | DPSKIPYEAR SCYCLE * RDSCYCLE + CONSTANT DPSCYCLE ( whole days per 7 year cycle ) |
197 | 381 | ( DPSCYCLE = DPSKIPYEAR × SCYCLE + RDSCYCLE ) |
198 | -( DPSCYCLE SPMCYC * DCONSTANT DPMCYCLE ) | |
199 | -( DPMCYCLE = DPSCYCLE × SPMCYC ) | |
200 | -( DPMCYCLE MP2LCYC * DCONSTANT DP2LCYCLE ) | |
201 | -( DP2LCYCLE = DPMCYCLE × MP2LCYC ) | |
382 | + | |
202 | 383 | ( DPMCYCLE and DP2LCYCLE would overflow on 16-bit math CPUs. ) |
203 | 384 | ( No particular problem on 32 bit CPUs. Need DCONSTANT for 16-bit CPUs. ) |
204 | 385 | ( But we need the constants more than we need to puzzle out ) |
205 | 386 | ( the differences between CREATE DOES> and <BUILDS DOES>. ) |
206 | -: DPMCYCLE DPSCYCLE SPMCYC UM* ; ( Takes a little extra time this way. ) | |
207 | -( DPMCYCLE is actually 34566, so the high CELL is 0, ) | |
208 | -( but the low CELL must be treated as unsigned. ) | |
209 | -: DP2LCYCLE DPMCYCLE DROP MP2LCYC UM* ; | |
210 | 387 | |
211 | -RDSCYCLE SPMCYC * 1 - CONSTANT RDMCYCLE ( remainder days in medium cycle ) | |
212 | -( RDMCYCLE = RDSCYCLE × SPMCYC - 1 ) | |
388 | +1 CONSTANT EDMCYCLE ( whole days adjusted down in 98 year cycle ) | |
389 | + | |
390 | +RDSCYCLE SPMCYC * EDMCYCLE - CONSTANT RDMCYCLE ( remainder days in medium cycle ) | |
391 | +( RDMCYCLE = RDSCYCLE × SPMCYC - EDMCYCLE ) | |
392 | + | |
393 | +( DPSCYCLE SPMCYC UM* EDMCYCLE 0 D- DCONSTANT DPMCYCLE : 34565, too large for signed 16 bit. ) | |
394 | +( DPMCYCLE = DPSCYCLE × SPMCYC - EDMCYCLE ) | |
395 | +( Fake DCONSTANT: ) | |
396 | +: DPMCYCLE [ DPSCYCLE SPMCYC UM* EDMCYCLE 0 D- SWAP ] LITERAL LITERAL ; ( Fits in unsigned 16 bit. ) | |
397 | + | |
398 | +2 CONSTANT SD2LCYCLE ( whole days adjusted up in 686 year cycle ) | |
213 | 399 | |
214 | -RDMCYCLE MP2LCYC * 2 + CONSTANT RD2LCYCLE ( remainder days in double long cycle -- odd number ) | |
215 | -( RD2LCYCLE = RDMCYCLE × MP2LCYC + 2 ) | |
400 | +RDMCYCLE MP2LCYC * SD2LCYCLE + CONSTANT RD2LCYCLE ( remainder days in double long cycle -- odd number ) | |
401 | +( RD2LCYCLE = RDMCYCLE × MP2LCYC + SD2LCYCLE ) | |
216 | 402 | ( RD2LCYCLE / 2LCYCLE is fractional part of year. ) |
217 | 403 | ( Ergo, length of year is DPSKIPYEAR + RD2LCYCLE / 2LCYCLE, ) |
218 | 404 | ( or 352 485/686 days. ) |
219 | 405 | |
406 | +( D* is not defined, but, luckily, DPMCYCLE fits in unsigned 16 bit. ) | |
407 | +( 100 years of 365.24 also fits in unsigned 16 bit, FWIW. ) | |
408 | +( DPLCYCLE would not be an integer, leaves a half day over. ) | |
409 | +( DPMCYCLE MP2LCYC S>D D* SD2LCYCLE 0 D+ DCONSTANT DP2LCYCLE : 241957 , too large for 16 bit. ) | |
410 | +( DP2LCYCLE = DPMCYCLE × MP2LCYC + SD2LCYCLE ) | |
411 | +( Fake DCONSTANT: ) | |
412 | +: DP2LCYCLE [ DPMCYCLE ( 34565 ) DROP MP2LCYC UM* SD2LCYCLE 0 D+ SWAP ] LITERAL LITERAL ; | |
413 | + | |
220 | 414 | 12 CONSTANT MPYEAR ( months per year ) |
221 | 415 | |
222 | 416 | DPSKIPYEAR MPYEAR /MOD CONSTANT FDMONTH ( floor of days per month ) |
@@ -255,7 +449,7 @@ MDENOMINATOR 2 / CONSTANT MROUNDFUDGE | ||
255 | 449 | SPACE 2DUP PSDNUM POINT ( whole days ) |
256 | 450 | 2 LC@ 1000 UM* ( Fake three digits of decimal precision. ) |
257 | 451 | MROUNDFUDGE S>D D+ ( Round the bottom digit. ) |
258 | - MDENOMINATOR FM/MOD ( Divide, or evaluate the fraction. ) | |
452 | + MDENOMINATOR UM/MOD ( Divide, or evaluate the fraction. ) | |
259 | 453 | S>D <# # # # #> ( Formatting puts most significant digits in buffer first. ) |
260 | 454 | TYPE ( Fake decimal output. ) |
261 | 455 | DROP SPACE |
@@ -293,6 +487,7 @@ MDENOMINATOR 2 / CONSTANT MROUNDFUDGE | ||
293 | 487 | 4 CONSTANT SK2SHORTCYC |
294 | 488 | 48 CONSTANT SKMEDIUMCYC |
295 | 489 | 186 CONSTANT LPLONGCYC ( Must be short1 or short2 within the seven year cycle. ) |
490 | +LCYCLE LPLONGCYC + CONSTANT LPLONGCYC2 | |
296 | 491 | |
297 | 492 | ( Since skipyears are the exception, ) |
298 | 493 | ( we test for skipyears instead of leapyears. ) |
@@ -322,7 +517,7 @@ MDENOMINATOR 2 / CONSTANT MROUNDFUDGE | ||
322 | 517 | 0 VARIABLE DIMARRAY ( Days In Months array ) |
323 | 518 | ( Modern Forths don't initialize, will leave 0 on stack. ) |
324 | 519 | |
325 | -CELLWIDTH - ALLOT ( Back up to store values. ) | |
520 | +CELLWIDTH NEGATE ALLOT ( Back up to store values. ) | |
326 | 521 | |
327 | 522 | 30 C, |
328 | 523 | 29 C, |
@@ -366,7 +561,7 @@ CELLWIDTH - ALLOT ( Back up to store values. ) | ||
366 | 561 | LOOP |
367 | 562 | ; |
368 | 563 | |
369 | -: SHOWMONTHS ( years -- ) | |
564 | +: SHOWMONTHS ( years --- ) | |
370 | 565 | >R |
371 | 566 | 0 0. 0 0. ( year, ddaysmemory, fractional, ddays ) |
372 | 567 | R> 0 DO |
@@ -377,6 +572,182 @@ CELLWIDTH - ALLOT ( Back up to store values. ) | ||
377 | 572 | 2DROP DROP 2DROP DROP |
378 | 573 | ; |
379 | 574 | |
575 | +: D, ( d --- ) ( Store a double into the dictionary. ) | |
576 | + SWAP , , ; | |
577 | + | |
578 | +: DINY ( year --- days ) | |
579 | + ISKIPYEAR 0= 1 AND DPSKIPYEAR + ; | |
580 | + | |
581 | +: DTYLONGLOOP ( years --- ddays ) ( Days in years. ) | |
582 | + 0. ROT DUP IF | |
583 | + 0 DO | |
584 | + I DINY S>D D+ | |
585 | + LOOP | |
586 | + ELSE | |
587 | + DROP | |
588 | + THEN | |
589 | +; | |
590 | + | |
591 | +( Already did these the other way: ) | |
592 | +( : DPMCYCLE [ MCYCLE DTYLONGLOOP SWAP ] LITERAL LITERAL ; ( 34565 ) | |
593 | +( : DP2LCYCLE [ 2LCYCLE DTYLONGLOOP SWAP ] LITERAL LITERAL ; ( 241957 ) | |
594 | + | |
595 | +( Synthetic division is faster than general division. ) | |
596 | +: DTYLONG ( ddays1 uyear1 --- ddays2 uyear2 ) ( Sum long cycle years. ) | |
597 | + BEGIN | |
598 | + 2LCYCLE - DUP 0< 0= WHILE | |
599 | + >R DP2LCYCLE D+ R> | |
600 | + REPEAT | |
601 | + 2LCYCLE + | |
602 | +; | |
603 | + | |
604 | +( Synthetic division is faster than general division. ) | |
605 | +: DTYMEDIUM ( ddays1 uyear1 --- ddays2 uyear2 ) ( Sum medium cycle years with leaps. ) | |
606 | + DUP LPLONGCYC2 > IF | |
607 | + >R 2. D+ R> | |
608 | + ELSE | |
609 | + DUP LPLONGCYC > IF >R 1. D+ R> THEN | |
610 | + THEN | |
611 | + BEGIN | |
612 | + MCYCLE - DUP 0< 0= WHILE | |
613 | + >R DPMCYCLE D+ R> | |
614 | + REPEAT | |
615 | + MCYCLE + | |
616 | +; | |
617 | + | |
618 | +( Synthetic division is still faster : max 98 / 7 loops. ) | |
619 | +: DTYSHORT ( ddays1 uyear1 --- ddays2 uyear2 ) ( Sum short cycle years with skip. ) | |
620 | + DUP SKMEDIUMCYC > IF | |
621 | + >R 1. D- R> | |
622 | + THEN | |
623 | + BEGIN | |
624 | + SCYCLE - DUP 0< 0= WHILE | |
625 | + >R DPSCYCLE 0 D+ R> | |
626 | + REPEAT | |
627 | + SCYCLE + | |
628 | +; | |
629 | + | |
630 | +( Synthetic division is faster than general division. ) | |
631 | +( Anyway, this has only algorithmic meaning prior to the standard calendar. ) | |
632 | +: DTY ( uyear --- ddays ) | |
633 | + 0. ROT | |
634 | + DTYLONG | |
635 | + DTYMEDIUM | |
636 | + DTYSHORT | |
637 | + DTYLONGLOOP | |
638 | + D+ | |
639 | +; | |
640 | + | |
641 | +( Saturates on month > 12. Generally use to month 11. ) | |
642 | +: DTM ( year month --- days ) ( Just the days from the beginning of the year. ) | |
643 | + DUP IF | |
644 | + 0 SWAP 0 DO | |
645 | + OVER I DIMONTH + | |
646 | + LOOP | |
647 | + THEN | |
648 | + SWAP DROP | |
649 | +; | |
650 | + | |
651 | + | |
652 | +0 VARIABLE CALENDAR-WIDTH | |
653 | +80 CALENDAR-WIDTH ! | |
654 | + | |
655 | +0 VARIABLE DAYCOUNT | |
656 | +0 DAYCOUNT ! 0 , ( Double variable, initialize cleared. Modern Forths leave a zero. ) | |
657 | + | |
658 | + | |
659 | +0 CONSTANT WKDAYOFFSET ( Weekday corresponding to day zero of year zero. ) | |
660 | +0 CONSTANT 1STDAYOFWEEK ( Weekday corresponding to first day of week. ) | |
661 | + | |
662 | +0 VARIABLE DOWKSTATE ( Current day of week. Modern Forths leave a zero. ) | |
663 | + | |
664 | +7 CONSTANT DPWK ( Days per week. ) | |
665 | + | |
666 | + | |
667 | +( For the cycles use scaled 485 / 686, keep scale in 16 bits. ) | |
668 | +RD2LCYCLE 16 * CONSTANT NUCYCLE ( numerator: 7760 ) | |
669 | +2LCYCLE 16 * CONSTANT DECYCLE ( denominator: 10976 ) | |
670 | + | |
671 | +( Their larger moon orbits their world in about twenty-eight and seven eighths days, ) | |
672 | +( about twelve and one fifth long lunar months each year.) | |
673 | +28 CONSTANT SMPERIODINT ( Slow moon period integer part. ) | |
674 | +7 DECYCLE 8 */ 41 + CONSTANT SMPERIODFRAC10976 ( Slow moon period fractional part. ) | |
675 | +( Fake DCONSTANT: ) | |
676 | +: SMPERIOD10976 [ SMPERIODINT DECYCLE UM* SMPERIODFRAC10976 0 D+ SWAP ] LITERAL LITERAL ; | |
677 | +( 28 9645 / 10976 == 316973 / 10976 ) | |
678 | +( | |
679 | + | |
680 | + | |
681 | +0 CONSTANT SMOFFINT ( Slow moon offset at year 0 day 0, integer part. ) | |
682 | +0 CONSTANT SMOFFFRAC10976 ( Fractional part. ) | |
683 | + | |
684 | +0 VARIABLE SMSTATEINT ( Slow moon state integer part. ) | |
685 | +0 SMSTATEINT ! ( Initialize cleared. Modern Forths leave a zero. ) | |
686 | +0 VARIABLE SMSTATEFRAC10976 ( Fractional part. ) | |
687 | + | |
688 | + | |
689 | +( The smaller moon orbits their world in just under seven and one eighth days, ) | |
690 | +( about forty-nine and a half lunar weeks a year ) | |
691 | +7 CONSTANT FMPERIODINT ( Fast moon period integer part. ) | |
692 | +1 DECYCLE 8 */ 9 - CONSTANT FMPERIODFRAC10976 ( Fast moon period fractional part. ) | |
693 | +( Fake DCONSTANT: ) | |
694 | +: FMPERIOD10976 [ FMPERIODINT DECYCLE UM* FMPERIODFRAC10976 0 D+ SWAP ] LITERAL LITERAL ; | |
695 | +( 7 1364 / 10976 == 78196 / 10976 ) | |
696 | + | |
697 | +0 CONSTANT FMOFFINT ( Fast moon offset at year 0 day 0, integer part. ) | |
698 | +0 CONSTANT FMOFFFRAC10976 ( Fractional part. ) | |
699 | + | |
700 | +0 VARIABLE FMSTATEINT ( Fast moon state integer part. ) | |
701 | +0 FMSTATEINT ! ( Initialize cleared. Modern Forths leave a zero. ) | |
702 | +0 VARIABLE FMSTATEFRAC10976 ( Fractional part. ) | |
703 | + | |
704 | + | |
705 | +: WSTYCYCLES ( year --- ddays ) ( Start the weekday counter for the year, keep the days. ) | |
706 | + DTY 2DUP DAYCOUNT D! | |
707 | + 2DUP WKDAYOFFSET 0 D- DPWK JM/MOD 2DROP DOWKSTATE ! | |
708 | +; | |
709 | + | |
710 | +: SSTYCYCLES ( ddays --- ) ( Start the slowmoon cycle counter for the year. ) | |
711 | + SMOFFINT SMSTATEINT ! | |
712 | + SMOFFFRAC10976 SMSTATEFRAC10976 ! | |
713 | + | |
714 | + 2DUP DECYCLE UDS* | |
715 | + | |
716 | +; | |
717 | + | |
718 | +: FSTYCYCLES ( year --- ) ( Start the fastmoon cycle counter for the year. ) | |
719 | + FMOFFINT 0 FMSTATEINT ! | |
720 | + FMOFFFRAC10976 FMSTATEFRAC10976 ! | |
721 | + | |
722 | + 2DUP DECYCLE UDS* ( Have to dived by period, period is double. ) | |
723 | + | |
724 | +; | |
725 | + | |
726 | +: STYCYCLES ( year --- ) ( Start the counters for the year. ) | |
727 | + DUP WSTYCYCLES | |
728 | + DUP SSTYCYCLES | |
729 | + DUP FSTYCYCLES | |
730 | +; | |
731 | + | |
732 | +: STMCYCLES ( year month --- ) ( The year is started, start the month. ) | |
733 | + DTM 0 DAYCOUNT D@ D+ 2DUP DAYCOUNT ! | |
734 | + 2DUP DPWK JM/MOD 2DROP DOWKSTATE ! ( Overwrite the state, don't sum it. ) | |
735 | + | |
736 | +; | |
737 | + | |
738 | + | |
739 | + | |
740 | +: PRMONTH ( year month day --- ) | |
741 | + >R OVER STYCYCLES | |
742 | + | |
743 | +Have to adjust by defined 1st day of week. | |
744 | + | |
745 | + | |
746 | + | |
747 | + | |
748 | +( Lots -- 6? -- of 0s left behind on modern Forths. ) | |
749 | + | |
750 | + | |
380 | 751 | ( Ancient Forths do not have standard WORDs, ) |
381 | 752 | ( and that makes it hard to have portable arrays of strings for those Forths. ) |
382 | 753 | : TPWDAY ( n --- ) ( TYPE the name of the day of the week. ) |
@@ -433,159 +804,4 @@ CELLWIDTH - ALLOT ( Back up to store values. ) | ||
433 | 804 | |
434 | 805 | |
435 | 806 | |
436 | -( Below here is scratch work I'm leaving for my notes. ) | |
437 | -( It can be deleted. ) | |
438 | - | |
439 | -: oldSU1MONTH ( startfractional startdays -- endfractional enddays ) | |
440 | - FDMONTH + ( Add the whole part. ) | |
441 | - SWAP ( Make the fractional part available to work on. ) | |
442 | - MNUMERATOR + ( Add the fractional part. ) | |
443 | - DUP MDENOMINATOR < ( Have we got a whole day yet? ) | |
444 | - IF | |
445 | - SWAP ( No, restore stack order for next pass. ) | |
446 | - ELSE | |
447 | - MDENOMINATOR - ( Take one whole day from the fractional part. ) | |
448 | - SWAP 1+ ( Restore stack and add the day carried in. ) | |
449 | - ENDIF | |
450 | -; | |
451 | - | |
452 | -: oldPRMONTH ( fractional days -- fractional days ) | |
453 | - SPACE DUP PSNUM POINT ( whole days ) | |
454 | - OVER 1000 UM* ( Fake three digits of decimal precision. ) | |
455 | - MROUNDFUDGE 0 D+ ( Round the bottom digit. ) | |
456 | - MDENOMINATOR FM/MOD ( Divide, or evaluate the fraction. ) | |
457 | - S>D <# # # # #> ( Formatting puts most significant digits in buffer first. ) | |
458 | - TYPE ( Fake decimal output. ) | |
459 | - DROP SPACE | |
460 | -; | |
461 | - | |
462 | -: oldSH1IDEALYEAR ( year daysmemory fractional days -- year daysmemory fractional days ) | |
463 | - CR | |
464 | - 12 0 DO | |
465 | - 3 LC@ PSNUM SPACE ( year ) | |
466 | - I PSNUM COLON SPACE | |
467 | - oldSU1MONTH | |
468 | - DUP 3 LC@ - ( difference in days ) | |
469 | - 2 LC@ ( ceiling ) IF 1+ ENDIF | |
470 | - DUP PSNUM SPACE ( show theoretical days in month ) | |
471 | - 3 LC@ + ( sum of days ) | |
472 | - LPAREN DUP PSNUM COMMA SPACE | |
473 | - 2 LC! ( update ) | |
474 | - oldPRMONTH RPAREN CR | |
475 | - LOOP | |
476 | -; | |
477 | - | |
478 | -: oldSHOWIDEALMONTHS ( years -- ) | |
479 | - >R | |
480 | - 0 0 0 0 ( year, daysmemory, fractional, days ) | |
481 | - R> 0 DO | |
482 | - CR | |
483 | - oldSH1IDEALYEAR | |
484 | - 3 LC@ 1+ 3 LC! | |
485 | - LOOP | |
486 | - DROP DROP DROP DROP | |
487 | -; | |
488 | - | |
489 | -: oldSH1YEAR ( year daysmemory fractional days -- year daysmemory fractional days ) | |
490 | - CR | |
491 | - 12 0 DO | |
492 | - 3 LC@ PSNUM SPACE ( year ) | |
493 | - I PSNUM COLON SPACE | |
494 | - SU1MONTH ( ideal month ) | |
495 | - 3 LC@ I DIMONTH ( real month ) | |
496 | - DUP PSNUM SPACE ( show days in month ) | |
497 | - 3 LC@ + ( sum of days ) | |
498 | - LPAREN DUP PSNUM COMMA SPACE | |
499 | - 2 LC! ( update ) | |
500 | - PRMONTH RPAREN CR | |
501 | - LOOP | |
502 | -; | |
503 | - | |
504 | -: oldSHOWMONTHS ( years -- ) | |
505 | - >R | |
506 | - 0 0 0 0 ( year, daysmemory, fractional, days ) | |
507 | - R> 0 DO | |
508 | - CR | |
509 | - SH1YEAR | |
510 | - 3 LC@ 1+ 3 LC! | |
511 | - LOOP | |
512 | - DROP DROP DROP DROP | |
513 | -; | |
514 | - | |
515 | -: V2-SHOWMONTHS ( years -- ) | |
516 | - >R | |
517 | - 0 0 0 ( daysmemory, fractional, days ) | |
518 | - R> 0 DO | |
519 | - CR | |
520 | - 12 0 DO | |
521 | - J PSNUM SPACE ( year ) | |
522 | - I PSNUM COLON SPACE | |
523 | - SU1MONTH | |
524 | - DUP 3 LC@ - ( difference in days ) | |
525 | - 2 LC@ ( ceiling ) IF 1+ ENDIF | |
526 | - DUP PSNUM SPACE ( show theoretical days in month ) | |
527 | - 3 LC@ + ( sum of days ) | |
528 | - LPAREN DUP PSNUM COMMA SPACE | |
529 | - 2 LC! ( update ) | |
530 | - PRMONTH RPAREN CR | |
531 | - LOOP | |
532 | - LOOP | |
533 | - DROP DROP DROP | |
534 | -; | |
535 | - | |
536 | - | |
537 | -: NUMERATORS ( count -- ) | |
538 | -DUP 1+ 0 DO | |
539 | - I PSNUM COLON SPACE | |
540 | - I 1000 * OVER / PSNUM COMMA ( 1000 times I divided by count ) | |
541 | - SPACE LOOP | |
542 | -DROP ; | |
543 | - | |
544 | -: FRACTIONS ( count -- ) | |
545 | -1 DO | |
546 | - I NUMERATORS CR | |
547 | -LOOP ; | |
548 | - | |
549 | -( : ABS number -- absolute-value *** built in! *** ) | |
550 | -( DUP 0< IF NEGATE THEN ; ) | |
551 | - | |
552 | -: WITHIN1 ( n1 n2 -- flag ) | |
553 | - - ABS 1 <= ; ( n1 and n2 are within 1 of each other ) | |
554 | - | |
555 | -( Negatives end in division by zero or infinite loop. ) | |
556 | -: SQRT ( number -- square-root ) | |
557 | -DUP IF ( square root of zero is zero. ) | |
558 | - ABS | |
559 | - 2 ( initial guess ) | |
560 | - BEGIN | |
561 | - OVER OVER / ( test guess by divide ) | |
562 | - OVER OVER - ABS 1 <= ( number guess quotient flag ) | |
563 | - IF ( number guess quotient ) | |
564 | - MIN -1 ( number result flag ) | |
565 | - ELSE | |
566 | - OVER + 2 / ( number guess avg ) | |
567 | - SWAP OVER ( number avg guess avg ) | |
568 | - - 1 <= ( number avg flag ) ( Integer average will always be floored. ) | |
569 | - ENDIF | |
570 | - UNTIL ( number result ) | |
571 | - SWAP DROP | |
572 | -ENDIF ; | |
573 | - | |
574 | - | |
575 | -353 CONSTANT DPYEAR ( nominal days per year ) | |
576 | - | |
577 | -7 CONSTANT 7YEARS | |
578 | - | |
579 | -2 CONSTANT DS7CYCLE ( days short in seven year cycle ) | |
580 | - | |
581 | -DPYEAR 7YEARS * DS7CYCLE - CONSTANT DP7YEAR ( whole days per 7 year cycle ) | |
582 | - | |
583 | -7YEARS 7 2 * * CONSTANT 98YEARS | |
584 | - | |
585 | -98YEARS 7YEARS / DS7CYCLE * 1 + CONSTANT DS98CYCLE ( days short in 98 year cycle ) | |
586 | - | |
587 | -98YEARS 7 * CONSTANT 686YEARS | |
588 | - | |
589 | -686YEARS 98YEARS / DS98CYCLE * 2 - CONSTANT DS686CYCLE ( days short in 686 year cycle ) | |
590 | - | |
591 | 807 |
@@ -44,7 +44,7 @@ year/longmontha | ||
44 | 44 | ( fastmoon is in prograde orbit with xhilr and tidelocked, ) |
45 | 45 | ( slowmoon is retrograde orbit with xhilr and not tidelocked, retrograde rotation in equilibrium with slowmoon ) |
46 | 46 | |
47 | -( Full double solar eclipse ) | |
47 | +( Full double solar eclipse on death? ) | |
48 | 48 | |
49 | 49 | |
50 | 50 | : U/R >R R U/ SWAP 2 * 0 R> U/ SWAP DROP + ; |
@@ -0,0 +1,55 @@ | ||
1 | +#include <stdlib.h> | |
2 | +#include <stdio.h> | |
3 | +#include <string.h> | |
4 | + | |
5 | +typedef struct string_header_s | |
6 | +{ short length; | |
7 | + char string[ 1 ]; | |
8 | +} string_header_t; | |
9 | + | |
10 | +char bigblock[ 100000 ]; | |
11 | +char * here = bigblock; | |
12 | + | |
13 | +string_header_t * string_allocate( long length ) | |
14 | +{ char * place = here;; | |
15 | + if ( ( place = here + length + sizeof (string_header_t) ) >= bigblock + 100000 ) | |
16 | + { return NULL; | |
17 | + } | |
18 | + here = place; | |
19 | + ( (string_header_t *) place )->length = length; | |
20 | + return (string_header_t *) place; | |
21 | +} | |
22 | + | |
23 | +string_header_t * string_save( char string[] ) | |
24 | +{ long length = strlen( string ); | |
25 | + string_header_t * headerp = string_allocate( length ); | |
26 | + memcpy( headerp->string, string, length ); | |
27 | + headerp->string[ length ] = '\0'; | |
28 | + return headerp; | |
29 | +} | |
30 | + | |
31 | +void print_string( string_header_t * header ) | |
32 | +{ int i; | |
33 | + for ( i = 0; i < header->length; ++i ) | |
34 | + { putchar( header->string[ i ] ); | |
35 | + } | |
36 | +} | |
37 | + | |
38 | + | |
39 | +int main ( int argc, char * argv[] ) | |
40 | +{ string_header_t * thing; | |
41 | + | |
42 | +puts( "before thing" ); | |
43 | + | |
44 | + thing = string_save( "hello" ); | |
45 | + | |
46 | +puts( "after thing" ); | |
47 | + | |
48 | + /* ... */ | |
49 | + | |
50 | + print_string( thing ); | |
51 | + putchar( '\n' ); | |
52 | + | |
53 | + return EXIT_SUCCESS; | |
54 | +} | |
55 | + |