; fibo.asm
;
; This program calculates and displays terms of the Fibonacci
; series by using nineteenth century French mathemetician Edouard
; Lucas' formula:
;
;             n           n
; x[n]  = (phi  + (-1/phi) ) / sqrt(5)
;
; phi is the so-called "golden number" and is defined as:
;
; phi = (1 + sqrt(5))/2
;
; This program was written on Sun  02-15-1998  by Ed Beroset
;   and is released to the public domain by the author.
;
        .model tiny
        .code
        .586
        LIMIT = 86
        org 100h
start:
        xor     ax,ax           ;
more2:
        inc     ax
        push    ax              ; save the term number (n)
        call    fibo            ; calculate x[n]
        call    showres         ; show it on screen
        pop     ax              ;
        cmp     ax,LIMIT        ; calculate lots of terms
        jb      more2           ;
        mov     ax,4c00h        ; DOS exit
        int     21h             ;
;
; fibo
;
; calculates the nth term of the Fibonacci series in a non-iterative
; manner.
;
; IN:  ax = n (the term number, where 0 < n < 87)
;
; OUT:
;   dx:ax = x[n]
;   for test purpose, the variable named zulu is filled with the
;   BCD equivalent
;
fibo proc
        push 5
        mov bp,sp
        fild    word ptr [bp]
        fsqrt                   ; st(0) = sqrt(5) = k
        push    ax              ;
        fild    word ptr [bp-2] ; n, k
        fld     st(1)           ; k, n, k
        fld1                    ; 1, k, n, k
        fadd    st(1),st        ; 1, 1+k, k, n, k
        fadd    st,st(0)        ; 2, 1+k, n, k
        fdivp   st(1),st        ; (1+k)/2, n, k
        fyl2x                   ; n*log2((1+k)/2), k
        fld     st(0)           ;
        frndint                 ; int, x, k
        fsub    st(1),st(0)     ; int, frac, k
        fxch    st(1)           ; frac, int
        f2xm1                   ; ((1+k)/2)**n - 1, exp, k
        fld1                    ; 1, ((1+k)/2)**n - 1, exp, k
        faddp                   ; ((1+k)/2)**n, exp, k
        fscale                  ; ((1+k)/2)**n, k
        fld1                    ; 1, ((1+k)/2)**n, k
        fld     st(1)           ; ((1+k)/2)**n, 1, ((1+k)/2)**n, k
        fdivp                   ; 1/(((1+k)/2)**n), ((1+k)/2)**n, k
        shr     al,1            ; Q: is n an odd number?
        jnc     notodd          ;  N: no, so skip
        fchs                    ;  Y: change sign of inverse term
notodd:
        faddp                   ; x, int, k
        fxch    st(1)           ; int, x, k
        ffree   st              ; --, x, k
        fincstp                 ; x, k
        fdivrp                  ;
        push    eax             ;
        fld     st              ;
        fistp   qword ptr [bp-6]; save the result
        fbstp   tbyte ptr [zulu]; save BCD result
        pop     eax             ; in edx:eax
        pop     edx
        ret
endp

showres proc
        mov     cx,18
        mov     si,offset zulu + 18 - 1
        mov     di,offset number
        mov     byte ptr [di],0 ; store a NUL to start
        std                     ; make 'em decrement
more:
        lodsb                   ;
        mov     ah,al           ;
        shr     al,4            ;
        and     ah,0fh          ;
        or      ax,3030h        ;
        mov     [di],ax         ;
        inc     di              ;
        inc     di              ;
skip:
        loop    more            ;
        mov     ax,0a0dh        ; CRLF
        mov     [di],ax         ;
        inc     di              ;
        inc     di              ;
        mov     cx,di           ;
        mov     di,offset number;
        sub     cx,di           ;
        cld                     ;
        mov     al,'0'          ; suppress leading zeroes
        repe    scasb           ;
        mov     dx,di           ;
        dec     dx              ;
        inc     cx              ;
        mov     bx,1            ; write to stdout
        mov     ah,40h          ;
        int     21h             ;
        ret
endp

        .data
zulu    db 18 dup (?)  ;
number  db 38 dup (?)  ;
        end start
