.model small .386p .stack .data ten dw 10 v1 dq 9.99999999999e7 v2 dq 0.00004321 v3 dq 1.23456789e23 v4 dq 45.2 nan db "(NAN)$",0 crlf db 10,13,'$' buf db 32 dup (0) .code ; ; this basically does NO checking for exceptions. ; It does clear them after the fact :) ; however, I do try to keep everything in bounds before doing any math... ; ; you have to write your own if you want non-exponential values for ; small numbers, but, the routines given should make that easy enough ; ; note I AM using log functions rather than a table-driven approach ; so, it might be a little inacurate at the extremes of significance ; ; ; get exponent and mantissa and sign ; ; enter: ; st(0) = value ; ; returns: ; ax = 0 ; ok val ; ; st(0) = mantissa ; bx = exp ; dx = sign ( +-1) ; ; ax = -1 ; infinity or dnormal ; fextract PROC enter 6,0 fstcw [bp-2] mov ax,[bp-2] or ah,0ch ; round toward zero mov [bp-4],ax fldcw [bp-4] ftst fnstsw ax fnclex ; just in case ... sahf mov eax,-1 ; first check for out of range jp fxx jnz dosign ; now check for zero sub bx,bx sub dx,dx jmp fxx dosign: mov dx,1 ; nonzero, finally get sign jnc pos fabs ; we will work with positive nums hereafter mov dx,-1 pos: fldlg2 ; log to base 10 fxch fyl2x fld st(0) ; get int part frndint fist word ptr [bp-6] pop bx fsubp ; fraction fldl2t ; convert back to base 2 fmulp fld st(0) ; lovely exponentiation frndint fxch fld st(1) fsubp f2xm1 ; fld1 faddp fscale fxch fcomp sub eax,eax fxx: fnclex fldcw [bp-2] fwait pop esi leave ret fextract ENDP ; ; get next digit from mantissa ; ; enter: ; mantissa from fextract on stack ; ; exit: ; eax = next digit (base 10) ; stack = new mantissa ; fnd PROC ENTER 6,0 fstcw [bp-2] mov ax,[bp-2] or ah,0ch ; round toward zero mov [bp-4],ax fldcw [bp-4] fld st(0) ; next digit frndint fist word ptr [bp-6] fsubp ; new mantissa fimul word ptr [ten] fnclex fldcw [bp-2] fwait pop ax ; cute trick to get result :) leave ret fnd ENDP ; ; calculate a power of 10 ; ; enter: ; eax = power ; exit: ; top of stack = exponent ; fpow PROC enter 4,0 fstcw [bp-2] mov ax,[bp-2] or ah,0ch ; round toward zero mov [bp-4],ax fldcw [bp-4] push eax fild dword ptr [esp] pop eax fldl2t ; y * log base 2 of 10 fmulp fld st(0) ; integral part frndint fsub st(1),st(0) fxch ; fractional part f2xm1 ; exponentiate fraction fld1 ; base 2 faddp fscale ; now scale in integral part fxch ; aren't intel processors a blast? fcomp ; have to clear stack fnclex fldcw [bp-2] leave ret fpow ENDP ; ; enter: ; floating value on fstack ; cx = number of significant digis ; ; exit: ; si = pointer to fp buf ; putfloat PROC mov di,offset buf ; get output buf mov al,'0' ; put a zero in case number is a multiple of 10 stosb ; after rounding call fextract ; xtract the mantissa and sign and exponent or eax,eax ; see if number jz isnum mov si,offset nan ; no, get nan msg ret isnum: or dx,dx ; else get sign jns noneg mov al,'-' call putch noneg: call fnd ; now put out first digit and . call putdig mov al,'.' call putch jcxz nosig ; now put out significant digits lp: call fnd call putdig loop lp nosig: call fnd ; now get next sig digit cmp al,5 ; need to round? jc nornd push di ; yep, doi a base 10 round rnl: dec di cmp byte ptr [di],'.' jz rnl inc byte ptr [di] cmp byte ptr [di],'9' jbe rndone mov byte ptr [di],'0' cmp di,offset buf jnz rnl rndone: pop di nornd: mov al,'E' ; now E for exponent call putch or bx,bx ; get sign of exponent jns nnx neg bx mov al,'-' call putch nnx: mov ax,bx ; put val of exponent call putexp mov si,offset buf ; figure out where result starts lodsb cmp al,'0' jz fpx dec si fpx: ret putexp: sub cx,cx el1: sub dx,dx div [ten] push dx inc cx or ax,ax jnz el1 el2: pop ax call putdig loop el2 fcomp ; clear FP stack fnclex ; might have made a stack fault there... mov al,'$' call putch ret putdig: or al,'0' putch: stosb ret putfloat ENDP ; ;-------------------------------- ; test routines start here ; printval: mov dx,si mov ah,9 int 21h mov dx,offset crlf mov ah,9 int 21h ret testit: fninit push dgroup pop ds push dgroup pop es fld qword ptr [v1] mov cx,6 call putfloat call printval fld qword ptr [v2] mov cx,2 call putfloat call printval fld qword ptr [v3] mov cx,16 call putfloat call printval fld qword ptr [v4] mov cx,0 call putfloat call printval mov ax,4c00h int 21h end testit