Author Topic: Large integers and floats  (Read 98 times)

nidud

  • Member
  • *****
  • Posts: 1323
    • https://github.com/nidud/asmc
Large integers and floats
« on: August 08, 2017, 12:16:04 AM »
There was some problems with the float implementation so I did a small overhaul of the EMU functions. I also added some helper functions for large integers and floats. REAL16 is also added to the assembler.

The new functions are declared in intn.inc and defined in the math directory, and tests added to the test directory.

The real16.asm file is the regress for the Asmc implementation.
Code: [Select]
    ;
    ; v2.25 - REAL16 and float const parameters
    ;
    .486
    .model flat
    .data

    real16 1.e1     ; 0x40024000000000000000000000000000
    real16 1.e2     ; 0x40059000000000000000000000000000
    real16 1.e4     ; 0x400C3880000000000000000000000000
    real16 1.e8     ; 0x40197D78400000000000000000000000
    real16 1.e16    ; 0x40341C37937E08000000000000000000
    real16 1.e32    ; 0x40693B8B5B5056E16B3BE04000000000
    real16 1.e64    ; 0x40D384F03E93FF9F4DAA797ED6E38ED6
    real16 1.e128   ; 0x41A827748F9301D319BF8CDE66D86D62
    real16 1.e256   ; 0x435154FDD7F73BF3BD1BBB77203731FE
    real16 1.e512   ; 0x46A3C633415D4C1D238D98CAB8A978A1
    real16 1.e1024  ; 0x4D4892ECEB0D02EA182ECA1A7A51E317
    real16 1.e2048  ; 0x5A923D1676BB8A7ABBC94E9A519C6536
    real16 1.e4096  ; 0x752588C0A40514412F3592982A7F0095 - F00949524
    real16 1.e8192  ; 0x7FFF0000000000000000000000000000 - Infinity

    REAL16 0.0      ; 0x00000000000000000000000000000000
    REAL16 -0.0     ; 0x80000000000000000000000000000000
    REAL16 1.0      ; 0x3FFF0000000000000000000000000000
    REAL16 -2.0     ; 0xC0000000000000000000000000000000
    ;
    ; 0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF - max quadruple precision
    ;
    ; 0x7FFB9999999999999999999999999997
    ;
    REAL16 1.189731495357231765085759326628007e4931
    ;
    ; 0x4000921FB54442D18469898CC51701B8
    ;
    REAL16 3.1415926535897932384626433832795028

    .code

p1  proc c a1:real4, a2:real8, a3:real10, a4:real16, a5:oword
    lea eax,a1
    lea eax,a2
    lea eax,a3
    lea eax,a4
    lea eax,a5
    ret
p1  endp

p2  proc stdcall a1:real4, a2:real8, a3:real10, a4:real16, a5:oword
    lea eax,a1
    lea eax,a2
    lea eax,a3
    lea eax,a4
    lea eax,a5
    ret
p2  endp

p3  proc pascal a1:real4, a2:real8, a3:real10, a4:real16, a5:oword
    lea eax,a1
    lea eax,a2
    lea eax,a3
    lea eax,a4
    lea eax,a5
    ret
p3  endp

    p1(1.0, 2.0, 3.0, 4.0, 5.0)
    p2(0.1, 0.2, 0.3, 0.4, 0.5)
    p3(10.1, 10.2, 10.3, 10.4, 10.5)

    end

nidud

  • Member
  • *****
  • Posts: 1323
    • https://github.com/nidud/asmc
Re: Large integers and floats
« Reply #1 on: August 10, 2017, 10:08:41 PM »
Some new changes.

All real numbers are now handled as quadruple precision by the assembler and scaled down accordingly. FPU usage for double (strtod()), and the internal long double implementation for real10 is thereby removed, reducing the binary size by around 10K. This also speed up (somewhat surprisingly) the assembly time for the math test.

The work horse for the ASCII to float conversion is the _atonf() function now able to handle any sized number limited to an INT_MAX exponent. The scaling of numbers is n dwords so the mantissa may be of any length.

Sizing up the maximum digits and significant digits is a bit blurry but it's currently scaled to the mantissa size.
Code: [Select]
; _atonf() - Converts a string to float
;
include intn.inc
include alloc.inc
include ltype.inc

    .code

_atonf proc uses esi edi ebx number:ptr, string:ptr, endptr:ptr, expptr:ptr, bits, expbits, n

    local buffer, flags, exponent, radix
    local digits, sigdig, maxdig, maxsig

    mov radix,10    ; assume desimal
    mov eax,bits    ; 53-bit --> 17
    mov ecx,eax     ; 64-bit --> 22
    mov edx,eax     ;113-bit --> 39
    shr eax,2
    shr edx,4
    shr ecx,5
    add eax,edx
    add eax,ecx
    shr ecx,2
    sub eax,ecx
    mov maxdig,eax
    add eax,10
    mov maxsig,eax
    inc eax
    mov buffer,alloca(eax)
    mov edi,number
    mov ecx,n
    xor eax,eax
    rep stosd
    mov sigdig,eax
    mov exponent,eax
    mov flags,_ST_ISZERO
    mov esi,string

    .repeat

        .repeat
            lodsb
            .break(1) .if !al
        .until !(_ltype[eax+1] & _SPACE)
        dec esi

        xor ecx,ecx
        .if al == '+'
            inc esi
            or  ecx,_ST_SIGN
        .endif
        .if al == '-'
            inc esi
            or  ecx,_ST_SIGN or _ST_NEGNUM
        .endif

        lodsb
        .break .if !al

        or  al,0x20
        .if al == 'n'
            mov ax,[esi]
            or  ax,0x2020
            .if ax == 'na'
                add esi,2
                or ecx,_ST_ISNAN
                movzx eax,byte ptr [esi]
                .if al == '('
                    lea edx,[esi+1]
                    movzx eax,byte ptr [edx]
                    .while al == '_' || _ltype[eax+1] & _DIGIT or _UPPER or _LOWER
                        inc edx
                        mov al,[edx]
                    .endw
                    .if al == ')'
                        lea esi,[edx+1]
                    .endif
                .endif
            .else
                dec esi
                or ecx,_ST_INVALID
            .endif
            mov flags,ecx
            .break
        .endif

        .if al == 'i'
            mov ax,[esi]
            or  ax,0x2020
            .if ax == 'fn'
                add esi,2
                or ecx,_ST_ISINF
            .else
                dec esi
                or ecx,_ST_INVALID
            .endif
            mov flags,ecx
            .break
        .endif

        mov ah,[esi]
        or  ah,0x20
        .if ax == 'x0'
            or ecx,_ST_ISHEX
            add esi,2
            mov edx,bits
            shl edx,2
            mov maxdig,edx
        .endif
        dec esi

        mov edi,buffer
        xor ebx,ebx
        xor edx,edx
        xor eax,eax
        ;
        ; Parse the mantissa
        ;
        .while 1
            lodsb
            .break .if !al
            .if al == '.'
                .break .if ecx & _ST_DOT
                or ecx,_ST_DOT
            .else
                .if ecx & _ST_ISHEX
                    .break .if !(_ltype[eax+1] & _HEX)
                .else
                    .break .if !(_ltype[eax+1] & _DIGIT)
                .endif
                .if ecx & _ST_DOT
                    inc sigdig
                .endif
                or ecx,_ST_DIGITS
                or edx,eax
                .continue .if edx == '0' ; if a significant digit
                .if ebx < maxsig
                    stosb
                .endif
                inc ebx
            .endif
        .endw
        mov byte ptr [edi],0
        mov digits,ebx
        ;
        ; Parse the optional exponent
        ;
        xor edx,edx
        .if ecx & _ST_DIGITS

            xor edi,edi ; exponent

            or  al,0x20
            mov ah,'e'
            .if ecx & _ST_ISHEX
                mov ah,'p'
            .endif

            .if al == ah

                mov al,[esi]
                lea edx,[esi-1]
                .if al == '+'
                    inc esi
                .endif
                .if al == '-'
                    inc esi
                    or  ecx,_ST_NEGEXP
                .endif
                and ecx,not _ST_DIGITS

                .while 1
                    movzx eax,byte ptr [esi]
                    .break .if !(_ltype[eax+1] & _DIGIT)
                    .if edi < 100000000 ; else overflow
                        lea ebx,[edi*8]
                        lea edi,[edi*2+ebx-'0']
                        add edi,eax
                    .endif
                    or  ecx,_ST_DIGITS
                    inc esi
                .endw
                .if ecx & _ST_NEGEXP
                    neg edi
                .endif
                .if !(ecx & _ST_DIGITS)
                    mov esi,edx
                .endif
            .else
                dec esi ; digits found, but no e or E
            .endif

            mov edx,edi
            mov eax,sigdig
            .if ecx & _ST_ISHEX
                shl eax,2
            .endif
            sub edx,eax
            mov ebx,digits
            mov eax,maxdig
            .if ebx > eax
                add edx,ebx
                mov ebx,eax
                .if ecx & _ST_ISHEX
                    shl eax,2
                .endif
                sub edx,eax
            .endif
            mov eax,buffer
            .while 1
                .break .ifs ebx <= 0
                .break .if byte ptr [eax+ebx-1] != '0'
                inc edx
                .if ecx & _ST_ISHEX
                    add edx,3
                .endif
                dec ebx
            .endw
            mov digits,ebx
        .else
            mov esi,string
        .endif
        .if ecx & _ST_ISHEX
            mov radix,16
        .endif
        mov flags,ecx
        mov exponent,edx
        mov eax,digits
        add eax,buffer
        mov byte ptr [eax],0
        ;
        ; convert string to binary
        ;
        _atond(number, buffer, radix, n)
        ;
        ; get bit-count of number
        ;
        .if _bsrnd(number, n)
            ;
            ; shift number to bit-size
            ;
            ; - 0x0001 --> 0x8000
            ;
            mov edi,bits
            mov ebx,edi
            sub ebx,eax

            .if eax > edi
                sub eax,edi
                ;
                ; or 0x10000 --> 0x1000
                ;
                _shrnd(number, eax, n)
            .elseif ebx
                _shlnd(number, ebx, n)
            .endif
            ;
            ; create exponent bias and mask
            ;
            mov ecx,expbits
            mov eax,1
            shl eax,cl
            mov ecx,eax     ; sign bit
            dec eax         ; mask
            mov edx,eax
            shr edx,1       ; bias
            add edi,edx     ; bits + bias
            sub edi,ebx     ; - shift count
            dec edi
            and edi,eax     ; remove sign bit
            .if flags & _ST_NEGNUM
                or edi,ecx
            .endif
            mov ebx,ecx
            xor edx,edx     ; get dword-id from bits
            mov eax,bits
            mov ecx,32
            div ecx
            mov ecx,ebx
            shl ecx,1
            dec ecx
            .if edx
                ;
                ; then shift exponent and sign to high word
                ;
                mov edx,ecx
                mov ecx,31
                bsf ebx,ebx
                sub ecx,ebx
                shl edi,cl
                shl edx,cl
                mov ecx,edx
            .endif

            lea ebx,[eax*4]
            add ebx,number
            not ecx
            and [ebx],ecx
            or  [ebx],edi
        .else
            or flags,_ST_ISZERO
        .endif

    .until 1

    mov eax,expptr
    .if eax
        mov ecx,exponent
        mov [eax],ecx
    .endif
    mov eax,endptr
    .if eax
        mov [eax],esi
    .endif
    mov eax,flags
    ret

_atonf endp

    end