Pevná řádová čárka - násobení celého čísla číslem desetinným

Ono to je docela jednoduché. Počítej s desetinným číslem úplně stejně jako by to bylo celé číslo, stačí jen vědět, že nevyjadřuje jednotky, ale binární zlomky.

Například, na desetinou část si vyhradím 1 bajt, na celou část 3 bajty, číslo zabere dohromady 4 bajty. Je to jako když desetinné číslo vynásobíš řádem zlomkové části, tedy číslem 256. Např. číslo 5 se zapíše jako 0x00000500, číslo 0.2 jako 0.2 * 256 = 51 = 0x00000033. Záporná čísla jsou opět stejná jako u běžných čísel, jen je to opět vynásobené řádem zlomkové části. Tedy např. -5 je 0xFFFFFB00 (tj. jako 0 - 5). Nejvyšší bit vyjadřuje tedy negativní číslo, ale pracuje se s ním stejně jako v běžné celočíselné aritmetice, tj. nijak zvlášť se neobsluhuje a je jen výsledkem běžných celočíselných operací. Proto je platné číslo i hodnota 0x8000… (tedy jako maximální možné záporné číslo).

Sčítání a odečítání čísel se dělá jako by to bylo celé číslo - tj. postupuje se od nejnižších řádů (bajty, slova, to co procesor umí), ty se sčítají/odčítají a provádí se přenos do vyšších řádů. Vůbec při tom není důležité kde je desetinná čárka, na algoritmu to nic nemění.

Násobení se dělá stejně jako u ručního násobení - tj. berou se jednotlivé části, násobí se mezi sebou a výsledky se přičítají do střadače. Teď nevím jistě jak se znaménkem, já to myslím řešil tak, že jsem převedl obě čísla na kladná a pak příp. negoval výsledek. U násobení se musí počítat s tím, že se zvyšuje rozsah a přesnost čísla 2x. To znamená, počítá se opět jako s celým číslem (tj. nerozlišuje se kde je desetinná tečka), ale výsledek se ukládá to bufferu, který je 2x větší, tedy desetinná část má v příkladu 2 bajty a celá 6 bajtů. Pak se převede výsledek do běžného bufferu čísla tak, že nižší polovina desetin a vyšší polovina celé části se ignoruje, použije se tedy jen ta část kolem desetinné čárky. Při násobení proto není třeba počítat přenosy přetékající rozsah nahoru, ale kvůli efektivnosti algoritmu je lepší počítat plný rozsah. Desetiny je potřeba počítat v plném rozsahu, protože ta vypouštěná část může ovlivnit výsledek kvůli zaokrouhlování.

Násobení lidé někdy počítají bitově, tj. bere se bit po bitu a přičítá rotované druhé číslo, ale když procesor umí hardwarově násobit tak by byla škoda to nevyužít, je efektivnější násobit úseky čísla podle možností procesoru.

U dělení je už horší situace. Snadnější varianta je, když se dělí číslem, které ještě zvládá hardwarová dělička procesoru. Pak se dá postupovat od vyšších řádů čísla, vzít část čísla, vydělit dělitelem a zbytek použít jako přenos do nižšího řádu. Znaménko je opět možné ošetřit převodem na absolutní hodnoty a negací výsledku (ale je možné že tohle jde jednodušeji). Při tomto dělení malým číslem se nemění rozsah výsledku, lze přímo ukládat do výstupního bufferu o stejném rozsahu.

Při dělení velkým číslem, které se musí vyjádřit v plném rozsahu, se už musí provádět dělení bitově. Dělenec se převede na dvojnásobný řád přípojením nul, tj. jako když se posune do 2x vyššího řádu. Pak se porovná dělenec a dělitel, když je dělenec větší, zapíše se do výsledku bit “1” a dělitel se od dělence odečte. Pak se dělitel rotuje o 1 bit dolů. Tedy … nějak tak, na detaily kolem dělení si teď přesně nevzpomínám.

Číslo -0,425 ve vyjádření 2+2 bajty (tedy Q15.16) se pak vyjádří jako -0,425 * 65536 = 0xFFFF9334. Kdyby části čísla nebyly násobkem bajtů, postupuje se obdobně. Např. při vyjádření Q12.4 se bude počítat s čísly stejně, jako s celými čísly představujícími desetinná čísla vynásobená 16x. Sčítání a odčítání se provádí stejně jako u celých čísel. U násobení bude výsledek větší o desetinou část, tedy při tom Q12.4 je výsledek násobení ve tvaru Q24.8. Proto se musí výsledek opravit tak, že se rotuje o 4 bity dolů. U dělení se postupuje obráceně, dělence je potřeba před dělením rotovat o 4 bity nahoru a zvýšit tak rozsah na Q24.8. Pak se vydělí jako běžné celé číslo a výsledek bude jít ve správném formátu Q12.4.