• R/O
  • HTTP
  • SSH
  • HTTPS

提交

標籤
無標籤

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Functions for working with the idealized calendar of Planet Xhilr


Commit MetaInfo

修訂ae9ce3df9af333a1c470db29d89f666cf1bbfea4 (tree)
時間2017-06-13 17:58:44
作者Joel Matthew Rees <joel.rees@gmai...>
CommiterJoel Matthew Rees

Log Message

progress, corrections, and a detour in C

Change Summary

差異

--- a/econmonths.fs
+++ b/econmonths.fs
@@ -70,35 +70,83 @@
7070 ( fig-Forth used first three character + length significance in symbol tables. )
7171
7272
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. )
7474 ( These definitions are only for ancient Forths, without the full set loaded, )
7575 ( especially pre-1983 fig and bif-c. )
7676 ( Un-comment them if you see errors like )
7777 ( UM* ? err # 0 )
7878 ( from PRMONTH or thereabouts. )
7979
80-: UM* U* ; ( modern name for unsigned mixed multiply )
80+: UM* U* ; ( u u --- ud : modern name for unsigned mixed multiply )
8181
82-( This is a cheat! Behavior is not well defined for negative numbers, )
83-( but we don't do negatives here. )
8482 ( 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 )
8686
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. )
8890
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. )
9092
9193 : 2DROP DROP DROP ; ( d --- : DROP a double, for readability. )
9294
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! )
95135
96136 ( : R@ R ; ( Modern name for copy top of return stack. )
97137
138+( Showing the above in infix won't help. )
139+
98140
99141 ( 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. )
100144
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> ;
102150
103151 SP@ SP@ - ABS CONSTANT CELLWIDTH
104152 ( Infix won't help here, either, but I can try to explain: )
@@ -144,6 +192,142 @@ SP@ SP@ - ABS CONSTANT CELLWIDTH
144192 D! ( *** Will fail in MISERABLE ways on push-up stacks! *** )
145193 ;
146194
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+
147331 ( Make things easier to read. )
148332 ( Infix will be confusing here, too. )
149333
@@ -195,28 +379,38 @@ MCYCLE MP2LCYC * CONSTANT 2LCYCLE ( years in double long cycle, should be 686 )
195379
196380 DPSKIPYEAR SCYCLE * RDSCYCLE + CONSTANT DPSCYCLE ( whole days per 7 year cycle )
197381 ( DPSCYCLE = DPSKIPYEAR × SCYCLE + RDSCYCLE )
198-( DPSCYCLE SPMCYC * DCONSTANT DPMCYCLE )
199-( DPMCYCLE = DPSCYCLE × SPMCYC )
200-( DPMCYCLE MP2LCYC * DCONSTANT DP2LCYCLE )
201-( DP2LCYCLE = DPMCYCLE × MP2LCYC )
382+
202383 ( DPMCYCLE and DP2LCYCLE would overflow on 16-bit math CPUs. )
203384 ( No particular problem on 32 bit CPUs. Need DCONSTANT for 16-bit CPUs. )
204385 ( But we need the constants more than we need to puzzle out )
205386 ( 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* ;
210387
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 )
213399
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 )
216402 ( RD2LCYCLE / 2LCYCLE is fractional part of year. )
217403 ( Ergo, length of year is DPSKIPYEAR + RD2LCYCLE / 2LCYCLE, )
218404 ( or 352 485/686 days. )
219405
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+
220414 12 CONSTANT MPYEAR ( months per year )
221415
222416 DPSKIPYEAR MPYEAR /MOD CONSTANT FDMONTH ( floor of days per month )
@@ -255,7 +449,7 @@ MDENOMINATOR 2 / CONSTANT MROUNDFUDGE
255449 SPACE 2DUP PSDNUM POINT ( whole days )
256450 2 LC@ 1000 UM* ( Fake three digits of decimal precision. )
257451 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. )
259453 S>D <# # # # #> ( Formatting puts most significant digits in buffer first. )
260454 TYPE ( Fake decimal output. )
261455 DROP SPACE
@@ -293,6 +487,7 @@ MDENOMINATOR 2 / CONSTANT MROUNDFUDGE
293487 4 CONSTANT SK2SHORTCYC
294488 48 CONSTANT SKMEDIUMCYC
295489 186 CONSTANT LPLONGCYC ( Must be short1 or short2 within the seven year cycle. )
490+LCYCLE LPLONGCYC + CONSTANT LPLONGCYC2
296491
297492 ( Since skipyears are the exception, )
298493 ( we test for skipyears instead of leapyears. )
@@ -322,7 +517,7 @@ MDENOMINATOR 2 / CONSTANT MROUNDFUDGE
322517 0 VARIABLE DIMARRAY ( Days In Months array )
323518 ( Modern Forths don't initialize, will leave 0 on stack. )
324519
325-CELLWIDTH - ALLOT ( Back up to store values. )
520+CELLWIDTH NEGATE ALLOT ( Back up to store values. )
326521
327522 30 C,
328523 29 C,
@@ -366,7 +561,7 @@ CELLWIDTH - ALLOT ( Back up to store values. )
366561 LOOP
367562 ;
368563
369-: SHOWMONTHS ( years -- )
564+: SHOWMONTHS ( years --- )
370565 >R
371566 0 0. 0 0. ( year, ddaysmemory, fractional, ddays )
372567 R> 0 DO
@@ -377,6 +572,182 @@ CELLWIDTH - ALLOT ( Back up to store values. )
377572 2DROP DROP 2DROP DROP
378573 ;
379574
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+
380751 ( Ancient Forths do not have standard WORDs, )
381752 ( and that makes it hard to have portable arrays of strings for those Forths. )
382753 : TPWDAY ( n --- ) ( TYPE the name of the day of the week. )
@@ -433,159 +804,4 @@ CELLWIDTH - ALLOT ( Back up to store values. )
433804
434805
435806
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-
591807
--- a/lunar.fs
+++ b/lunar.fs
@@ -44,7 +44,7 @@ year/longmontha
4444 ( fastmoon is in prograde orbit with xhilr and tidelocked, )
4545 ( slowmoon is retrograde orbit with xhilr and not tidelocked, retrograde rotation in equilibrium with slowmoon )
4646
47-( Full double solar eclipse )
47+( Full double solar eclipse on death? )
4848
4949
5050 : U/R >R R U/ SWAP 2 * 0 R> U/ SWAP DROP + ;
--- /dev/null
+++ b/stringheader.c
@@ -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+