;***************************************************************************
; pflaot.asm
;
;     Decimal output of Intel 80bit extended precision real number
;
;  Note: in scientific notation if  ( 1 > value >= 1000 )
;
; call print_float
;
; expects  EAX -> Tbyte ptr of real10
;          EDX -> string buffer (maximum length = NUM_SIG_FIGURES + 9 )
;                 terminates with TERMINATING_CHAR
;
;
;
;***************************************************************************
.386
.387

.model flat

include     debug.inc


POINT_CHAR          EQU     'ú'
TERMINATING_CHAR    EQU     '$'
NUM_SIG_FIGURES     EQU     17


EXPONENT_CHAR       EQU     SUPERSCRIPT_CHAR
EXPONENT_MINUS      EQU     SUPERSCRIPT_CHAR+10
EXPONENT_PLUS       EQU     SUPERSCRIPT_CHAR+11
EXPONENT_TIMES_CHAR EQU     SUPERSCRIPT_CHAR+12

;EXPONENT_CHAR       EQU     '0'
;EXPONENT_MINUS      EQU     '-'
;EXPONENT_PLUS       EQU     '+'
;EXPONENT_TIMES_CHAR EQU     '*'

.CODE

exponent2       long    ?
exponent10      long    ?
significand     real10  ?
max_int_digits  long    3
one4i           long    1
ten4i           long    10
adj10i          long    ?
after_adj       byte    ?
exp10_string    byte    ' ',EXPONENT_TIMES_CHAR,'1','0'


print_float2 PROC
    cld
    pushad
    mov         edi,edx
    mov         edx,eax

    mov     adj10i, 0
    mov     after_adj,0

Loop012:
    inc     after_adj
;    int 3
    finit

    fld Tbyte ptr [edx]

    fxtract         ; exponent in ST(1)

    fldlg2
    fmul    st,st(2)
    frndint         ; round to nearest integer
    fiadd   adj10i

    fist exponent10     ; save exponent (power of 10)

    .if (exponent10 < 3) && (exponent10 > 0)
        inc  after_adj              ; stop after exponent adjust
        mov  exponent10,0           ; zero power of 10
    .endif

    fild    exponent10

    fldl2t
    fmul st,st(1)

    fst st(1)
    frndint
    fstp st(2)
    fsub st,st(1)
    f2xm1
    fld1
    fadd
    fscale

    fld  Tbyte ptr [edx]

    fdivr                   ; convert value

;    comment #

    ;
    ; Adjust to keep scientific notaion
    ;
    cmp     after_adj,1
    ja      _in_range

    ficom      ten4i
    fstsw ax
    sahf
    jb _not_above_equal_10
    inc  adj10i
    jmp  Loop012

_not_above_equal_10:


    ficom      one4i
    fstsw ax
    sahf
    jae _in_range
    dec  adj10i
    jmp  Loop012

_in_range:
;#


    fxtract             ; exponent in ST(1), significand in ST
    fstp significand    ; save sign'
    fist exponent2      ; save exponent (power of 2)


    ; print sign '-' or nothing
    ;
        mov     al,' '
        test    byte ptr [edx+9],10000000b
        jz @f
        mov al,'-'
    @@:
        stosb

      ;
      ; read signifcand into EBX:EDX:EAX
      ;
        mov     eax,dword ptr [significand+0]
        mov     edx,dword ptr [significand+4]
        xor     ebx,ebx

        ; compensate 2^x instruction error in significand.
        ;

        mov     esi,4
        add     eax,esi
        adc     edx,0
        adc     ebx,0



        inc     exponent2
        mov     ecx,exponent2

        shld    ebx,edx,cl
        shld    edx,eax,cl
        shl     eax,cl

        mov     cl,'0'
        call    print_decimal_80bit_unsigned_real_fixedpoint

        ;
        ; Print exponent field
        ;
        mov     ebx, exponent10
        and     ebx,ebx
        jz      finished
        mov     eax,dword ptr exp10_string
        stosd
        mov     al,EXPONENT_PLUS
        jge     @@J3
        neg     ebx
        mov     al,EXPONENT_MINUS
@@J3:
		stosb
        xor     eax,eax
        xor     edx,edx
        mov     cl,EXPONENT_CHAR
        call    print_decimal_80bit_unsigned_real_fixedpoint

finished:
        mov         al,TERMINATING_CHAR
        stosb
        mov         al,0
        stosb
        popad
        ret
print_float2 ENDP





;***************************************************************************
;------------ prints unsigned ( EBX.EDX:EAX ) ------------------
;***************************************************************************

print_decimal_80bit_unsigned_real_fixedpoint PROC USES ESI EDX ECX EAX EBX
Local   Value[4]        :dword
Local   digit_count     :byte
Local   first_zero_flag :byte
Local   ascii_0         :byte
Local   figure_count    :byte


    mov     ascii_0,CL
    mov     figure_count,0



    ;  Value[0..15] contains a 128 bit number with a binary point
    ; between bits 80 & 81
    ;
    ;
    mov     Value[0],0
    mov     Value[4],eax
    mov     Value[8],edx
    mov     Value[12],ebx


    mov     esi,0
    mov     first_zero_flag,0

@@_dec_loop:
    mov     digit_count,0
    xor     eax,eax
    xor     edx,edx
    xor     ecx,ecx
    xor     ebx,ebx
    jmp     div_Loop_start

@@div_Loop01:

  ; 128 bit compare EBX:ECX:EDX:EAX   ,   Value[0..15]
  ;
    cmp     ebx,Value[12]
    ja    Jexit01
    jb    J22
    cmp     ecx,Value[8]
    ja    Jexit01
    jb    J22
    cmp     edx,Value[4]
    ja    Jexit01
    jb    J22
    cmp     eax,Value[0]
    ja    Jexit01
J22:
    ; if comparasson is below then add  EBX:ECX:EDX:EAX with
    ; 128 bit value [decimal_divison]
    ;

    inc     digit_count
div_Loop_start:

    add     eax, decimal_divison[esi+0]
    adc     edx, decimal_divison[esi+4]
    adc     ecx, decimal_divison[esi+8]
    adc     ebx, decimal_divison[esi+12]
    jc      Jexit01

    cmp     digit_count,9
    jb      @@div_Loop01

Jexit01:
    sub     eax, decimal_divison[esi+0]
    sbb     edx, decimal_divison[esi+4]
    sbb     ecx, decimal_divison[esi+8]
    sbb     ebx, decimal_divison[esi+12]

    sub     Value[0], eax
    sbb     Value[4], edx
    sbb     Value[8], ecx
    sbb     Value[12], ebx


    ;
    ; Plot the digit.  IF its a first zero then then skip it.
    ;
    mov     al,digit_count
    cmp     first_zero_flag,al
    je  skip_1stZ
    add     al,ascii_0
    stosb
    inc     figure_count
    mov     first_zero_flag,-1
skip_1stZ:



    add     esi,4*4



    ;
    ; Plot decimal point after the 10th digit
    ;
    .if  (esi == 4*4*10)
    ;
    ; print a '0' if havn't already done so

    call    Print_first_zero

    mov     al,POINT_CHAR
    stosb

    .endif

    ; ---  loop until finished
    ;
    cmp     esi,decimal_divison_SIZE
    jb      @@_dec_loop
@@finished:
    call    Print_first_zero

  ; only display 17 significant figures
  ;
    .while ( figure_count >  NUM_SIG_FIGURES  )
       DEC edi
       DEC figure_count
    .endw


 ; if decimal number was printed remove trailing zero digits
 ;
    .if ( esi >= 4*4*10 )
       mov al,ascii_0
       dec  edi
       .WHILE  (byte ptr [edi] != POINT_CHAR )
    .IF  ([edi] != AL)
       inc edi
       .BREAK
    .ENDIF
    dec edi
    dec     figure_count
       .ENDW
    .endif

    ret


;***********************************************************
; sub procedure to print a zero if one hasn't been printed
;***********************************************************
Print_first_zero:
    .if  ( first_zero_flag == 0)
     mov        al,ascii_0
     stosb
     mov        first_zero_flag,-1
    .endif
    ret 0


print_decimal_80bit_unsigned_real_fixedpoint ENDP


decimal_divison     LABEL   DWORD       ;128 bit unsinged integer array

DQ  0000000000000000h,3B9ACA0000000000h             ;=10^+9 * 2^80
DQ  0000000000000000h,05F5E10000000000h             ;=10^+8 * 2^80
DQ  0000000000000000h,0098968000000000h             ;=10^+7 * 2^80
DQ  0000000000000000h,000F424000000000h             ;=10^+6 * 2^80
DQ  0000000000000000h,000186A000000000h             ;=10^+5 * 2^80
DQ  0000000000000000h,0000271000000000h             ;=10^+4 * 2^80
DQ  0000000000000000h,000003E800000000h             ;=1000  * 2^80
DQ  0000000000000000h,0000006400000000h             ;=100   * 2^80
DQ  0000000000000000h,0000000A00000000h             ;=10    * 2^80
DQ  0000000000000000h,0000000100000000h             ;=1     * 2^80
DQ  9999999999999999h,0000000019999999h             ;=10^-1 * 2^80
DQ  0F5C28F5C28F5C28Fh,00000000028F5C28h            ;=10^-2 * 2^80
DQ  4BC6A7EF9DB22D0Eh,0000000000418937h             ;=10^-3 * 2^80
DQ  0BAC710CB295E9E1Bh,0000000000068DB8h            ;=10^-4 * 2^80
DQ  0AC471B4784230FCFh,000000000000A7C5h            ;=10^-5 * 2^80
DQ  0F7A0B5ED8D36B4C7h,00000000000010C6h            ;=10^-6 * 2^80
DQ  07F29ABCAF485787Ah,00000000000001ADh            ;=10^-7 * 2^80
DQ  0F31DC4611873BF3Fh,000000000000002Ah            ;=10^-8 * 2^80
DQ  4B82FA09B5A52CB9h,0000000000000004h             ;=10^-9 * 2^80
DQ  6DF37F675EF6EADFh,0000000000000000h             ;=10^-10* 2^80
DQ  0AFEBFF0BCB24AAFh,0000000000000000h             ;=10^-11* 2^80
DQ  0119799812DEA111h,0000000000000000h             ;=10^-12* 2^80
DQ  001C25C268497681h,0000000000000000h             ;=10^-13* 2^80
DQ  0002D09370D42573h,0000000000000000h             ;=10^-14* 2^80
DQ  0000480EBE7B9D58h,0000000000000000h             ;=10^-15* 2^80
DQ  00000734ACA5F622h,0000000000000000h             ;=10^-16* 2^80
DQ  000000B877AA3236h,0000000000000000h             ;=10^-17* 2^80
DQ  00000012725DD1D2h,0000000000000000h             ;=10^-18* 2^80
DQ  00000001D83C94FBh,0000000000000000h             ;=10^-19* 2^80
; DQ    000000002F394219h,0000000000000000h             ;=10^-20* 2^80
; DQ    0000000004B8ED02h,0000000000000000h             ;=10^-21* 2^80
; DQ    000000000078E480h,0000000000000000h             ;=10^-22* 2^80
; DQ    00000000000C16D9h,0000000000000000h             ;=10^-23* 2^80
; DQ    000000000001357Ch,0000000000000000h             ;=10^-24* 2^80
; DQ    0000000000001EF2h,0000000000000000h             ;=10^-25* 2^80
; DQ    0000000000000318h,0000000000000000h             ;=10^-26* 2^80
; DQ    000000000000004Fh,0000000000000000h             ;=10^-27* 2^80
; DQ    0000000000000007h,0000000000000000h             ;=10^-28* 2^80
; DQ    0000000000000000h,0000000000000000h             ;=10^-29* 2^80

decimal_divison_SIZE = $ - OFFSET decimal_divison










end

