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

Obsah / Utility / TEXTFORM / ExpToTextBufN

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

Související:

ExpSToTextBuf   Zformátování čísla s exponentem do bufferu, malé "e"
ExpCToTextBuf   Zformátování čísla s exponentem do bufferu, velké "E"
MixToTextBufN   Délka textu formátovaného smíšeného desetinného čísla
FormToTextBufN   Délka formátovaného textu

ExpToTextBufN - Délka textu formátovaného čísla s exponentem

Funkce ExpToTextBufN zjistí délku formátovaného čísla s exponentem v bufferu.


; -----------------------------------------------------------------------------
;  Convert float number into text buffer in exponential form - get text length
; -----------------------------------------------------------------------------
; INPUT:	ST0 = float number (it does not pop it from the FPU stack)
;		EBX = formatting parameters FORMPAR
; OUTPUT:	EAX = text length
; NOTES:	It uses 2 more registers from FPU stack.
;		To destroy FPU register you can use "ffreep st0" instruction.
; -----------------------------------------------------------------------------

Na vstupu funkce obsahuje registr ST0 desetinné číslo ke konverzi a registr EBX formátovací parametry FORMPAR (ne ukazatel). Na výstupu je navrácena v registru EAX délka textu. 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.


; ------------- Push registers

ExpToTextBufN: 	push	ebx		; push EBX
		push	ecx		; push ECX
		push	edx		; push EDX
		push	esi		; push ESI
		sub	esp,12		; create local buffer

; ------------- Prepare precision (alternate: number of significant digits)

		bt	ebx,FORMFLAG_Prec_b ; alternate precision?
		sbb	bl,0		; without first digit
		adc	bl,0		; minimal precision 0 if borrow

Po úschově obsahu registrů je v zásobníku vytvořeno volné místo pro uložení čísla v rozšířené přesnosti.

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).


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

		fld	st0		; duplicate number
		fstp	tword [esp]	; store number into stack
		
; ------------- Load number into registers (-> AX:EDX:ESI)

		fwait			; synchronize FPU
		mov	esi,[esp]	; ESI <- mantissa LOW
		mov	edx,[esp+4]	; EDX <- mantissa HIGH
		movzx	eax,word [esp+8] ; EAX <- exponent

; ------------- Special cases

		test	ax,7fffh	; clear sign flag
		jnz	ExpToTextBufN0	; not zero

Číslo se uloží do bufferu v zásobníku (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). Do registrového páru EDX:ESI se načte mantisa čísla a do registru EAX exponent. Vynulováním nejvyššího bitu v registru AX se vynuluje znaménkový bit. Je-li exponent v registru AX nulový, jedná se o speciální případ nuly nebo nenormalizovaného čísla.


; ------------- Zero

		mov	ecx,edx		; ECX <- mantissa HIGH
		or	ecx,esi		; ECX <- is mantissa zero?
		jnz	ExpToTextBufN2	; mantissa is not zero
		and	ah,B7		; get sign flag
		or	ax,3fffh	; EAX <- normalize exponent
		bt	ebx,FORMFLAG_Alt2_b ; truncate zeros?
		jnc	ExpToTextBufN28	; don't truncate trailing zeros
		jmp	ExpToTextBufN29	; truncate zeros (here is ECX = 0)

V případě nulového exponentu se provede text mantisy. 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. Exponent se nastaví na normalizovanou hodnotu 3FFFh a zachová se znaménko nuly. Dále se pokračuje obsluhou se zkrácením koncových nul nebo bez zkrácení nul.


; ------------- Infinity (+1.#INF, -1.#INF) or non-number (+1.#NAN, -1.#NAN)

ExpToTextBufN0:	cmp	ax,0ffffh	; negative infinity or non-number?
		je	ExpToTextBufN1	; yes
		cmp	ax,7fffh	; infinity or non-number?
		jne	ExpToTextBufN2	; neither infinity nor non-number
ExpToTextBufN1:	xor	ecx,ecx		; ECX <- 0
		mov	cl,7		; ECX <- text length
		jmp	ExpToTextBufN8

Má-li exponent v registru AX hodnotu 0FFFFh nebo 7FFFh, jedná se o další zvláštní případ - nekonečno nebo nedefinované číslo. Do registru ECX se připraví délka textu (=7) a funkce může přejít přímo na obsluhu minimální šířky pole s textem.


; ------------- Check if truncate trailing zeros

ExpToTextBufN2:	bt	ebx,FORMFLAG_Alt2_b ; truncate zeros?
		jnc	ExpToTextBufN28	; don't truncate trailing zeros

; ------------- Push registers (here is AX=exponent, EBX=formatting param.)

		mov	ecx,esp		; ECX <- pointer to float in stack
		push	eax		; push EAX
		push	edx		; push EDX
		push	ebx		; push EBX (formatting parameters)

; ------------- Absolute value

		fld	st0		; duplicate number
		fabs			; absolute value

Je-li požadováno ořezání nevýznamných koncových nul (příznak FORMFLAG_Alt2_b), je nutné provést plný rozklad čísla na číslice, aby bylo možné zjistit skutečnou přesnost čísla.

Do registru ECX se připraví ukazatel do bufferu čísla v zásobníku. Po uložení registrů se číslo v registru ST0 zduplikuje a převede na absolutní hodnotu.


; ------------- Split number to mantissa and exponent (here is EDX=bin. exp.)

		and	ah,7fh		; mask sign flag
		xchg	eax,edx		; EDX <- exponent
		call	FloatSplit	; split number to mantissa and exponent

Vynulováním nejvyššího bitu registru AX se v exponentu vynuluje příznak záporného znaménka čísla a exponent se uloží do registru EDX. 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).


;-------------- Round, denormalize and convert mantissa to BCD (EBX = exponent)

		pop	eax		; EAX <- formatting parameters
		push	eax		; push EAX (formatting parameters)
		bt	eax,FORMTYPE_Cap_b ; round always down?
		movzx	eax,al		; EAX <- precision
		call	FloatMantBCD	; process mantissa

Čí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, registr ECX obsahuje 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.


; ------------- Truncate trailing zeros

		lea	edx,[esp+3*4+9]	; EDX <- last digit
		call	FloatTrunc	; truncate trailing zeros

; ------------- Pop registers

		pop	ebx		; pop EBX (formatting parameters)
		pop	edx		; pop EDX
		pop	eax		; pop EAX
		cmp	cl,bl		; check precision
		jb	ExpToTextBufN29	; limit precision

Funkcí FloatTrunc je zjištěna skutečná přesnost čísla (tj. počet platných desetinných míst) a obsahy registrů jsou navrácen. Je-li skutečná přesnost nižší než požadovaná, použije se počet číslic podle skutečné přesnosti.


; ------------- Prepare number of digits after decimal point (-> ECX)

ExpToTextBufN28:movzx	ecx,bl		; ECX <- number of digits

; ------------- Add decimal point and first digit

ExpToTextBufN29:cmp	cl,1		; 1 or more digits?
		cmc			; CY = 1 or more digits
		jc	ExpToTextBufN3	; 1 or more digits
		bt	ebx,FORMFLAG_Alt_b ; always use decimal point?
ExpToTextBufN3:	adc	ecx,byte 1	; add decimal point and first digit

Do registru ECX se připraví požadovaná přesnost, představující počet číslic za oddělovačem desetinných míst. V případě ořezání koncových nul se namísto požadované přesnosti může použít skutečná přesnost čísla.

Požaduje-li se dosazení oddělovače desetinných míst vždy nebo je-li počet číslic za oddělovačem nenulový, zvýší se délka textu v registru ECX o 1.


; ------------- Add sign

		or	ax,ax		; negative number?
		js	ExpToTextBufN4	; negative number
		test	ebx,(FORMFLAG1_Sign + FORMFLAG1_Space)*256*256 ; sign?
		jz	ExpToTextBufN5	; no sign
ExpToTextBufN4:	inc	ecx		; add sign
ExpToTextBufN5:	and	ah,7fh		; clear sign flag

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. Znaménkový bit v registru AX se vynuluje.


; ------------- Add exponent, 3 digits

		add	ecx,byte 1+1+3	; add exp. character, sign and 3 digits

; ------------- Add +exponent, 4 digits (1.0e+1000, 4CF8 F38DB1F9 DD3DAC05)

		cmp	ax,4cf8h	; exponent
		jb	ExpToTextBufN6	; number is less than 1.0e+1000
		ja	ExpToTextBufN7	; number if greater than 1.0e+1000
		cmp	edx,0f38db1f9h	; mantissa HIGH
		jb	ExpToTextBufN8	; number is less than 1.0e+1000
		ja	ExpToTextBufN7	; number if greater than 1.0e+1000
		cmp	esi,0dd3dac05h	; mantissa LOW
		jb	ExpToTextBufN8	; number is less than 1.0e+1000
		jmp	ExpToTextBufN7	; add 1 digit

; ------------- Add -exponent, 4 digits (1.0e-1000, 3305 868A9188 A89E1467)

ExpToTextBufN6:	cmp	ax,3305h	; exponent
		ja	ExpToTextBufN8	; number is greater than 1.0e-1000
		jb	ExpToTextBufN7	; number if less than 1.0e-1000
		cmp	edx,868a9188h	; mantissa HIGH
		ja	ExpToTextBufN8	; number is greater than 1.0e-1000
		jb	ExpToTextBufN7	; number if less than 1.0e-1000
		cmp	esi,0a89e1467h	; mantissa LOW
		ja	ExpToTextBufN8	; number is greater than 1.0e-1000
ExpToTextBufN7:	inc	ecx		; add 1 digit

Ke střadači délky textu v registru ECX se přičte minimální počet znaků na exponent - 1 znak oddělovače exponentu (písmeno "e" nebo "E"), 1 znak pro znaménko exponentu a minimálně 3 číslice exponentu.

Má-li číslo hodnotu 1e+1000 a více nebo 1e-1000 a méně, bude mít exponent 4 číslice a je tedy nutné zvýšit délku textu. Porovnání se pro zrychlení provede testem hodnoty čísla pomocí celočíselných registrů (k rozhodnutí ve většině případů postačí test hodnoty exponentu). Při splnění podmínky se zvýší střadač délky textu ECX o 1.


; ------------- Check field width

ExpToTextBufN8:	movzx	eax,bh		; EAX <- minimal width
		cmp	eax,ecx		; check minimal width
		ja	ExpToTextBufN84	; use minimal width
		xchg	eax,ecx		; EAX <- text length

; ------------- Pop registers

ExpToTextBufN84:add	esp,12		; free local buffer
		pop	esi		; pop ESI
		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	ebx		; pop EBX
ExpToTextBufN9:	ret

Na závěr se porovná zjištěná délka textu čísla s požadovanou minimální šířkou pole s textem a je-li menší, navrátí se namísto zjištěné délky textu šířka pole s textem. Po navrácení ukazatele zásobníku se navrátí uschované registry.


Obsah / Utility / TEXTFORM / ExpToTextBufN