Obsah / Utility / TEXTFORM / ExpSToTextBuf, ExpCToTextBuf
Zdrojový kód: INCLUDE\UTIL\TEXTFORM.INC, UTIL\TEXTFORM.ASM
Související:
ExpToTextBufN | Délka textu formátovaného čísla s exponentem | |
MixSToTextBuf | Zformátování smíšeného desetinného čísla do bufferu, malé "e" | |
MixCToTextBuf | Zformátování smíšeného desetinného čísla do bufferu, velké "E" | |
FormToTextBuf | Zformátování textu do bufferu |
ExpSToTextBuf, ExpCToTextBuf - Zformátování čísla s exponentem do bufferu
Funkce ExpSToTextBuf a ExpCToTextBuf zkonvertují desetinné číslo na text ve formátovaném tvaru s exponentem. ExpSToTextBuf použije malé písmeno exponentu "e", ExpCToTextBuf velké písmeno "E". Velikost písmene exponentu přitom nemusí odpovídat formátovacímu příznaku FORMTYPE_Cap_b, který vypne zaokrouhlování poslední číslice.
|
Na vstupu každé z funkcí obsahuje registr ST0 desetinné číslo ke konverzi, registr EBX obsahuje formátovací parametry FORMPAR (ne ukazatel), registr ECX ukazatel na popisovač národnostních informací NATIONAL, registr ESI čítač zbylého místa v cílovém bufferu a registr EDI ukazatel do cílového bufferu. Na výstupu z funkce jsou registry ESI a EDI posunuty na novou ukládací pozici. Funkce používá další 2 registry koprocesoru. Vstupní číslo v registru ST0 zůstává zachováno, neuvolňuje se ze zásobníku koprocesoru. K uvolnění čísla z registru ST0 lze použít instrukci "ffreep st0" volanou po ukončení funkce. Funkce předpokládá, že koprocesor je v implicitním nastavení - přesnost 64 bitů, zaokrouhlení k nejbližšímu.
Funkce používá lokální proměnné s bázovým registrem EBP. Proměnné s kladným offsetem (EXPNat) jsou použity jen pro čtení, jejich obsah není modifikován. EXPNat je ukazatel na národnostní informace NATIONAL (vstupní registr ECX). EXPForm jsou formátovací parametry FORMPAR (vstupní registr EBX). EXPLen je délka ukládaného textu. EXPChar je znak exponentu (malé "e" nebo velké "E"). EXPSign jsou příznaky - bit 7 označuje záporné znaménko čísla, bit 6 je záporné znaménko exponentu. EXPFloat je desetinné číslo v zásobníku a skládá se z částí EXPMantL - nižší dvojslovo mantisy, EXPMantH - vyšší dvojslovo mantisy a EXPExp - exponent. EXPStack je velikost lokálních proměnných v zásobníku.
|
Na začátku funkce ExpSToTextBuf je nejdříve proveden test volného místa v cílovém bufferu. Není-li v cílovém bufferu volné místo, funkce se ihned ukončí.
Po úschově registrů se vytvoří v zásobníku místo pro lokální proměnné. Do proměnné EXPChar se připraví znak exponentu malé "e".
|
Začátek funkce ExpCToTextBuf je shodný se začátkem funkce ExpSToTextBuf s tím rozdílem, že do proměnné EXPChar se připraví znak exponentu velké "E". Dále již pokračují obě funkce společnou větví programu.
|
Je-li požadována alternativní přesnost, má parametr FORMPAR_Prec formátovacích parametrů význam celkového počtu číslic namísto počtu číslic za desetinnou čárkou. Proto se v tom případě požadovaná přesnost opraví tak, že se sníží o 1. V případě podtečení se omezí na alespoň 1 číslici (není podporována přesnost 0 významných číslic). Formátovací parametry se uloží do lokální proměnní EXPForm.
|
Nyní se připraví exponent konvertovaného čísla. Číslo se uloží do bufferu v zásobníku EXPFloat (nejdříve se musí zduplikovat, protože není k dispozici instrukce pro uložení čísla v rozšířené přesnosti bez uvolnění čísla ze zásobníku koprocesoru).
Exponent čísla EXPExp se načte do registru EDX. Do proměnné EXPSign se uchová znaménko čísla, současně se vynulují ostatní bity EXPSign.
|
Konvertované číslo se zduplikuje (aby mohlo být modifikováno a přitom zůstalo vstupní číslo uchováno) a převede se na absolutní hodnotu. Vynulováním nejvyššího bitu v registru DX se vynuluje znaménkový bit. Je-li exponent v registru DX nulový, jedná se o speciální případ nuly nebo nenormalizovaného čísla.
|
V případě nulového exponentu se provede test mantisy na nulu. Není-li mantisa nulová, jedná se o nenormalizované číslo (s exponentem menším než přibližně 1e-4931), takové číslo se bude dále zpracovávat běžným způsobem.
Jsou-li exponent i mantisa nulové, jedná se o nulu. Číslo je uvolněno ze zásobníku koprocesoru, do registru EBX je připraven nulový dekadický exponent a přeskočí se část rozdělující číslo na exponent a mantisu. V případě požadavku ořezání koncových nul se omezí přesnost na 0 desetinných číslic.
|
Má-li exponent v registru DX hodnotu 7FFFh, jedná se o další zvláštní případ - nekonečno nebo nedefinované číslo. Číslo se uvolní ze zásobníku koprocesoru, do registru AH (bit 7) se připraví příznak záporného znaménka, do registru ECX se připraví ukazatel na národnostní informace, do registru EDX se připraví ukazatel na buffer čísla v zásobníku a voláním funkce FloatInfNan se dekóduje text speciálního případu do výstupního bufferu. Je-li navrácen příznak ZY, došlo k přetečení výstupního bufferu a funkce se ihned ukončí. Jinak se pokračuje uložením koncových mezer (v registru EAX je navrácena délka textu).
|
Dále bude pokračovat obsluha rozložení čísla na číslice. Pomocí funkce FloatSplit je číslo rozloženo na mantisu a dekadický exponent. Na vstupu funkce je v registru EDX binární exponent čísla, registr ECX ukazuje na buffer čísla v zásobníku a v registru ST0 je absolutní hodnota konvertovaného čísla. Funkce navrací v registru EBX dekadický exponent a v registru ST0 mantisu čísla (normalizovanou do rozsahu 1 včetně až 10 vyjma).
|
Číslo je pomocí funkce FloatMantBCD zaokrouhleno na poslední číslici a rozloženo na jednotlivé číslice. Před voláním funkce je do registru EAX připravena požadovaná přesnost, do registru ECX ukazatel na buffer čísla v zásobníku, registr EBX obsahuje dekadický exponent. Testem příznaku FORMTYPE_Cap_b je funkci předán příznak, zda se má vypnout zaokrouhlování poslední zobrazené číslice.
|
Mají-li být ořezány nevýznamné koncové nuly, je funkcí FloatTrunc zjištěna skutečná přesnost čísla (tj. počet platných desetinných míst). Je-li skutečná přesnost nižší než požadovaná, opraví se parametr FORMPAR_Prec na skutečnou přesnost.
|
V další části bude zjištěna délka textu dekódovaného čísla. Do registru EAX se připraví požadovaná přesnost představující počet číslic za desetinnou tečkou. Není-li počet číslic za tečkou nulový, zapne se vynuceně příznak indikující, že se desetinná tečka použije. Pokud je požadována desetinná tečka, délka textu se zvýší o 1.
|
Je-li číslo záporné nebo je-li vynuceně znaménko (nebo náhradní mezera) vyžadováno vždy, je délka textu zvýšena o 1 znak znaménka.
|
Připraví se absolutní hodnota dekadického exponentu a příznak v proměnné EXPSign (bit 6) indikující, že exponent je záporný.
|
Přičte se délka exponentu. Exponent se skládá z 1 znaku oddělovače exponentu ("e" nebo "E"), 1 znaku znaménka a minimálně 3 číslic exponentu. Je-li exponent 1000 a více, bude mít exponent 4 číslice, délka textu se proto zvýší o 1. Výsledná délka textu se uloží do proměnné EXPLen a také do registru EDX.
|
Všechny potřebné informace jsou nyní již k dispozici a proto může být zahájeno dekódování čísla do výstupního bufferu.
Není-li číslo zarovnáno doleva (příznak FORMFLAG1_Left) a nejsou-li ani požadovány nuly (příznak FORMFLAG2_Zero), je nutno před číslo doplnit úvodní mezery. Do registru ECX se připraví z parametru FORMPAR_Width požadovaná šířka pole. Odečtením délky textu z registru EDX se obdrží zbývající šířka pro okraje. Má-li být text centrován, použije se pouze polovina mezer se zaokrouhlením dolů.
V cyklu se ukládají znaky mezer do cílového bufferu. Počet mezer je v registru ECX. Dekrementací registru ESI se ověřuje, zda bude v bufferu místo pro další znak. Pokud čítač ESI dosáhne nuly, dosáhlo se konce cílového bufferu a funkce se ukončí.
|
Před číslo se uloží znaménko. Je-li číslo záporné, uloží se znaménko mínus "-". Je-li znaménko vynucené (příznak FORMFLAG1_Sign), uloží se znaménko plus "+". Má-li být mezera místo kladného znaménka (příznak FORMFLAG1_Space), uloží se znak mezery " ". Jinak se žádný znak neuloží. Pokud čítač ESI volného místa v cílovém bufferu dosáhl nuly, funkce se ihned ukončí.
|
Má-li být číslo doplněno nulami namísto mezerami, uloží se před začátek čísla úvodní nuly. Do registru ECX se připraví požadovaná šířka pole, odečte se délka textu a uloží se nuly. Pokud během ukládání čítač ESI volného místa v cílovém bufferu dosáhne nuly, funkce se ihned ukončí.
|
Bude následovat dekódování jednotlivých číslic mantisy. Do registru EDX se připraví ukazatel na začátek mantisy v zásobníku. První číslice (z nižší tetrády prvního bajtu) se uloží vždy, jedná se o celočíselnou část mantisy. Pokud čítač ESI volného místa v cílovém bufferu dosáhl nuly, funkce se ihned ukončí.
|
Za první číslicí se uloží oddělovač desetinných míst, ale to jen v případě, že má být uložen. Příznak FORMFLAG2_Alt je již připraven tak, že není-li nastaven, nebudou následovat žádné desetinné číslice a další operace se mohou přeskočit. Pokud během ukládání oddělovače desetinných míst čítač ESI volného místa v cílovém bufferu dosáhne nuly, funkce se ihned ukončí.
|
Do registru ECX se připraví počet desetinných číslic a omezí se na maximální počet 18 číslic.
Číslice mantisy jsou v zásobníku uloženy jako BCD číslice, tj. každý bajt mantisy obsahuje v nižší tetrádě první číslici a v druhé tetrádě druhou číslici. První číslice byla již dekódována před oddělovačem desetinných míst, proto cyklus začíná dekódováním druhé číslice (z vyšší tetrády) a pokračuje dekódováním první číslice z dalšího bajtu. Pokud během ukládání číslic čítač ESI volného místa v cílovém bufferu dosáhne nuly, funkce se ihned ukončí.
|
Následuje uložení nevýznamných koncových nul. Nuly se uloží v případě, že je požadována vyšší přesnost než 18 číslic za oddělovačem desetinných míst, jinak byly nuly již zajištěny mantisou. Pokud během ukládání číslic čítač ESI volného místa v cílovém bufferu dosáhne nuly, funkce se ihned ukončí.
|
Za mantisou bude uložen exponent. Absolutní hodnota dekadického exponentu je v registru EBX. Nejdříve se uloží oddělovací znak exponentu, který je v proměnné EXPChar (písmeno malé "e" nebo velké "E"). Za oddělovacím znakem exponentu se uloží znak znaménka "-" nebo "+" podle příznakového bitu v proměnné EXPSign (bit 6).
|
Exponent se bude dekódovat jako 3 nebo 4 číslice. Vydělením exponentu číslem 1000 se obdrží nejvyšší číslice exponentu (tisíce). Pro urychlení se namísto operace dělení použije vynásobení převrácenou hodnotou. Nejvyšší číslice exponentu se uloží jen v případě, že není nulová. Po uložení číslice tisíců se číslice odečte od dekadického exponentu.
Vydělením exponentu (nebo jeho zbytku bez tisíců) číslem 100 se obdrží číslice stovek. Pro urychlení se namísto operace dělení použije vynásobení převrácenou hodnotou. Číslice stovek se odečte od exponentu v registru EBX.
Nakonec se uloží číslice jednotek a desítek, k rozložení exponentu na jednotky a desítky se použije instrukce AAM. Pokud během ukládání číslic exponentu čítač ESI volného místa v cílovém bufferu dosáhne nuly, funkce se ihned ukončí.
|
Poslední operací je uložení mezer za koncem čísla. Je-li požadováno použití nul namísto mezer, není potřeba již ukládat žádnou mezeru a funkce se ukončí. Jinak se do registru EAX načte délka textu (bez mezer) a do registru ECX požadovaná šířka pole, odečtením zůstane v registru ECX počet zbývajících mezer. Pokud žádné mezery pro okraje nezbyly, funkce se ukončí.
Je-li nastaven příznakový bit FORMFLAG1_Left, je číslo zarovnáno doleva, ihned se přejde k ukládání mezer za číslo. Není-li tento příznak nastaven a není-li nastaven ani příznakový bit FORMFLAG2_Cent, bylo číslo zarovnáno doprava a mezery tedy již byly uloženy dříve, takže se funkce ukončí. Jinak platí, že číslo je centrováno. Do registru ECX se připraví poloviční počet mezer, ale tentokrát se zaokrouhlí nahoru (aby se zachytila případná lichá mezera).
Následuje ukládání mezer do bufferu. Počet mezer je dán čítačem v registru ECX. Současně se sleduje zbývající volné místo v cílovém bufferu čítáním registru ESI. Pokud dosáhne nuly, bylo dosaženo konce bufferu a smyčka se ukončí.
Obsah / Utility / TEXTFORM / ExpSToTextBuf, ExpCToTextBuf