mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1484 lines
48 KiB
1484 lines
48 KiB
page ,132
|
|
;------------------------------Module-Header----------------------------;
|
|
; Module Name: math.asm ;
|
|
; ;
|
|
; This module contains the arithmetics routines for the engine internal ;
|
|
; floating point type EFLOAT. It is mostly adapted from ChuckWh's ;
|
|
; math.asm for PM. ;
|
|
; ;
|
|
; Created: 14-Nov-1990 ;
|
|
; Author: Wendy Wu [wendywu] ;
|
|
; ;
|
|
; Copyright (c) 1990 Microsoft Corporation ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
.386
|
|
.model small,c
|
|
|
|
assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
|
|
assume fs:nothing,gs:nothing
|
|
|
|
.xlist
|
|
include stdcall.inc
|
|
include gdii386.inc
|
|
.list
|
|
|
|
.data
|
|
if DBG
|
|
MATH_DivideError db 'divff3_c - Divide overflow',10,0
|
|
endif
|
|
|
|
.code
|
|
|
|
if DBG
|
|
extrn DbgPrint:proc
|
|
endif
|
|
|
|
NUMBER_OF_INTEGER_BITS_LONG equ 32
|
|
NUMBER_OF_INTEGER_BITS_FIX equ 28
|
|
IEEE_NAN equ 7FFFFFFFh ; not a number exp = 255 mant != 0
|
|
EXPONENT_OF_ONE equ 2
|
|
MANTISSA_OF_ONE equ 040000000h
|
|
|
|
BOOL_TRUNCATE equ 0
|
|
BOOL_ROUND equ 1
|
|
|
|
RESULT_NEGATIVE equ 1
|
|
|
|
public cmp_table_1
|
|
public cmp_table_2
|
|
public cmp_table_3
|
|
public cmp_table_4
|
|
|
|
cmp_table_1 label dword
|
|
dd 01000000h
|
|
dd 00000100h
|
|
|
|
cmp_table_2 label dword
|
|
dd 10000000h
|
|
dd 00100000h
|
|
dd 00001000h
|
|
dd 00000010h
|
|
|
|
cmp_table_3 label dword
|
|
dd 40000000h
|
|
dd 04000000h
|
|
dd 00400000h
|
|
dd 00040000h
|
|
dd 00004000h
|
|
dd 00000400h
|
|
dd 00000040h
|
|
dd 00000004h
|
|
|
|
cmp_table_4 label dword
|
|
dd 80000000h
|
|
dd 20000000h
|
|
dd 08000000h
|
|
dd 02000000h
|
|
dd 00800000h
|
|
dd 00200000h
|
|
dd 00080000h
|
|
dd 00020000h
|
|
dd 00008000h
|
|
dd 00002000h
|
|
dd 00000800h
|
|
dd 00000200h
|
|
dd 00000080h
|
|
dd 00000020h
|
|
dd 00000008h
|
|
dd 00000002h
|
|
|
|
;---------------------------Private-Routine-----------------------------;
|
|
; dNormalize
|
|
;
|
|
; Normalizes a DWORD so that its absolute value has 0 in sign bit and
|
|
; 1 in the highest order non-sign bit. Return the number of shifts done.
|
|
;
|
|
; Entry:
|
|
; EAX = DWORD
|
|
; Returns:
|
|
; ZF = 1 if zero, 0 otherwise
|
|
; EAX = normalized DWORD
|
|
; ECX = shift count
|
|
; Registers Destroyed:
|
|
; EDX
|
|
; Calls:
|
|
; None
|
|
; History:
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu]
|
|
; Wrote it
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc dNormalize
|
|
|
|
cdq ; save the sign
|
|
xor ecx,ecx
|
|
|
|
xor eax,edx ; absolute eax
|
|
sub eax,edx
|
|
jz dNormalize_zero
|
|
js dNormalize_80000000
|
|
|
|
cmp eax,10000h
|
|
adc cl,cl ; cl = 0 if eax >= 10000h
|
|
; cl = 1 if eax < 10000h
|
|
cmp eax,cmp_table_1[4*ecx]
|
|
adc cl,cl ; cl = 0 if eax > 1000000h
|
|
; cl = 1 if 1000000h > eax > 10000h
|
|
; cl = 2 if 10000h > eax > 100h
|
|
; cl = 3 if eax < 100h
|
|
|
|
cmp eax,cmp_table_2[4*ecx]
|
|
adc cl,cl ; 0 <= cl <= 7
|
|
|
|
cmp eax,cmp_table_3[4*ecx]
|
|
adc cl,cl ; 0 <= cl <= 15
|
|
|
|
cmp eax,cmp_table_4[4*ecx]
|
|
adc cl,cl ; 1 <= cl <= 31
|
|
; cl will never be 0 since eax > 0
|
|
|
|
dec cl ; offset to highest non-sign bit
|
|
shl eax,cl ; shift to highest non-sign bit
|
|
|
|
xor eax,edx ; negate eax if was negative number
|
|
sub eax,edx
|
|
|
|
dNormalize_zero:
|
|
cRet dNormalize
|
|
|
|
dNormalize_80000000:
|
|
sar eax,1
|
|
mov ecx,-1
|
|
cRet dNormalize
|
|
endProc dNormalize
|
|
|
|
;-----------------------------Private-Routine---------------------------;
|
|
; ltoef
|
|
;
|
|
; Convert a LONG integer to an EFLOAT format number.
|
|
;
|
|
; Entry:
|
|
; EAX = LONG integer to be converted
|
|
; Returns:
|
|
; ZF = 1 if zero, 0 otherwise
|
|
; EAX = mantissa of the EFLOAT number
|
|
; ECX = exponent of the EFLOAT number
|
|
; Registers Destroyed:
|
|
; EDX
|
|
; Calls:
|
|
; dNormalize
|
|
; History:
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu]
|
|
; Wrote it
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc ltoef
|
|
|
|
cCall dNormalize ; mant = normalized LONG
|
|
jz @F
|
|
neg ecx
|
|
add ecx,NUMBER_OF_INTEGER_BITS_LONG ; exp = 32 - shift count
|
|
|
|
@@:
|
|
cRet dNormalize
|
|
endproc ltoef
|
|
|
|
;---------------------------Public-Routine------------------------------;
|
|
; ltoef_c
|
|
;
|
|
; Convert a LONG integer to an EFLOAT format number.
|
|
;
|
|
; Arguments:
|
|
; IN l LONG integer to be converted
|
|
; OUT pef points to the EFLOAT number
|
|
; Calls:
|
|
; dNormalize
|
|
; History:
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu]
|
|
; Wrote it
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc ltoef_c,8,< \
|
|
l: dword, \
|
|
pef: ptr EFLOAT >
|
|
|
|
mov eax,l
|
|
cCall dNormalize ; mant = normalized LONG
|
|
jz @F
|
|
neg ecx
|
|
add ecx,NUMBER_OF_INTEGER_BITS_LONG ; exp = 32 - shift count
|
|
|
|
@@:
|
|
mov edx,pef
|
|
mov [edx].ef_lMant,eax
|
|
mov [edx].ef_lExp,ecx
|
|
|
|
cRet ltoef_c
|
|
endProc ltoef_c
|
|
|
|
;-----------------------------Private-Routine---------------------------;
|
|
; fxtoef
|
|
;
|
|
; Convert a FIX number to an EFLOAT format number.
|
|
;
|
|
; Entry:
|
|
; EAX = FIX number to be converted
|
|
; Returns:
|
|
; ZF = 1 if zero, 0 otherwise
|
|
; EAX = mantissa of the EFLOAT number
|
|
; ECX = exponent of the EFLOAT number
|
|
; Registers Destroyed:
|
|
; EDX
|
|
; Calls:
|
|
; dNormalize
|
|
; History:
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu]
|
|
; Wrote it
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc fxtoef
|
|
|
|
cCall dNormalize ; mant = normalized fIX number
|
|
jz @F
|
|
neg ecx
|
|
add ecx,NUMBER_OF_INTEGER_BITS_FIX ; exp = 28 - shift count
|
|
|
|
@@:
|
|
cRet fxtoef
|
|
endProc fxtoef
|
|
|
|
;---------------------------Public-Routine------------------------------;
|
|
; fxtoef_c
|
|
;
|
|
; Convert a FIX number to an EFLOAT format number.
|
|
;
|
|
; Arguments:
|
|
; IN fx FIX number to be converted
|
|
; OUT pEf points to the EFLOAT number
|
|
; Calls:
|
|
; dNormalize
|
|
; History:
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu]
|
|
; Wrote it
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc fxtoef_c,8,< \
|
|
fx: dword, \
|
|
pEf: ptr EFLOAT >
|
|
|
|
mov eax,fx
|
|
cCall dNormalize ; mant = normalized LONG
|
|
jz @F
|
|
neg ecx
|
|
add ecx,NUMBER_OF_INTEGER_BITS_FIX ; exp = 28 - shift count
|
|
|
|
@@:
|
|
mov edx,pEf
|
|
mov [edx].ef_lMant,eax
|
|
mov [edx].ef_lExp,ecx
|
|
|
|
cRet fxtoef_c
|
|
endProc fxtoef_c
|
|
|
|
;---------------------------Public-Routine------------------------------;
|
|
; ftoef_c
|
|
;
|
|
; Convert an IEEE FLOAT format number to an EFLOAT format number.
|
|
;
|
|
; Arguments:
|
|
; IN e IEEE FLOAT number to be converted
|
|
; OUT pEf points to the EFLOAT number
|
|
; Calls:
|
|
; None
|
|
; History:
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu]
|
|
; Wrote it
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc ftoef_c,8,< \
|
|
e: dword, \
|
|
pEf: ptr EFLOAT >
|
|
|
|
mov eax,e
|
|
shld ecx,eax,9
|
|
and ecx,0FFh ; ecx = e.exponent
|
|
jnz @F
|
|
|
|
xor eax,eax ; return 0 if (exp == 0)
|
|
jmp ftoef_zero
|
|
|
|
@@:
|
|
|
|
; We got a non-zero number
|
|
; EFLOAT.mantissa = FLOAT.mantissa + hidden one
|
|
|
|
cdq ; sign extend eax to edx
|
|
and eax,07FFFFFh ; mask off sign bit and exponent
|
|
shl eax,7 ; shift to its position
|
|
or eax,040000000h ; or in the hidden one
|
|
|
|
;ASSERT(((eax & 080000000h) == 0),"ftoef_c error");
|
|
|
|
xor eax,edx ; negate mantissa if (e < 0)
|
|
sub eax,edx
|
|
|
|
; ef.exp = e.exp + 2 - 127
|
|
|
|
sub ecx,125
|
|
|
|
ftoef_zero:
|
|
mov edx,pEf
|
|
mov [edx].ef_lMant,eax
|
|
mov [edx].ef_lExp,ecx
|
|
|
|
cRet ftoef_c
|
|
endProc ftoef_c
|
|
|
|
;-----------------------------Public-Routine----------------------------;
|
|
; eftofx
|
|
;
|
|
; Convert an EFLOAT number to a FIX number. Fractions of 1/32 or greater
|
|
; are rounded up.
|
|
;
|
|
; Entry:
|
|
; EAX = mantissa
|
|
; ECX = exponent
|
|
; Returns:
|
|
; OF = 0
|
|
; EAX = converted long integer
|
|
; Error Returns:
|
|
; OF = 1
|
|
; Registers Destroyed:
|
|
; EDX,ECX
|
|
; Calls:
|
|
; eftol
|
|
; History:
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu]
|
|
; Wrote it
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc eftofx
|
|
|
|
add ecx,4 ; so we can call eftol
|
|
mov edx,BOOL_ROUND
|
|
|
|
eftofx_fall_through::
|
|
|
|
endProc eftofx ; fall through to eftol
|
|
|
|
;-----------------------------Public-Routine----------------------------;
|
|
; eftol
|
|
;
|
|
; Convert an EFLOAT number to a LONG integer. Fractions are either
|
|
; rounded or truncated depending on the flag in EDX.
|
|
;
|
|
; Entry:
|
|
; EAX = mantissa
|
|
; ECX = exponent
|
|
; EDX = roundoff boolean
|
|
; Returns:
|
|
; OF = 0
|
|
; EAX = converted long integer
|
|
; Error Returns:
|
|
; OF = 1
|
|
; Registers Destroyed:
|
|
; ECX
|
|
; Calls:
|
|
; None
|
|
|
|
; History:
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu]
|
|
; Wrote it
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc eftol
|
|
|
|
.errnz $-eftofx_fall_through
|
|
|
|
; if exp < 1, return 0.
|
|
|
|
cmp ecx,1
|
|
jl eftol_exp_small
|
|
cmp ecx,32
|
|
jg eftol_exp_big
|
|
jz @F ; return mantissa if (exp == 32)
|
|
|
|
;ASSERT((1 <= ecx <= 31),"eftol exponent error")
|
|
|
|
xor cl,31 ; 31 - exp
|
|
|
|
; EDX = 1 if we'll do truncation, LONG = ((mant >> (31 - exp)) + 1) >> 1
|
|
; EDX = 0 if we'll do rounding, LONG = (mant >> (31 - exp)) >> 1
|
|
|
|
;ASSERT(((edx & FFFFFFFEh) == 0),"eftol rounding boolean error")
|
|
|
|
sar eax,cl
|
|
add eax,edx
|
|
jo eftol_7fffffff ; overflow if mant = 7fffffff, exp = 31
|
|
sar eax,1
|
|
@@:
|
|
cRet eftol ; normal return
|
|
|
|
eftol_exp_small:
|
|
xor eax,eax ; exponent too small, return 0
|
|
cRet eftol ; OF = 0 by xor
|
|
|
|
eftol_exp_big:
|
|
mov cl,1 ; OF = 1 if exp > 32
|
|
add cl,7fh
|
|
cRet eftol
|
|
|
|
eftol_7fffffff:
|
|
shr eax,1 ; return 40000000h
|
|
xor cl,cl ; OF = 0
|
|
cRet eftol
|
|
|
|
endProc eftol
|
|
|
|
;---------------------------Public-Routine------------------------------;
|
|
; eftol_c
|
|
;
|
|
; Convert an EFLOAT number to a LONG integer. Fractions are rounded
|
|
; or truncated depending on the passed in flag.
|
|
;
|
|
; Arguments:
|
|
; IN pEf points to the EFLOAT number
|
|
; OUT pL points to the LONG integer
|
|
; IN bRound roundoff boolean
|
|
; Returns:
|
|
; EAX = 1 if success
|
|
; Error Returns:
|
|
; EAX = 0 if overflow
|
|
; Calls:
|
|
; eftol
|
|
; History:
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu]
|
|
; Wrote it
|
|
;
|
|
;CR!!! Delete this if nobody uses it.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc eftol_c,12,< \
|
|
pEf: ptr EFLOAT, \
|
|
pL: ptr LONG, \
|
|
bRound: dword >
|
|
|
|
mov edx,pEf
|
|
mov eax,[edx].ef_lMant
|
|
mov ecx,[edx].ef_lExp
|
|
mov edx,bRound
|
|
|
|
cCall eftol
|
|
|
|
mov edx,pL
|
|
mov [edx],eax
|
|
|
|
mov eax,0
|
|
setno al
|
|
|
|
cRet eftol_c
|
|
endProc eftol_c
|
|
|
|
;---------------------------Public-Routine------------------------------;
|
|
; eftofx_c
|
|
;
|
|
; Convert an EFLOAT number to a FIX number. Fractions of 1/32 or greater
|
|
; are rounded up.
|
|
;
|
|
; Arguments:
|
|
; IN pEf points to the EFLOAT number
|
|
; OUT pFx points to the FIX number
|
|
; Returns:
|
|
; EAX = 1 if success
|
|
; Error Returns:
|
|
; EAX = 0 if overflow
|
|
; Calls:
|
|
; eftol
|
|
; History:
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu]
|
|
; Wrote it
|
|
;
|
|
;CR!!! Delete this if nobody uses it.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc eftofx_c,8,< \
|
|
pEf: ptr EFLOAT, \
|
|
pFx: ptr FIX >
|
|
|
|
mov edx,pEf
|
|
mov eax,[edx].ef_lMant
|
|
mov ecx,[edx].ef_lExp
|
|
add ecx,4
|
|
|
|
mov edx,BOOL_ROUND
|
|
cCall eftol
|
|
|
|
mov edx,pFx
|
|
mov [edx],eax
|
|
|
|
mov eax,0
|
|
setno al
|
|
|
|
cRet eftofx_c
|
|
endProc eftofx_c
|
|
|
|
;---------------------------Public-Routine------------------------------;
|
|
; eftof_c
|
|
;
|
|
; Convert an EFLOAT number to an IEEE FLOAT format number.
|
|
;
|
|
; Arguments:
|
|
; IN pEf points to the EFLOAT number
|
|
; Returns:
|
|
; EAX = resulting IEEE FLOAT number
|
|
; Error Returns:
|
|
; EAX = NAN if overflow
|
|
; Calls:
|
|
; None
|
|
; History:
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu]
|
|
; Wrote it
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc eftof_c,4,< \
|
|
pEf: ptr EFLOAT >
|
|
|
|
xor eax,eax ; assume result is 0
|
|
mov edx,pEf
|
|
mov ecx,[edx].ef_lMant
|
|
or ecx,ecx ; faster than jcxz
|
|
jz eftof_zero
|
|
|
|
mov edx,[edx].ef_lExp
|
|
|
|
jns eftof_positive
|
|
or eax,080000000h ; turn on sign bit if negative number
|
|
neg ecx ; make it positive
|
|
|
|
eftof_positive:
|
|
|
|
and ecx,3FFFFFFFh ; mask off sign bit and hidden one
|
|
shr ecx,7 ; shift mantissa to its position
|
|
adc ecx,0 ; round the result
|
|
test ecx,0800000h
|
|
jnz eftof_rounding_overflow
|
|
|
|
eftof_mant_done:
|
|
add edx,125 ; FLOAT.exp = EFLOAT.exp + 127 - 2
|
|
jo eftof_NAN
|
|
|
|
shl edx,23 ; shift exponent to its position
|
|
|
|
or eax,ecx
|
|
or eax,edx ; or sign, mant, exp bits together
|
|
eftof_zero:
|
|
cRet eftof_c
|
|
|
|
eftof_rounding_overflow:
|
|
xor ecx,ecx
|
|
inc edx
|
|
jno eftof_mant_done
|
|
|
|
eftof_NAN:
|
|
mov eax,IEEE_NAN
|
|
cRet eftof_c
|
|
|
|
endProc eftof_c
|
|
|
|
;---------------------------Public-Routine------------------------------;
|
|
; fraction_c
|
|
;
|
|
; Get the fraction part of an EFLOAT number.
|
|
;
|
|
; Arguments:
|
|
; IN pEfIn points to the EFLOAT number its fractional part is
|
|
; to be computed
|
|
; OUT pEfOut points to the EFLOAT number that stores the fractional
|
|
; part result
|
|
; Returns:
|
|
; Nothing
|
|
; Calls:
|
|
; dNormalize
|
|
; History:
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu]
|
|
; Wrote it
|
|
;-----------------------------------------------------------------------;
|
|
|
|
;!!!CR Does Andrew use this? Is the result correct when a negative number
|
|
;!!!CR is passed in?
|
|
|
|
cProc fraction_c,8,< \
|
|
pEfOut: ptr EFLOAT, \
|
|
pEfIn: ptr EFLOAT >
|
|
|
|
mov edx,pEfIn
|
|
|
|
mov eax,[edx].ef_lMant ; EAX = mantissa
|
|
mov ecx,[edx].ef_lExp ; ECX = exponent
|
|
cmp ecx,0
|
|
jle got_fractions ; if (exp <= 1) return itself
|
|
|
|
cmp ecx,32
|
|
jge no_fraction
|
|
|
|
; shift off integer part
|
|
|
|
have_fraction:
|
|
shl eax,cl ; shift off the integer bits
|
|
shr eax,1 ; make it positive
|
|
cCall dNormalize
|
|
jz no_fraction
|
|
neg ecx ; exp = 1 - left shift count
|
|
inc ecx
|
|
|
|
; We get here either because the number is too big, no fraction is stored
|
|
; in the mantissa or this number is an integer.
|
|
|
|
store_results:
|
|
mov edx,pEfOut
|
|
mov [edx].ef_lMant,eax
|
|
mov [edx].ef_lExp,ecx
|
|
mov eax,edx
|
|
cRet fraction_c
|
|
|
|
got_fractions: ; take care of negative fractions here
|
|
or eax,eax
|
|
jge store_results
|
|
neg ecx
|
|
sar eax,cl
|
|
shr eax,1 ; make it positive
|
|
neg ecx
|
|
inc ecx
|
|
jmp short store_results
|
|
|
|
no_fraction:
|
|
xor eax,eax ; exp >= 32 return 0
|
|
xor ecx,ecx
|
|
jmp store_results
|
|
|
|
endProc fraction_c
|
|
|
|
;-----------------------------Public-Routine----------------------------;
|
|
; addff
|
|
;
|
|
; Add two EFLOAT numbers together.
|
|
;
|
|
; Entry:
|
|
; EDX = mant
|
|
; EBX = exp
|
|
; EAX = mant
|
|
; ECX = exp
|
|
; Returns:
|
|
; EAX = mant
|
|
; ECX = exp
|
|
; OF = 0
|
|
; ZF = 1 if zero
|
|
; Error Returns:
|
|
; OF = 1 if overflow
|
|
; Registers Destroyed:
|
|
; EBX,EDX
|
|
; Calls:
|
|
; dNormalize
|
|
; History:
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu]
|
|
; Wrote it
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc addff
|
|
|
|
or edx,edx ; early out if either one is 0
|
|
jz addff_exit
|
|
or eax,eax
|
|
jz addff_xchg_exit
|
|
|
|
cmp ecx,ebx
|
|
jge second_summand_larger
|
|
xchg eax,edx
|
|
xchg ecx,ebx
|
|
|
|
second_summand_larger:
|
|
sub ecx,ebx
|
|
cmp ecx,30 ; only 30 bits of pre-adding precision
|
|
jbe first_summand_not_small ;
|
|
add ecx,ebx ; clear overflow flag
|
|
jmp addff_exit
|
|
|
|
first_summand_not_small:
|
|
add ebx,ecx ; restore the bigger exp in ebx
|
|
sar edx,cl ; shift the smaller number right by
|
|
; difference in exp bit
|
|
sar eax,1 ; prevent overflow
|
|
; adc eax,0 ; round the bigger number
|
|
sar edx,1 ; prevent overflow
|
|
; adc edx,0 ; round the smaller number
|
|
|
|
add eax,edx ; add mantissa together
|
|
cCall dNormalize
|
|
jz addff_exit
|
|
|
|
; sum's exponent = EBX - ECX + 1
|
|
|
|
neg ecx
|
|
add ecx,ebx
|
|
inc ecx ; compensate for the right shift
|
|
|
|
addff_exit:
|
|
cRet addff
|
|
|
|
addff_xchg_exit:
|
|
mov eax,edx
|
|
mov ecx,ebx
|
|
cRet addff
|
|
|
|
endProc addff
|
|
|
|
;---------------------------Public-Routine------------------------------;
|
|
; subff_c ;
|
|
; ;
|
|
; Subtract an EFLOAT number from another. The result overwrites the ;
|
|
; subtrahend. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; IN OUT pSub points to the EFLOAT subtrahend ;
|
|
; IN pMin points to the EFLOAT minuend ;
|
|
; Returns: ;
|
|
; EAX = 1 if success ;
|
|
; Error Returns: ;
|
|
; EAX = 0 if overflow ;
|
|
; Calls: ;
|
|
; addff ;
|
|
; History: ;
|
|
; Thu 19-Mar-1992 17:44:34 -by- Charles Whitmer [chuckwh] ;
|
|
; Added 3 parameter entry point. This gives us better C++ code. ;
|
|
; ;
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu] ;
|
|
; Wrote it ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc subff_c,8,< \
|
|
uses ebx, \
|
|
pSub: ptr EFLOAT, \
|
|
pMin: ptr EFLOAT >
|
|
|
|
mov ebx, pSub
|
|
mov edx, [ebx].ef_lMant
|
|
mov ebx, [ebx].ef_lExp
|
|
|
|
mov ecx, pMin
|
|
mov eax, [ecx].ef_lMant
|
|
mov ecx, [ecx].ef_lExp
|
|
neg eax
|
|
|
|
cCall addff
|
|
|
|
mov ebx,pSub
|
|
mov [ebx].ef_lMant,eax
|
|
mov [ebx].ef_lExp,ecx
|
|
|
|
mov eax,0
|
|
setno al
|
|
|
|
cRet subff_c
|
|
|
|
endProc subff_c
|
|
|
|
cProc subff3_c,12,< \
|
|
uses ebx, \
|
|
pRes: ptr EFLOAT, \
|
|
pSub: ptr EFLOAT, \
|
|
pMin: ptr EFLOAT >
|
|
|
|
mov ebx, pSub
|
|
mov edx, [ebx].ef_lMant
|
|
mov ebx, [ebx].ef_lExp
|
|
|
|
mov ecx, pMin
|
|
mov eax, [ecx].ef_lMant
|
|
mov ecx, [ecx].ef_lExp
|
|
neg eax
|
|
|
|
cCall addff
|
|
|
|
mov ebx,pRes
|
|
jo short @F
|
|
mov [ebx].ef_lMant,eax
|
|
mov [ebx].ef_lExp,ecx
|
|
@@: mov eax,ebx
|
|
cRet subff3_c
|
|
endProc subff3_c
|
|
|
|
;---------------------------Public-Routine------------------------------;
|
|
; addff_c ;
|
|
; ;
|
|
; Add two EFLOAT numbers together. The result overwrites the first ;
|
|
; summand. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; IN OUT pSum1 points to the first EFLOAT summand ;
|
|
; IN pSum2 points to the second EFLOAT summand ;
|
|
; Returns: ;
|
|
; EAX = 1 if success ;
|
|
; Error Returns: ;
|
|
; EAX = 0 if overflow ;
|
|
; Calls: ;
|
|
; addff ;
|
|
; History: ;
|
|
; Thu 19-Mar-1992 17:44:34 -by- Charles Whitmer [chuckwh] ;
|
|
; Added 3 parameter entry point. This gives us better C++ code. ;
|
|
; ;
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu] ;
|
|
; Wrote it ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc addff_c,8,< \
|
|
uses ebx, \
|
|
pSum1: ptr EFLOAT, \
|
|
pSum2: ptr EFLOAT >
|
|
|
|
mov ebx, pSum2
|
|
mov edx, [ebx].ef_lMant
|
|
mov ebx, [ebx].ef_lExp
|
|
|
|
mov ecx, pSum1
|
|
mov eax, [ecx].ef_lMant
|
|
mov ecx, [ecx].ef_lExp
|
|
|
|
cCall addff
|
|
|
|
mov ebx,pSum1
|
|
mov [ebx].ef_lMant,eax
|
|
mov [ebx].ef_lExp,ecx
|
|
|
|
mov eax,0
|
|
setno al
|
|
|
|
cRet addff_c
|
|
endProc addff_c
|
|
|
|
cProc addff3_c,12,< \
|
|
uses ebx, \
|
|
pRes: ptr EFLOAT, \
|
|
pSum1: ptr EFLOAT, \
|
|
pSum2: ptr EFLOAT >
|
|
|
|
mov ebx, pSum2
|
|
mov edx, [ebx].ef_lMant
|
|
mov ebx, [ebx].ef_lExp
|
|
|
|
mov ecx, pSum1
|
|
mov eax, [ecx].ef_lMant
|
|
mov ecx, [ecx].ef_lExp
|
|
|
|
cCall addff
|
|
|
|
mov ebx,pRes
|
|
jo short @F
|
|
mov [ebx].ef_lMant,eax
|
|
mov [ebx].ef_lExp,ecx
|
|
@@: mov eax,ebx
|
|
cRet addff3_c
|
|
endProc addff3_c
|
|
|
|
;-----------------------------Public-Routine----------------------------;
|
|
; mulff ;
|
|
; ;
|
|
; Multiply two EFLOAT numbers together. ;
|
|
; ;
|
|
; Entry: ;
|
|
; EDX = first multiplicand's mant ;
|
|
; EBX = first multiplicand's exp ;
|
|
; EAX = second multiplicand's mant ;
|
|
; ECX = second multiplicand's exp ;
|
|
; Returns: ;
|
|
; EAX = mant ;
|
|
; ECX = exp ;
|
|
; OF = 0 ;
|
|
; ZF = 1 if zero ;
|
|
; Error Returns: ;
|
|
; OF = 1 if overflow ;
|
|
; Registers Destroyed: ;
|
|
; EDX,EBX ;
|
|
; Calls: ;
|
|
; None ;
|
|
; History: ;
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu] ;
|
|
; Wrote it ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
mul_shift_table label byte ; highest 4 bits
|
|
db 0 ; 0000 should have been early out
|
|
db 2 ; 0001
|
|
db 1 ; 0010
|
|
db 1 ; 0011
|
|
|
|
cProc mulff
|
|
|
|
add ebx,ecx ; add exponent together
|
|
jo mul_exit
|
|
|
|
xor ecx,ecx
|
|
imul edx ; edx:eax = edx * eax
|
|
|
|
; the product of two mantissas is now in edx:eax. Since on entry
|
|
; to this function both mantissas were normalized the absolute value
|
|
; of this product is <= 7fffffff * 7fffffff = 3fffffff:00000001;
|
|
; The legal values of the most significant nibble in edx are 0, 1, 2, 3.
|
|
|
|
or edx,edx
|
|
jz mul_exit ; eax == 0 if (edx == 0), so it's
|
|
; safe to early out here
|
|
js mul_neg
|
|
|
|
shld ecx,edx,4 ; normalize the result
|
|
mov cl,mul_shift_table[ecx] ; find the shift count from the table
|
|
shld edx,eax,cl
|
|
shl eax,cl
|
|
|
|
; now do the rounding. We should add the most significant bit of eax to edx.
|
|
; Adding this extra bit to edx could result in the
|
|
; loss of normalization of edx which should then be restored by shr edx,1
|
|
; and adjusting the exponent accordingly.
|
|
|
|
add eax,80000000h
|
|
adc edx,0
|
|
js mul_restore_normalization
|
|
|
|
mul_store_result:
|
|
neg ecx
|
|
mov eax,edx ; return mantissa in eax
|
|
add ecx,ebx ; exponent = ebx - ecx
|
|
|
|
mul_exit:
|
|
cRet mulff
|
|
|
|
mul_restore_normalization:
|
|
|
|
shr edx,1 ; edx now normalized == 40000000h
|
|
dec ecx ; adjust exponent
|
|
jmp mul_store_result
|
|
|
|
; the result is negative:
|
|
|
|
mul_neg:
|
|
|
|
; We can't normalize a negative number. e.g. the shift count for 1110
|
|
; can be either 1 or 2.
|
|
|
|
neg eax ; negate edx:eax
|
|
adc edx,0
|
|
neg edx
|
|
|
|
shld ecx,edx,4 ; normalize the result
|
|
mov cl,mul_shift_table[ecx] ; find the shift count from the table
|
|
shld edx,eax,cl
|
|
shl eax,cl
|
|
|
|
; do the rounding as in the positive case
|
|
|
|
add eax,80000000h
|
|
adc edx,0
|
|
js mul_restore_normalization_neg
|
|
|
|
; all the information is now in edx, including least significant bit
|
|
|
|
mul_store_result_neg:
|
|
|
|
neg edx ; restore the sign
|
|
neg ecx ; finish off as in the positive case
|
|
add ecx,ebx ; exponent = ebx - ecx
|
|
mov eax,edx ; return mantissa in eax
|
|
|
|
cRet mulff
|
|
|
|
mul_restore_normalization_neg:
|
|
|
|
shr edx,1 ; edx now normalized == 40000000h
|
|
dec ecx ; adjust exponent
|
|
jmp mul_store_result_neg
|
|
|
|
endProc mulff
|
|
|
|
;---------------------------Public-Routine------------------------------;
|
|
; mulff_c ;
|
|
; ;
|
|
; Multiply two EFLOAT numbers together. The result overwrites the ;
|
|
; first multiplicand. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; IN OUT pMult1 points to the first EFLOAT multiplicand. ;
|
|
; IN pMult2 points to the second EFLOAT multiplicand. ;
|
|
; Returns: ;
|
|
; EAX = 1 if success ;
|
|
; Error Returns: ;
|
|
; EAX = 0 if overflow ;
|
|
; Calls: ;
|
|
; mulff ;
|
|
; History: ;
|
|
; Thu 19-Mar-1992 17:44:34 -by- Charles Whitmer [chuckwh] ;
|
|
; Added 3 parameter entry point. This gives us better C++ code. ;
|
|
; ;
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu] ;
|
|
; Wrote it ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc mulff_c,8,< \
|
|
uses ebx, \
|
|
pMult1: ptr EFLOAT, \
|
|
pMult2: ptr EFLOAT >
|
|
|
|
mov ebx,pMult2
|
|
mov eax,[ebx].ef_lMant
|
|
mov ecx,[ebx].ef_lExp
|
|
mov ebx,pMult1
|
|
mov edx,[ebx].ef_lMant
|
|
mov ebx,[ebx].ef_lExp
|
|
|
|
cCall mulff
|
|
|
|
mov ebx,pMult1
|
|
mov [ebx].ef_lMant,eax
|
|
mov [ebx].ef_lExp,ecx
|
|
|
|
mov eax,0
|
|
setno al
|
|
|
|
cRet mulff_c
|
|
endProc mulff_c
|
|
|
|
cProc mulff3_c,12,< \
|
|
uses ebx, \
|
|
pRes: ptr EFLOAT, \
|
|
pMult1: ptr EFLOAT, \
|
|
pMult2: ptr EFLOAT >
|
|
|
|
mov ebx,pMult2
|
|
mov eax,[ebx].ef_lMant
|
|
mov ecx,[ebx].ef_lExp
|
|
mov ebx,pMult1
|
|
mov edx,[ebx].ef_lMant
|
|
mov ebx,[ebx].ef_lExp
|
|
|
|
cCall mulff
|
|
|
|
mov ebx,pRes
|
|
jo short @F
|
|
mov [ebx].ef_lMant,eax
|
|
mov [ebx].ef_lExp,ecx
|
|
@@: mov eax,ebx
|
|
cRet mulff3_c
|
|
endProc mulff3_c
|
|
|
|
;---------------------------Private-Routine-----------------------------;
|
|
; divff ;
|
|
; ;
|
|
; Divide an EFLOAT number by another. ;
|
|
; ;
|
|
; Entry: ;
|
|
; EDX = dividend's mantissa ;
|
|
; EBX = dividend's exponent ;
|
|
; EAX = divisor's mantissa, should never be 0 ;
|
|
; ECX = divisor's exponent ;
|
|
; Returns: ;
|
|
; EAX = quotient's mantissa ;
|
|
; ECX = quotient's exponent ;
|
|
; OF = 0 ;
|
|
; ZF = 1 if zero ;
|
|
; Error Returns: ;
|
|
; OF = 1 if overflow ;
|
|
; Registers Destroyed: ;
|
|
; EDX,EBX ;
|
|
; Calls: ;
|
|
; dNormalize ;
|
|
; History: ;
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu] ;
|
|
; Wrote it ;
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; cProc divff
|
|
;
|
|
; ;assert((eax != 0), "divff error: divide by 0")
|
|
;
|
|
; sub ebx,ecx ; subtract divisor's exp from dividend's
|
|
; jo divff_exit
|
|
;
|
|
; mov ecx,eax ; save divisor's mantissa
|
|
; xor eax,eax
|
|
; shrd eax,edx,2 ; prevent overflow, shift dividend
|
|
; sar edx,2 ; right by 2
|
|
;
|
|
; idiv ecx
|
|
; cCall dNormalize
|
|
; jz divff_exit ; eax = ecx = 0 if ZF = 1
|
|
;
|
|
; neg ecx
|
|
; inc ecx ; compensate for right shift by 2
|
|
; inc ecx
|
|
; add ecx,ebx ; add the exponent of the dividend
|
|
;
|
|
; divff_exit:
|
|
; cRet divff
|
|
; endProc divff
|
|
;
|
|
;---------------------------Public-Routine------------------------------;
|
|
; divff_c ;
|
|
; ;
|
|
; Divide an EFLOAT number by another. The result overwrites the ;
|
|
; dividend. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; IN OUT pDvdend points to the EFLOAT dividend. ;
|
|
; IN pDvsor points to the EFLOAT divisor. ;
|
|
; Returns: ;
|
|
; EAX = 1 if success ;
|
|
; Error Returns: ;
|
|
; EAX = 0 if overflow or zero divisor ;
|
|
; Calls: ;
|
|
; divff ;
|
|
; History: ;
|
|
; Thu 19-Mar-1992 17:44:34 -by- Charles Whitmer [chuckwh] ;
|
|
; Added 3 parameter entry point. This gives us better C++ code. ;
|
|
; ;
|
|
; 14-Nov-1990 -by- Wendy Wu [wendywu] ;
|
|
; Wrote it ;
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; cProc divff_c,8,< \
|
|
; uses ebx, \
|
|
; pDvdend: ptr EFLOAT, \
|
|
; pDvsor: ptr EFLOAT >
|
|
;
|
|
; mov ebx,pDvsor
|
|
; mov eax,[ebx].ef_lMant
|
|
; or eax,eax
|
|
; jz divff_error
|
|
;
|
|
; mov ecx,[ebx].ef_lExp
|
|
; mov ebx,pDvdend
|
|
; mov edx,[ebx].ef_lMant
|
|
; mov ebx,[ebx].ef_lExp
|
|
;
|
|
; cCall divff
|
|
;
|
|
; mov edx,pDvdend
|
|
; mov [edx].ef_lMant,eax
|
|
; mov [edx].ef_lExp,ecx
|
|
;
|
|
; mov eax,0
|
|
; setno al
|
|
;
|
|
; cRet divff_c
|
|
;
|
|
; divff_error:
|
|
; xor eax,eax
|
|
; cRet divff_c
|
|
;
|
|
; endProc divff_c
|
|
;
|
|
; cProc divff_old3_c,12,< \
|
|
; uses ebx, \
|
|
; pRes: ptr EFLOAT, \
|
|
; pDvdend: ptr EFLOAT, \
|
|
; pDvsor: ptr EFLOAT >
|
|
;
|
|
; mov ebx,pDvsor
|
|
; mov eax,[ebx].ef_lMant
|
|
; or eax,eax
|
|
; jz short divff_old3_error
|
|
;
|
|
; mov ecx,[ebx].ef_lExp
|
|
; mov ebx,pDvdend
|
|
; mov edx,[ebx].ef_lMant
|
|
; mov ebx,[ebx].ef_lExp
|
|
;
|
|
; cCall divff
|
|
;
|
|
; mov edx,pRes
|
|
; jo short @F
|
|
; mov [edx].ef_lMant,eax
|
|
; mov [edx].ef_lExp,ecx
|
|
; @@: mov eax,edx
|
|
; cRet divff_old3_c
|
|
;
|
|
; divff_old3_error:
|
|
; mov eax,pRes
|
|
; cRet divff_old3_c
|
|
; endProc divff_old3_c
|
|
;
|
|
;------------------------------Public-Routine------------------------------;
|
|
; divff3_c ;
|
|
; ;
|
|
; A newer concept for EFLOAT division. This makes maximal use of the ;
|
|
; assumption that the given numbers are normalized. I think the older ;
|
|
; method spends a lot of time in dNormalize for no reason. ;
|
|
; ;
|
|
; Fri 14-Jan-1994 -by- Bodin Dresevic [BodinD] ;
|
|
; update: added all the comments while trying to debug this routine ;
|
|
; ;
|
|
; Sun 22-Mar-1992 02:04:09 -by- Charles Whitmer [chuckwh] ;
|
|
; Wrote it. ;
|
|
;--------------------------------------------------------------------------;
|
|
|
|
cProc divff3_c,12,< \
|
|
uses ebx esi, \
|
|
pRes: ptr EFLOAT, \
|
|
pNum: ptr EFLOAT, \
|
|
pDenom: ptr EFLOAT >
|
|
|
|
mov ebx,pNum
|
|
mov esi,[ebx].ef_lExp
|
|
mov ecx,[ebx].ef_lMant
|
|
or ecx,ecx
|
|
jz short divff3_zero
|
|
mov eax,ecx
|
|
cdq
|
|
xor ecx,edx
|
|
sub ecx,edx ; ecx = |MantN|
|
|
mov ebx,pDenom
|
|
sub esi,[ebx].ef_lExp ; esi = ExpN - ExpD == expR
|
|
jo short divff3_error
|
|
mov eax,[ebx].ef_lMant
|
|
mov ebx,edx ; save sgn(MantN) into ebx
|
|
cdq
|
|
xor eax,edx
|
|
sub eax,edx ; eax = |MantD|
|
|
xor ebx,edx ; ebx = sgn(MantN) * sgn(MantD)
|
|
mov edx,ecx
|
|
mov ecx,eax
|
|
add ecx,ecx ; ecx = 2 * |MantD|
|
|
jz short divff3_error
|
|
xor eax,eax ; edx:eax = |MantN|:0, ecx = 2 * |MantD|
|
|
div ecx ; the result in eax, remainder in edx
|
|
shr ecx,1 ; ecx = |MantD|
|
|
cmp ecx,edx ; if remainder <= |MantD| need roundoff bit
|
|
sbb edx,edx
|
|
neg edx ; edx = roundoff bit
|
|
xor ecx,ecx ; ecx = 0, ecx will be used to store correction to ExpR
|
|
or eax,eax ; eax = unnormalized |MantR|, may need to clear sign bit
|
|
setns cl ; cl = 1 iff sign bit in eax NOT set
|
|
and edx,ecx ; fix roundoff bit
|
|
xor cl,1 ; cl = 1 iff sign bit in eax IS set
|
|
shr eax,cl ; normalize eax, will set CF iff least significant bit is set in eax before shr
|
|
adc eax,edx ; round the |MantR|, add CF if it is set
|
|
inc ecx ; because we divided by 2 * |MantD| above
|
|
add esi,ecx ; adjust expR
|
|
jo short divff3_error
|
|
xor eax,ebx ; restore the sign of MantR
|
|
sub eax,ebx ; eax = MantR
|
|
mov ebx,pRes
|
|
mov [ebx].ef_lMant,eax
|
|
mov [ebx].ef_lExp,esi
|
|
mov eax,ebx
|
|
cRet divff3_c
|
|
|
|
divff3_zero:
|
|
mov eax,pRes
|
|
mov [eax].ef_lMant,ecx
|
|
mov [eax].ef_lExp,ecx
|
|
cRet divff3_c
|
|
|
|
divff3_error:
|
|
if DBG
|
|
push offset MATH_DivideError
|
|
call DbgPrint
|
|
add esp,4
|
|
int 3
|
|
endif
|
|
mov eax,pRes
|
|
cRet divff3_c
|
|
endProc divff3_c
|
|
|
|
;------------------------------Public--Routine-----------------------------;
|
|
; void sqrtf2_c (pRes,pef) ;
|
|
; ;
|
|
; Takes the square root of an EFLOAT ;
|
|
; ;
|
|
; History: ;
|
|
; Thu 19-Mar-1992 17:38:58 -by- Charles Whitmer [chuckwh] ;
|
|
; Added result pointer. Removed 9 instructions from the calculation. ;
|
|
; Doesn't change return value on error. ;
|
|
; ;
|
|
; Tue 02-Apr-1991 11:45:09 -by- Kirk Olynyk [kirko] ;
|
|
; Uses Newton's method now. ;
|
|
; ;
|
|
; Mon 25-Mar-1991 14:08:47 -by- Kirk Olynyk [kirko] ;
|
|
; Uses a loop instead of IREPT ;
|
|
; ;
|
|
; Fri 01-Mar-1991 07:34:05 -by- Kirk Olynyk [kirko] ;
|
|
; Wrote it. ;
|
|
;--------------------------------------------------------------------------;
|
|
|
|
cProc sqrtf2_c,8,< \
|
|
uses esi edi ebx, \
|
|
pRes: ptr EFLOAT, \
|
|
pef: ptr EFLOAT >
|
|
|
|
mov esi,pef
|
|
mov edi,[esi].ef_lMant
|
|
mov ebx,[esi].ef_lExp ; EDI:EBX = mant,exp
|
|
|
|
; quick out for zero
|
|
|
|
mov esi,pRes ; ESI -> Result
|
|
or edi,edi
|
|
js short sqrtf_error
|
|
jz short sqrtf_early_out
|
|
|
|
; quick out for one
|
|
|
|
mov eax,ebx
|
|
mov edx,edi
|
|
sub eax,EXPONENT_OF_ONE
|
|
sub edx,MANTISSA_OF_ONE
|
|
or edx,eax
|
|
jz short sqrtf_early_out
|
|
|
|
; Calculate the exponent of the square root
|
|
|
|
sar ebx,1
|
|
sbb ecx,ecx ; ECX = (exp is odd) ? FFFFFFFFh : 0h
|
|
inc ebx
|
|
mov [esi].ef_lExp,ebx ; return the exponent
|
|
|
|
; The mantissa must be shifted. Calculate the shift factor
|
|
; CL = (exp is odd) ? 1 : 2
|
|
|
|
add cl,2
|
|
|
|
; Shift the mantissa, keep extra bits in ESI.
|
|
|
|
xor esi,esi ; esi = 0
|
|
shrd esi,edi,cl
|
|
shr edi,cl ; EDI = M / 2^shift_factor = P
|
|
|
|
; extract high and low word of the mantissa
|
|
|
|
shld ecx,edi,16 ; DI = lo word of P, CX = hi word of P
|
|
|
|
; recursion formula is x(n+1) = [x(n) + t/x(n)]/2, where we are trying to
|
|
; compute sqrt(t), the value below has empirically proven to be a good guess for
|
|
; x(0) in our range of results [bodind]
|
|
|
|
; form zero'th guess for square root
|
|
|
|
lea ebx,[ecx+4000h] ; BX:0000 = zeroth guess
|
|
|
|
; calculate 1'st guess to 16 bit accuracy
|
|
|
|
mov edx,ecx
|
|
mov eax,edi
|
|
div bx
|
|
add bx,ax
|
|
rcr bx,1 ; BX:0000 = 1'st guess
|
|
|
|
; calculate 2'nd guess to 16 bit accuracy
|
|
|
|
mov edx,ecx
|
|
mov eax,edi
|
|
div bx
|
|
add bx,ax
|
|
rcr bx,1 ; BX:0000 = 2'nd guess
|
|
|
|
; calculate 3'rd guess to 32 bit accuracy, division done with
|
|
; proper rounding [bodind]
|
|
|
|
shl ebx,16
|
|
mov edx,edi
|
|
mov eax,esi ; recover the lost bits
|
|
|
|
; do division with rounding, make sure that after adding 1/2 denom
|
|
; that carry bit if ehists is added properly to edx [bodind]
|
|
|
|
mov ecx,ebx
|
|
shr ecx,1
|
|
add eax,ecx
|
|
adc edx,0
|
|
div ebx
|
|
|
|
add ebx,eax
|
|
rcr ebx,1 ; EBX = 3'rd guess
|
|
|
|
mov esi,pRes ; ESI -> to the result
|
|
|
|
; done except that maybe our result is not normalized properly
|
|
|
|
or ebx,ebx ; too big a number, adjust mant and exp
|
|
jns short sqrtf_return_mantissa
|
|
shr ebx,1 ; divide mantissa by 2
|
|
inc dword ptr [esi].ef_lExp ; add one to the exponent
|
|
|
|
; return the mantissa
|
|
|
|
sqrtf_return_mantissa:
|
|
|
|
mov [esi].ef_lMant,ebx
|
|
|
|
sqrtf_error:
|
|
mov eax,esi
|
|
cRet sqrtf2_c
|
|
|
|
; Do early outs.
|
|
|
|
sqrtf_early_out:
|
|
mov [esi].ef_lMant,edi
|
|
mov [esi].ef_lExp,ebx
|
|
mov eax,esi
|
|
cRet sqrtf2_c
|
|
endProc sqrtf2_c
|
|
|
|
;------------------------------Public--Routine-----------------------------;
|
|
; VOID vEfToLfx(pefloat,plfx) ;
|
|
; ;
|
|
; Converts an EFLOAT to a 32.32 fix point number. ;
|
|
; ;
|
|
; Warning: ;
|
|
; No checks are made to see if the EFLOAT can fit. ;
|
|
; ;
|
|
; History: ;
|
|
; Tue 17-Mar-1992 00:32:48 -by- Charles Whitmer [chuckwh] ;
|
|
; Wrote it. ;
|
|
;--------------------------------------------------------------------------;
|
|
|
|
cProc vEfToLfx,8,< \
|
|
pefloat: ptr EFLOAT, \
|
|
plfx: ptr LARGE_INTEGER >
|
|
|
|
; Load the EFLOAT.
|
|
|
|
mov ecx,pefloat
|
|
mov eax,[ecx].ef_lMant
|
|
mov ecx,[ecx].ef_lExp
|
|
|
|
; Sign extend into EDX. The EFLOAT is now EDX.EAX * 2^ECX.
|
|
|
|
cdq
|
|
|
|
; Decide about shifting.
|
|
|
|
or ecx,ecx
|
|
jz short saveit
|
|
jl short shift_right
|
|
|
|
; Shift it left.
|
|
|
|
shld edx,eax,cl
|
|
shl eax,cl
|
|
saveit:
|
|
mov ecx,plfx
|
|
mov [ecx].li_LowPart,eax
|
|
mov [ecx].li_HighPart,edx
|
|
cRet vEfToLfx
|
|
|
|
; Shift it right.
|
|
|
|
shift_right:
|
|
neg ecx
|
|
shrd eax,edx,cl
|
|
sar edx,cl
|
|
mov ecx,plfx
|
|
mov [ecx].li_LowPart,eax
|
|
mov [ecx].li_HighPart,edx
|
|
cRet vEfToLfx
|
|
endProc vEfToLfx
|
|
|
|
end
|