Search code examples
assemblyx86x87

x86 Assembly Newtons square root algorithm registers are 1#IND


I am trying to write an assembly version of the C program below. It is meant to take the square root of 9. Everything seems to be working until the 3rd pass through my loop, and then my values for upper and lower become 1#IND when pushed to the stack. I don't know why because it correctly prints just below the label whileLoop, but I get the wrong values the second time it is printed directly after the label notAccurateEnough, even though the values don't change between these two labels and it worked fine on the previous iterations.
Below are screenshots that show how it successfully prints once, then fails to print the second time in the same iteration.

Sucessfully pring

Now it's broken

Assembly Code:

.586
.MODEL FLAT
.STACK 4096                 
n=550
.data
    PUBLIC _sqrtX

upper REAL4 9.0
accuracy REAL4 0.00001
lower REAL4 1.0
guess REAL4 1.0
multValue REAL4 1.0
num REAL4 9.0
two DWORD 2

.code

_sqrtX  PROC

        finit   ;initialize fpu

        whileLoop:
        fld upper    ;push upper onto stack
        fld lower    ;push lower onto stack
        fsub         ;subtract upper-lower

        fld accuracy          ;push accuracy onto stack
        fcom                  ;compare accuracy with upper-lower

        fstsw ax              ;copy condition code bits to AX
        sahf                  ;shift condition code bits to flags
        jna notAccurateEnough ;jump if accuracy is greater
        jmp endnewt           ;end algorith, is less than accuracy

        notAccurateEnough:
        ;**************************
        ;************  Logic to implement:   guess = (lower + upper) / 2;
        ;**************************
        fld upper      ;push upper onto stack
        fld lower      ;push lower onto stack
        fadd           ;(lower + upper)
        fidiv two      ;divide by 2
        fstp guess     ;set guess to first stack element. guess = (lower + upper) / 2
        ;**************************

        ;**************************
        ;************  Logic to implement:  if((guess * guess) > number)
        ;**************************
        fld guess ;push guess onto stack as first element
        fld guess ;push guess onto stack again, it is now first and second element
        fmul      ;multiply first and second element
        fcom num  ;compare 9 to product of guess*guess:
        fstsw ax  ;copy condition code bits to AX
        sahf      ;shift condition code bits to flags
        jna SetLower ;if guess is less than num, call set lower and set lower = guess;
        ;*** else, guess > num
        fld guess ;push guess onto the stack
        fstp upper ;set upper equal to top of stack: upper = guess
        jmp whileLoop
        ;**************************

        setLower:
        fld guess   ;push guess onto stack
        fstp lower  ;store guess in lower
        jmp whileLoop

        endnewt:
        mov eax, 0
        ret

_sqrtX ENDP
END

C algorithm I am trying to write in Assembly:

double sqrtX (double x)
{
    const double ACCURACY=0.00001;
    double lower, upper, guess;
    double number;

    number = x;
    lower = 1;
    upper = number;

    while ((upper-lower) > ACCURACY)
    {
        guess = (lower + upper) / 2;
        if((guess * guess) > number)
        {
            upper = guess;
        }
        else
        {
            lower = guess;
        }
    }
    return (lower + upper)/2;
}

Solution

  • Had stack overflow. Cleared the stack after each iteration with finit and now it works.