Výpočet sínusu s komentárom od Busyho
Spektrácka kalkulačka RST #28 počíta sínus pomocou polynomického rozvoja. Je to spôsob síce krásny, výsledok dostaneme na 8 až 10 platných číslic, ale veľmi pomalý, pretože je nutné pri ňom urobiť veľa zložitých operácií. Pre demomaking potrebujeme presný opak - výpočet musí byť veľmi rýchly a presnosť nám (obvykle) úplne postačí na osem bitov (v rozsahu 0..255).
Rutinka na výpočet sínusu využíva skutočnosť, že jednotlivé vlnovky na sínusoide sa veľmi podobajú na paraboly. Preto sínusový priebeh aproximuje parabolami. Samotný priebeh paraboly sa vypočíta veľmi jednoducho: Y=X^2=X*X To znamená, že potrebujeme len jedno násobenie a zopár jednoduchých, v podstate triviálnych manipulácií, na ktoré máme priamo inštrukcie.
Na začiatku rutinky musíme mať nejak zadaný uhol - v akých jednotkách ho budeme mať. Radiány by som pre spracovanie v asembleri radšej nedoporučoval, klasické stupne, kde 360 stupňov je celý kruh, sú už zaujímavejšie, ale toto číslo sa nám už nevojde do jedného bajtu. Pre spracovanie v asembleri je ideálne si kruh rozdeliť na 256 “asembleristických” stupňov. Potom sa celý kruh krásne vojde do jedného bajtu, pre neustále otáčanie okolo kruhu nám stačí obyčajný osembitový inkrement a pretečenie nám zároveň rieši modulo pri viac otáčkach.
Na konci rutinky musíme vedieť, aký výsledok z rutinky očakávame. Matematický sínus by mal mať rozsah výstupných hodnôt od -1 do +1. Keďže ale v asembleri sa desatinným číslam chceme vyhnúť, namapujme si tento interval ←1,+1> na rozsah presne jedného bajtu, t.j. <0,255>. To znamená, že sínus nám vráti 0 tam, kde by mal dávať -1, a 255 tam, kde +1. Nuž a tam, kde by mal dávať reálnu nulu, nám vráti stred intervalu 128.
A teraz už poďme na samotnú rutinku.
Na začiatku sa “pootočíme” o štvrťkruh, pretože je to výhodné pre ďalší výpočet. Pootočenie urobíme pripočítaním uhla zodpovedajúcemu štvrtine kruhu, t.j. hodnoty 64. Z pôvodného kruhu s uhlami 0..255 získame kruh s uhlami 64..255,0..63
sinus add a,$40
Ak nám na presnej fáze sínusu nezáleží, resp. je nám tak nejak jedno, či potrebujeme priamo sínus, alebo to môže byť aj kosínus, toto pootočenie môžeme úplne vynechať. Napríklad v situácii, keď sa má niečo na obrazovke vlniť a je jedno v akej konkrétnej polohe sa nachádza v konkrétnom časovom okamihu, dôležité je, len aby sa to vlnilo.
Nulové D budeme potrebovať neskôr kvôli násobeniu.
ld d,$00
Uhol si dočasne odložíme do C, pretože ho budeme ešte potrebovať.
ld c,a
Teraz uhol vynásobíme štyrmi.
add a,a add a,a
Teoreticky by teraz náš kruh mal byť rozdelený na 1024 stupňov, avšak keďže do A sa vojde len 8-bitový údaj, získame tým to, že v každej štvrtine kruhu máme uhol od 0 do 255. Čiže celý kruh namiesto 0..1023 vyzerá takto: 0..255, 0..255, 0..255, 0..255
ld e,a
Do carry nám vypadol deviaty bit po poslednom zdvojnásobení uhla. Tým pádom carry nesie informáciu o tom, či náš zadaný uhol leží v párnej, alebo nepárnej štvrtine kruhu.
sbc a,a
Týmto sme carry “rozkopírovali” do všetkých bitov A, takže A je nulové pre prvú a tretiu štvrtinu kruhu a 255 pre druhú a štvrtú štvrtinu.
V registri E máme stále odložený štvornásobok uhla.
xor e
Po tejto operácii invertujeme hodnotu uhla pre párne štvrtiny kruhu, takže kruh bude vyzerať takto: 0..255, 255..0, 0..255, 255..0
ld e,a ld h,d ld l,e
A teraz ideme počítať rovnicu paraboly Y=X^2 V registroch A,E,L máme pripravené X, registre H a D sú nulové.
rra
Ešte pred samotným násobením sme si hodnotu X v A vydelili dvomi, takže A bude obsahovať číslo v rozsahu 0..127, aby sme po výpočte získali výsledok v požadovanom rozsahu.
A tu už nasleduje samotný výpočet: HL = E * (A/2) + L Záverečné +L je malá korekcia, aby sa parabola čo najviac podobala na sínus.
mksin1 add hl,de dec a jr nz,mksin1
Samotné násobenie sme robili klasickým N-násobným sčítaním v slučke. Dalo by sa zrýchliť použitím bitoveho násobenia, ale rutinka by potom bola dlhšia. Výsledok násobenia je v registri HL a je to číslo v rozsahu 0..32767. Náš kruh vyzerá teraz takto: 0..32767, 32767..0, 0..32767, 32767..0, pričom ale jednotlivé časti už nie sú lineárne úsečky, ale časti paraboly.
Na to, aby sa nám kruh podobal na sínusoidu, musíme teraz dve prostredné časti otočiť “hore nohami”. Takže najprv si zistíme, ktoré su prostredné časti:
ld a,#40 add a,c
Vzali sme pôvodný uhol 0..255, pripočítaním 64 sme ho pootočili o štvrtinu kruhu. Vzniklo nám toto: 64..127,128..255,0..63
add a,a
Po vynásobení dvomi nám časti kruhu s uhlom väčším ako 128 pretiekli, takže sa nám pre hodnoty 128..255 nastavilo carry. Toto carry si zase rozkopírujeme do všetkých bitov A.
sbc a,a
V HL stále máme niečo takéto: 0..32767, 32767..0, 0..32767, 32767..0 Keďže nám stačí 8-bitová presnosť, vezmeme si len vyšší bajt v H. Takze v H budeme mat nieco taketo: 0..127, 127..0, 0..127, 127..0
V A máme nuly pre prvú a poslednú štvrtinu kruhu a 255 pre prostredné štvrtiny kruhu. A teraz príde to najzaujímavejšie !
xor h
Po tejto operácii sa nám otočia “hore nohami” dve štvrtiny kruhu uprostred. Takže v A budeme mať toto: 0..127, 128..255, 255..128, 127..0
Toto keď teraz posunieme o štvrťkruh (viď úvodné add a,$40 na začiatku rutinky), máme jednu krásnu ukážkovú periódu zo sínusovky: 128..255, 255..128, 127..0, 0..127
A tým je výpočet sínusu hotový :)
Navigation: general . math . graphic . sound . system . other . back to start