Tvůrce webu je i pro tebe! Postav třeba web. Bez grafika. Bez kodéra. Hned.
wz

Obsah / Utility / TEXTFORM / FloatSplit

Zdrojový kód: INCLUDE\UTIL\TEXTFORM.INC, UTIL\TEXTFORM.ASM

Související:

FltToTextBuf   Zformátování desetinného čísla do bufferu
FltToTextBufN   Délka textu formátovaného desetinného čísla
ExpSToTextBuf   Zformátování čísla s exponentem do bufferu, malé "e"
ExpCToTextBuf   Zformátování čísla s exponentem do bufferu, velké "E"
ExpToTextBufN   Délka textu formátovaného čísla s exponentem

FloatSplit - Rozdělení desetinného čísla na mantisu a exponent

Funkce FloatSplit je interní funkce používaná funkcemi dekódujícími desetinné číslo na text. Rozděluje desetinné číslo na mantisu a exponent.


; -----------------------------------------------------------------------------
;           Internal - Split positive float to mantissa and exponent
; -----------------------------------------------------------------------------
; INPUT:	ECX = pointer to extended double float number in stack
;		EDX = binary exponent
;		ST0 = float number (positive number, not zero)
; OUTPUT:	EBX = decimal exponent
;		ST0 = mantissa (in range 1 including to 10 excluding)
; DESTROYS:	EAX, EDX
; NOTES:	It uses 1 more register from FPU stack.
; -----------------------------------------------------------------------------

Na vstupu funkce obsahuje registr ECX ukazatel na desetinné číslo v rozšířeném formátu (velikost 10 bajtů). Registr EDX obsahuje binární exponent čísla a v registru ST0 je uloženo konvertované desetinné číslo. Číslem musí být kladné číslo (ne záporné a ani ne nula). Na výstupu funkce obsahuje registr EBX dekadický exponent a registr ST0 mantisu (tj. číslo normalizované do rozsahu 1 včetně až 10 vyjma). Funkce ruší obsahy registrů EAX a EDX a používá 1 další registr matematického koprocesoru.


; ------------- Convert binary exponent to decimal exponent, 100-step (-> EDX)
; 100 * ln 10 / ln 2 = 332.1928094887
; Binary exponent in range 0 to 32766 goes to range 0 to 98.

FloatSplit:	add	edx,60		; add shift correction
		mov	eax,12929140	; EAX <- 100000000h/332.1928094887
		mul	edx		; EDX <- decimal exponent

Binární exponent čísla (v rozsahu 0 až 32766) bude nejdříve převeden na stovky dekadického exponentu. Přičtením korekční konstanty 60 se upřesní hranice pro přechod mezi stovkami exponentu. Binární exponent bude vydělen číslem 100 * ln 10 / ln 2, ale pro zrychlení se použije rychlejší operace vynásobení převrácenou hodnotou, tedy číslem (ln 2 / ln 10) / 100 * 100000000h. Výsledek (v rozsahu 0 až 98) bude v registru EDX.


; ------------- Table of exponents, step 100 (1.0e4900 to 1.0e-4900, size 1 KB)

		align	8, db 0
Exp100Tab:
		%assign EXPN 4900
		%rep	99
		dt	1.0e %+ EXPN
		%assign EXPN EXPN - 100
		%endrep

Přibližný dekadický exponent se použije k prvnímu normalizačnímu kroku - exponent se sníží o řády stovek. K tomu se použije tabulka exponentů Exp100Tab s krokem 100. Normalizační exponenty mají rozsah hodnot 1e4900 až 1e-4900.


; ------------- Multiply number with 100-step exponent

		imul	eax,edx,byte 10	; EAX <- offset of exponent
		fld	tword [eax+Exp100Tab] ; load exponent
		fmulp	st1		; multiple with exponent

; ------------- Load exponent into exponent accumulator (-> EBX)

		imul	eax,edx,byte 100 ; EAX <- exponent correction
		lea	ebx,[eax-4900]	; EBX <- exponent correction

Z tabulky Exp100Tab se načte exponent podle hodnoty stovek dekadického exponentu a to takový, aby se vykorigoval řád stovek dekadického exponentu. Tj. například pro číslo 1,234e120 se načte exponent 1e-100. Tímto číslem se normalizované číslo vynásobí a tím se dostane do rozsahu zhruba 1 až 1e+100.

Současně s normalizací čísla se aktualizuje střadač výsledného dekadického exponentu - údaj stovek exponentu se vynásobí číslem 100 a odečte se 4900, protože exponent desetinných čísel má počátek s exponentem 1e-4931 (binární exponent pro 1e-4931 má hodnotu 1).


; ------------- Store new number into stack

		fld	st0		; duplicate number
		fstp	tword [ecx]	; store number into stack

; ------------- Load exponent (-> EDX)

		fwait			; synchronize FPU
		movzx	edx,word [ecx+8] ; EDX <- exponent

Před dalším pokračováním je nutné znovu načíst novou hodnotu binárního exponentu. Normalizované číslo se uloží do lokální proměnné v zásobníku a do registru EDX se načte jeho binární exponent.


; ------------- Convert binary exponent to decimal exponent, 1-step (-> EDX)
; ln 10 / ln 2 = 3.321928094887
; Binary exponent in range 0 to 32766 goes to range 0 to 9863.

		mov	eax,1292913987	; EAX <- 100000000h/3.321928094887
		mul	edx		; EDX <- decimal exponent
		sub	edx,4932	; EDX <- correction of exponent base

Nový binární exponent čísla bude dále převeden na jednotky dekadického exponentu. Binární exponent bude vydělen číslem ln 10 / ln 2, tedy vynásoben číslem ln 2 / ln 10 * 100000000h. Po odečtení korekční konstanty 4932 (aby se exponent dostal do správného rozsahu -4931 až +4932) bude výsledek v registru EDX.


EXP1TABBEG	EQU	150		; starting exponent of Exp1Tab
EXP1TABNUM	EQU	300		; number of exponents in Exp1Tab

; ------------- Table of exponents, step 1 (1.0e150 to 1.0e-150, size 3 KB)

		align	8, db 0
Exp1Tab:
		%assign EXPN EXP1TABBEG
		%rep	EXP1TABNUM
		dt	1.0e %+ EXPN
		%assign EXPN EXPN - 1
		%endrep

Během druhého kroku normalizace se sníží dekadický exponent o řády jednotek. K tomu se použije tabulka exponentů Exp1Tab s krokem 1. Normalizační exponenty mají rozsah hodnot 1e150 až 1e-150.


; ------------- Multiply with 1-step exponent

		imul	eax,edx,byte 10	; EAX <- offset of exponent
		fld	tword [eax+Exp1Tab+EXP1TABBEG*10] ; load exponent
		fmulp	st1		; multiple with exponent

; ------------- Load exponent into exponent accumulator (-> EBX)

		add	ebx,edx		; EBX <- add exponent into accumulator

Z tabulky Exp1Tab se načte exponent podle hodnoty jednotek dekadického exponentu a to takový, aby se vykorigoval řád jednotek dekadického exponentu. Tj. například pro číslo 1,234e56 se načte exponent 1e-56. Tímto číslem se normalizované číslo vynásobí a tím se dostane do rozsahu zhruba 1 až 10.

Současně s normalizací čísla se aktualizuje střadač výsledného dekadického exponentu - údaj jednotek exponentu se přičte je střadači dekadického exponentu.


; ------------- Check if mantissa is less than 1

		fld1			; load 1
                fcomp	st1		; compare 1 with mantissa
		fstsw	ax		; AX <- FPU flags
		sahf			; get FPU flags
		ja	FloatSplit2	; mantissa is less than 1

; ------------- Check if mantissa is less than 10

		ficom	dword [Const10Num] ; compare mantissa with 10
		fstsw	ax		; AX <- FPU flags
		sahf			; get FPU flags
		jae	FloatSplit4	; mantissa is not less than 10
		ret

; ------------- Mantissa is less than 1

FloatSplit2:	fimul	dword [Const10Num] ; multiply mantissa with 10
		dec	ebx		; EBX <- exponent correction
		ret

; ------------- Mantissa is not less than 10

FloatSplit4:	fld	tword [Const01Num] ; load constant 0.1
		inc	ebx		; EBX <- exponent correction
		fmulp	st1,st0		; multiply mantissa with 0.1
		ret

Pro hodnoty ležící blízko přelomu exponentů se výsledná hodnota stále ještě může lišit o jeden dekadický řád, proto poslední normalizační krok zajistí, aby normalizovaná mantisa ležela v rozsahu 1 (včetně) až 10 (vyjma).

Mantisa v registru ST0 je porovnána s číslem 1. Je-li menší, není dosud správně normalizovaná a je potřeba provést korekci vynásobení mantisy číslem 10. Současně se dekrementací opraví vypočtený dekadický exponent a funkce se ukončí.

Dále se mantisa porovná s číslem 10. Je-li větší nebo rovna 10, není dosud správně normalizovaná a je potřeba provést korekci vynásobením mantisy číslem 0,1. Současně se inkrementací opraví vypočtený dekadický exponent a funkce se ukončí. Na rozdíl od násobení číslem 10 bylo nutné konstantu 0,1 načíst s rozšířenou přesností, aby se zachovala její plná přesnost.


Obsah / Utility / TEXTFORM / FloatSplit