Bystrému a hlavně pravidelnému čtenáři těchto webových stránek dozajista neuniklo, že jejich autor se v předchozích ukázkách pro různé shluky programových řádků zdráhal užít názvu program. V případě ukázky výpočtu data velikonoční neděle je takové pojmenovaní naprosto legitimní, neboť se jedná o "monument" zvíci osmdesáti programových řádků.
Program (Všimli jste si? Ani náznak uzardění :-) je pro kalkulátor HP-35s, a tentokrát se sluší podotknout, že výhradně pro tento. Jeho transkripce pro jiné typy je samozřejmě možná, ale ne zcela jednoduchá. Zdaleka ne všechny modely disponují funkcemi RMDR nebo INT÷. Ani přímá adresace libovolného registru RPN stacku (viz instrukce REGY) není zcela běžnou výbavou. Snad jen typy HP-41C nebo HP-42s jí disponují.
Inspirací pro tento program je postup publikovaný v knize Umění programování - Základní algoritmy amerického autora Donalda E. Knutha, kterému bude lidstvo vděčit další tisíciletí za jeho famózní soubor knih o programování. Jak na to Mistr šel, popatřte sem. Mistr jistě promine, ale my mladí (rozumějte: narozeni až po válce - té druhé, pochopitelně) vše snáze pochopíme, bude-li postup napsán v jazyku C. Názvy proměnných jsou ponechány a jejich významy rekapituluje následující seznam.
Y | Year | G | Golden number |
C | Century |
X | Century leap year adjustment |
Z | Moon's orbit adjustment |
D | Sunday date |
E | Epact |
N | Day of month |
A zde konečně program "Céčku".
#define INTG void easter(int y) { int g, c, x, z, d, e, n, m; g = y % 19 + 1; c = INTG(y / 100) + 1; x = INTG((3 * c) / 4) - 12; z = INTG((8 * c + 5) / 25) - 5; d = INTG((5 * y) / 4) - x - 10; e = (11 * g + 20 + z - x) % 30; if(e == 25 && g > 11 || e == 24) ++e; n = 44 - e; if(n < 21) n += 30; m = n + 7 - (d + n) % 7; if(m > 31) { m -= 31; printf("%d. dubna %d\n", m, y); } else printf("%d. brezna %d\n", m, y); }
Pro snazší realizaci v "kalkulačkovém pojetí" je postup upraven. Jsou zde patrné tři výrazné změny:
#define INTG(v) ((int)floor(v)) #define SGN(v) ((v) == 0 ? 0 : ((v) > 0 ? 1 : -1)) void easter(int y) { int g, c, x, z, d, e, n, m, f, h; g = y % 19 + 1; c = INTG(y / 100) + 1; x = INTG(0.75 * c) - 2; z = INTG(0.32 * c + 0.2); d = INTG(1.25 * y) - x; e = (11 * g + 25 + z - x) % 30; f = e - 24; do { if(f != 0) { h = -(SGN(11 - g) >> 1); if(f != h) break; } ++f; } while(0); n = -f; if(n ≤ 0) n += 30; n += 20; m = n + 7 - (d + n) % 7; if(m > 31) { m -= 31; printf("%d. dubna %d\n", m, y); } else printf("%d. brezna %d\n", m, y); }
A nyní nebojácně a s plným odhodláním přistupme k hotovému kódu pro HP-35s. Je třeba přiznat, že celková délka (počet bajtů) programu je v podstatě srovnatelná s použitím algebraického módu. Znamená to, že se vzorce "slepě" opíšou do sekvence výrazů s proměnnými G, C, X, Z, D, E, N, M (viz EQN). Jaký je potom přínos předkládaného RPN běsnění? Dvojí:
ADDR | CODE | X | Y | Z | T |
---|---|---|---|---|---|
Y001 | LBL Y | y | |||
Y002 | STO Y | y | |||
Y003 | 19 | 19 | y | ||
Y004 | RMDR | y % 19 | |||
Y005 | 1 | 1 | y % 19 | ||
Y006 | + | g | |||
Y007 | LASTx | 1 | g | ||
Y008 | RCL Y | y | 1 | g | |
Y009 | 100 | 100 | y | 1 | g |
Y010 | INT÷ | intg(y / 100) | 1 | g | g |
Y011 | + | c | g | g | g |
Y012 | 0.32 | 0.32 | c | g | g |
Y013 | REGY | c | 0.32 | c | g |
Y014 | × | 0.32 c | c | g | g |
Y015 | 0.2 | 0.2 | 0.32 c | c | g |
Y016 | + | 0.32 c + 0.2 | c | g | g |
Y017 | INTG | z | c | g | g |
Y018 | x<>y | c | z | g | g |
Y019 | 0 4/3 | 4/3 | c | z | g |
Y020 | INT÷ | intg(0.75 c) | z | g | g |
Y021 | 2 | 2 | intg(0.75 c) | z | g |
Y022 | - | x | z | g | g |
Y023 | - | z - x | g | g | g |
Y024 | LASTx | x | z - x | g | g |
Y025 | 1.25 | 1.25 | x | z - x | g |
Y026 | RCL× Y | 1.25 y | x | z - x | g |
Y027 | INTG | intg(1.25 y) | x | z - x | g |
Y028 | x<>y | x | intg(1.25 y) | z - x | g |
Y029 | - | d | z - x | g | g |
Y030 | x<>y | z - x | d | g | g |
Y031 | 25 | 25 | z - x | d | g |
Y032 | + | 25 + z - x | d | g | g |
Y033 | 11 | 11 | 25 + z - x | d | g |
Y034 | STO H | 11 | 25 + z - x | d | g |
Registr/proměnná H = 11 | |||||
Y035 | R↑ | g | 11 | 25 + z - x | d |
Y036 | STO- H | g | 11 | 25 + z - x | d |
H = 11 - g | |||||
Y037 | × | 11 g | 25 + z - x | d | d |
Y038 | + | 11 g + 25 + z - x | d | d | d |
Y039 | 30 | 30 | 11 g + 25 + z - x | d | d |
Y040 | RMDR | e | d | d | d |
Y041 | 1 | 1 | e | d | d |
Y042 | x<>y | e | 1 | d | d |
Y043 | 24 | 24 | e | 1 | d |
Y044 | - | f = 24 - e | 1 | d | d |
Y045 | x=0? | f | 1 | d | d |
Y046 | GTO Y056 | f | 1 | d | d |
Y047 | x<>y | 1 | f | d | d |
Y048 | R↓ | f | d | d | 1 |
Y049 | RCL H | 11 - g | f | d | d |
Y050 | SGN | sgn(11 - g) | f | d | d |
Y051 | 2 | 2 | sgn(11 - g) | f | d |
Y052 | INT÷ | sgn(11 - g) / 2 | f | d | d |
Y053 | +/- | h | f | d | d |
Y054 | x<>y | f | h | d | d |
Y055 | x=y? | f | h | d | d |
Y056 | + | f | d | d | d |
Y057 | +/- | -f | d | d | |
Y058 | 30 | 30 | -f | d | |
Y059 | x<>y | -f | 30 | d | |
Y060 | x≤0? | -f | 30 | d | |
Y061 | + | -f + 30 | d | ||
Y062 | R↑ | d | -f + 30 | ||
Y063 | x<>y | -f + 30 | d | ||
Y064 | 20 | 20 | -f + 30 | d | |
Y065 | + | n | d | ||
Y066 | x<>y | d | n | ||
Y067 | REGY | n | d | n | |
Y068 | + | d + n | n | ||
Y069 | 7 | 7 | d + n | n | |
Y070 | RMDR | (d + n) % 7 | n | ||
Y071 | 7.03 | 7.03 | (d + n) % 7 | n | |
Y072 | x<>y | (d + n) % 7 | 7.03 | n | |
Y073 | - | 7.03 - (d + n) % 7 | n | ||
Y074 | + | m | |||
Y075 | 31.03 | 31.03 | m | ||
Y076 | x<>y | m | 31.03 | ||
Y077 | x≤y? | m | 31.03 | ||
Y078 | GTO Y081 | (v březnu) | |||
Y079 | 30.99 | 30.99 | m | ||
Y080 | - | (v dubnu) | |||
Y081 | RCL Y | rok | den.měsíc | ||
Y082 | RTN | ||||
LN=298, CK=ACEA |
Použití programu:
Stisk kláves | Činnost | Display |
---|---|---|
1 9 6 4 | rok, pro který se hledá datum velikonoční neděle | 0.0000 1964_ |
XEQ Y ENTER | spuštění programu | RUNNING |
výsledek: 29. březen 1964 | 29.0300 1,964.0000 |
Kontrolní výsledky lze získat zde.
Poznámka:
Program používá dvě proměnné (postaru řečeno paměťové registry) Y a H. V případě konfliktu se stejnojmennými proměnnými jiných programů je třeba je přejmenovat. Programové řádky, kterých se taková úprava týká, jsou ve výpisu barevně odlišeny.
Ještě jedna poznámka:
Někomu se může zdát, že použití dvou proměnných pro tak jednoduchý výpočet je neodpustitelná rozežranost. I pro něj tu je řešení: proměnnou H vůbec nepoužít, nahradit jí proměnnou Y (bez ní se to celé opravdu neobejde) a řádek Y081 RCL Y vypustit. Výsledek potom bude v X-registru RPN stacku a zadaný rok nebude zobrazen. Holt, každá sranda něco stojí :-).
Pokud má vůbec smysl na závěr něco zdůraznit, tak snad jedině fakt obecně platný pro všechny ukázky RPN programů na těchto webových stránkách: předkládaný program v žádném případě nebyl sestaven za účelem něco vyřešit (zde konkrétně stanovit termín velikonoc v daném roce). Účel tvorby programu je právě samotná tvorba. A to bez ohledu na její přínos. Těžko si lze představit zoufalce, který na kalkulačce píše program proto, aby zjistil datum velikonočních svátků letos, loni nebo kdykoliv v budoucnu. Daleko snáze si lze představit jiného zoufalce, který se "hnípe" s instrukcemi použitého kalkulátoru a snaží se je - jen tak ze sportu - seřadit co nejefektivněji...