首页 > 解决方案 > 汇编 x86 x87 数字处理器

问题描述

在此处输入图像描述

在此处输入图像描述 我正在尝试在程序集中编写一个循环,相当于:

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 应用任何更改。

如果有人能告诉我我做错了什么,我将不胜感激。

标签: assemblyx86precisionemu8086x87

解决方案


推荐阅读