Сборка x86 x87 Numeric Proccesor
Я пытаюсь написать цикл в сборке, которая эквивалентна:
for(i=0; x1 + i*h <= x2; i++)
И каждый раз, когда я вызываю другую функцию, которая использует (x1 + i*h) в качестве одного из своих параметров, по какой-то причине она получает ее с добавлением 0,00000000000000001. Например, если я отправлю 0,26, он получит 0,26000000000000001 вместо этого, что приведет к сбою программы.
Вот часть C программы:
#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
А вот и сборочная часть:
.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
Проблема возникает во второй итерации LOOP2, так как в первый раз I*h = 0, следовательно, никакие изменения не применяются к x1.
Если кто-то может сказать мне, что я делаю неправильно, я был бы очень благодарен.