I'm trying to write a loop in assembly that is the equivalent of:
for(i=0; x1 + i*h <= x2; i++)
And each time I call another function that uses (x1 + i*h) as one of its parameters for some reason it receives it with the addition of 0.00000000000000001. For example if I send it 0.26 it receives 0.26000000000000001 instead, which ends up in crashing the program.
Here's the C part of the program:
#include <stdio.h>
#include <math.h>
extern double find_delta1(double(*f)(double), double x0, double eps);
extern double find_delta2(double(*f)(double), double x1, double x2, double h, double eps);
double mysqr(double x)
{
return x*x;
} // mysqr
int main()
{
double x1 = -0.5, x2 = 1.0, x, eps = 0.001, h = 0.01;
x = (x1 + x2) / 2.0;
printf("\nfind_delta1(mysqr,%lf, %lf) = %lf\n", x, eps, find_delta1(mysqr, x, eps));
printf("\nfind_delta2(mysqr, %lf, %lf,%lf, %lf) = %lf\n", x, x2, h, eps, find_delta2(mysqr, x, x2, h, eps));
return 0;
} // main
And here's the assembly part:
.MODEL SMALL
.DATA
DELTA DQ ?
CURRENTX DQ ?
TEMP DQ ?
MIN DQ ?
X DQ ?
I DW ?
TWO DQ 2.0
.CODE
.386
.387
;double find_delta1(double (*f)(double),double x0, double eps)
; +4 +6 +14
PUBLIC _find_delta1
_find_delta1 PROC NEAR
PUSH BP
MOV BP,SP
FLDZ ;
FST X ;
FSTP DELTA ; Initialize parameters
FLD QWORD PTR [BP+6] ;
FABS ;
FSTP DELTA ; Delta = |X0|
LOOP1:
FLD DELTA
FDIV TWO ;
FST DELTA ; Delta = Delta / 2.0
FLD QWORD PTR [BP+6] ;
FADD ;
FSTP X ; X = X0 + Delta
PUSH X ;
CALL WORD PTR [BP+4] ;
ADD SP,8 ; ST(0) = f(X)
PUSH QWORD PTR [BP+6] ;
CALL WORD PTR [BP+4] ;
ADD SP,8 ; ST(0) = f(X0)
FSUB ;
FABS ; ST(0) = |f(X) - f(X0)|
FCOMP QWORD PTR [BP+14] ;
FSTSW AX ;
SAHF ; Compare with epsilon
JNB LOOP1
FLD DELTA ; Return Delta
POP BP
RET
_find_delta1 ENDP
;----------------------------------------------------------------------------------------------------------------------------
;----------------------------------------------------------------------------------------------------------------------------
;double find_delta2(double (*f)(double),double x1, double x2, double h, double eps)
; +4 +6 +14 +22 +30
PUBLIC _find_delta2
_find_delta2 PROC NEAR
PUSH BP
MOV BP,SP
MOV I,0
FLDZ ;
FST TEMP ;
FST CURRENTX ;
FSTP MIN ; Initialize parameters
PUSH QWORD PTR [BP+30] ;
PUSH QWORD PTR [BP+6] ;
PUSH WORD PTR [BP+4] ;
CALL _find_delta1 ;
ADD SP,20 ; MIN = find_delta1(mysqr, X1, eps)
FSTP MIN
LOOP2:
FLD QWORD PTR [BP+6] ; ST(0) = X1
FLD QWORD PTR [BP+22] ; ST(0) = h
FIMUL I ; ST(0) = I*h
FADD ; ST(0) = X1 + I*h
FSTP CURRENTX
PUSH QWORD PTR [BP+30] ;
PUSH CURRENTX ;
PUSH WORD PTR [BP+4] ;
CALL _find_delta1 ;
ADD SP,20 ; ST(0) = find_delta1(mysqr, X1 + I*h, eps)
FCOM MIN ;
FSTSW AX ;
SAHF ;
JNB NOTBELOW ; Compare with current minimum
FSTP MIN ; If (find_delta1(mysqr, X1 + I*h, eps) < MIN)
INC I ; -> MIN = find_delta1(mysqr, X1 + I*h, eps)
JMP SHORT NEXT ; i++
NOTBELOW: ; Else
FSTP TEMP ; -> i++
INC I ;
NEXT:
FLD CURRENTX
FCOMP QWORD PTR [BP+14] ;
FSTSW AX ;
SAHF ;
JNE LOOP2 ; Compare (X1 + I*h) with X2
FLD MIN
POP BP
RET
_find_delta2 ENDP
END
The problem occurs in the second iteration of LOOP2, since the first time I*h = 0, hence no change is applied to x1.
If someone can tell me what I'm doing wrong I'd be very grateful.