Search code examples
loopsassemblyx86-16fibonacciemu8086

Code stuck at an infinite loop when finding the nth fibonacci number


I was trying to find the nth Fibonacci number e.x n=3, output = 1

so my logic was this

a = 0
b = 1
input n
si 0

n>2
loop
temp = b
b = a+b
a = b
loop if si/=cx

print b

This is my pseudo code logic. When I tried to implement this I am stuck in an infinite loop


.MODEL SMALL
.STACK 100h
.DATA
 STRING0 DB 'Enter INDEX $'           
.CODE
    MAIN PROC
        MOV AX,@DATA
        MOV DS,AX  
        
        LEA DX, STRING0  
        MOV AH,9
        INT 21H  
        
        
        MOV AH, 2  
        MOV DL,0AH    ;NEW LINE
        INT 21H
        MOV DL,0DH 
        INT 21H   
        
  
        MOV AH,1
        INT 21H 
        SUB CX,CX
        MOV CL,AL
        MOV SI,0
        MOV AX,0
        MOV BX,1
        

        LOOP1:
        
        PUSH BX
        ADD BX,AX
        POP AX
        INC SI
        
        LOOP LOOP1
             
        MOV DX,BX
        MOV AH,9
        INT 21H
         

     MAIN ENDP
END MAIN

I use EMU 4.08. The code us stuck at an infinite loop. I have no idea why

I did SUB cx,cx to move the AL value to CL and use CL as counter otherwise it gives me error that the code failed to send 8bit data to 16bit


Solution

  • I was trying to find the nth Fibonacci number e.x n=3, output = 1

    From your example I understand that you consider the Fibonacci sequence to begin with 0, 1, 1, 2, 3, 5, 8, 13, 21, ...
    Fibonacci himself started his sequence from 1, 2, 3, 5, 8, ...
    See the Wikipedia article https://en.wikipedia.org/wiki/Fibonacci_number

    I didn't follow your pseudo code too much as it has flaws of its own!

    Why your assembly program fails

    • You say your "code is stuck at an infinite loop", but that's not really the case. It is just that your loop executes an extra 50 iterations. The reason is that the DOS.GetCharacter function 01h gives you an ASCII code, that you have to convert into the digit that the pressed key represents. eg. If you press 3, DOS gives you AL=51, and you need to subtract 48 to obtain the inputted digit which is 3.
      But wait, don't use this number 3 as your loop counter already! Since the 1st and 2nd Fibonacci numbers are known from the start, calculating the 3rd Fibonacci number requires just 1 iteration of the loop. Account for this and subtract 2 beforehand.

    • Once your program has found the answer you simply move the result from BX to DX, and expect the DOS.PrintString function 09h to output the number. It can't do that. It's a function that outputs a series of characters (so a string beginning at the address in DX), however your result is still a number in a register. You have to convert it into its textual representation. Displaying numbers with DOS has all the fine details about this conversion!

    Next code allows the user to input a single-digit from 1 to 9

      ...
      mov  ah, 01h   ; DOS.GetCharacter
      int  21h       ; -> AL = ["1","9"]
      sub  al, 48    ; -> AL = [1,9]
      cbw            ; -> AH = 0
      mov  cx, ax    ; -> CX = [1,9]
      xor  ax, ax    ; -> AX = 0
      dec  cx
      jz   PrintIt   ; 1st Fib is 0
      inc  ax        ; -> AX = 1
      dec  cx
      jz   PrintIt   ; 2nd Fib is 1
      cwd            ; -> DX = 0
    CalcIt:          ; 3rd Fib and others
      xchg ax, dx
      add  ax, dx
      loop CalcIt
    
    PrintIt:         ; AX is at most 21 (because of the limited input)
      aam
      add  ax, 3030h ; Conversion into text
      xchg al, ah
      cmp  al, '0'
      mov  dh, 02h   ; DOS.PrintCharacter
      xchg ax, dx
      je   Ones
      int  21h
    Ones:
      mov  dl, dh
      int  21h
    

    Because in your program the output is very limited, I used a special code to display at most 2 digits. For the general case of outputting numbers see this Q/A.