7.8.4. Квадратное уравнение

Теперь приведем два примера, использующих программу индикации чисел с плавающей точкой. Первый пример - решение квадратного уравнения. Найдем корни уравнения, задаваемого следующей формулой


0 = A*X**2 + B*X + C

Из школьного курса математики известно, что решение этого уравнения


X = ( -B +- SQR( B**2 - 4*A*C))/(2*A)

Программа решения этого уравнения очевидна и показана на Фиг. 7.26. В ней предполагается, что все три параметра A, B и C записаны в виде целых чисел. Конечно, если вы будете использовать программу не только как пример, нужно организовать процедуру ввода различных коэффициентов.


Microsoft (R) Macro Assembler Version 5.00                  1/1/80 04:03:56
Фиг. 7.26 Вычисление корней квадратного уравнения                 Page  1-1
PAGE  ,132
                         TITLE    Фиг. 7.26 Вычисление корней квадратного уравнения
0000                     STACK    SEGMENT STACK
0000    0040[                     DW        64 DUP (?)
             ????
            ]
0080                     STACK    ENDS

0000                     CODE     SEGMENT 

                                  ASSUME    CS:CODE,DS:CODE,ES:CODE
                         EXTRN    FLOAT_ASCII:NEAR
0000    0001             A        DW        1
0002    FFFB             B        DW        -5
0004    0006             C        DW        6
0006    ????             STATUS   DW        ?
0008    0004             FOUR     DW        4
000A    0002             TWO      DW        2
000C    8C AD A8 AC EB A5 20  ERROR_MSG     DB       'Мнимые корни',10,13,'$'
        AA AE E0 AD A8 0A 0D
        24
001B                     QUADRATIC  PROC    FAR
001B    1E                        PUSH      DS            ; Сохранение адреса возврата
001C    2B C0                     SUB       AX,AX
001E    50                        PUSH      AX
001F    8C C8                     MOV       AX,CS
0021    8E D8                     MOV       DS,AX
0023    8E C0                     MOV       ES,AX
0025    9B DB E3                  FINIT                   ;-----ST(0)-----;-----ST(1)------
0028    9B DF 06 0002 R           FILD      B             ; B             ; ?
002D    9B D8 8E 0000             FMUL      ST(0)         ; B**2          ; ?
0032    9B DF 06 0000 R           FILD      A             ; A             ; B**2
0037    9B DE 0E 0008 R           FIMUL     FOUR          ; 4*A           ; B**2
003C    9B DE 0E 0004 R           FIMUL     C             ; 4*A*C         ; B**2
0041    9B DE E1                  FSUBRP    ST(1),ST(0)   ; D=B**2-4*A*C  ; ?
0044    9B D9 E4                  FTST
0047    9B DD 3E 0006 R           FSTSW     STATUS
004C    9B                        FWAIT
004D    8A 26 0007 R              MOV       AH,BYTE PTR STATUS+1
0051    9E                        SAHF
0052    72 37                     JB        IMAGINARY
0054    9B D9 FA                  FSQRT                   ; SQR(D)        ;
0057    9B D9 C0                  FLD       ST(0)         ; SQR(D)        ; SQR(D)
005A    9B D9 E0                  FCHS                    ; -SQR(D)       ; SQR(D)
005D    9B DE 06 0002 R           FIADD     B             ; B-SQR(D)      ; SQR(D)
0062    9B D9 E0                  FCHS                    ; -B+SQR(D)     ; SQR(D)
0065    9B D9 C9                  FXCH      ST(1)         ; SQR(D)        ; -B+SQR(D)
0068    9B DE 06 0002 R           FIADD     B             ; B+SQR(D)      ; -B+SQR(D)
006D    9B D9 E0                  FCHS                    ; N1=-B-SQR(D)  ; N2=-B+SQR(D)
0070    9B DE 36 0000 R           FIDIV     A             ; N1/A          ; N2
0075    9B DE 36 000A R           FIDIV     TWO           ; ROOT1=N1/2*A  ; N2
007A    E8 0000 E                 CALL      FLOAT_ASCII   ; N2            ; ?
007D    9B DE 36 0000 R           FIDIV     A             ; N2/A          ; ?
0082    9B DE 36 000A R           FIDIV     TWO           ; ROOT2=N2/2*A  ; ?
0087    E8 0000 E                 CALL      FLOAT_ASCII   ; ?             ; ?
008A    CB                        RET
008B                       IMAGINARY:
008B    8D 16 000C R              LEA       DX,ERROR_MSG
008F    B4 09                     MOV       AH,9H
0091    CD 21                     INT       21H           ; Вывод сообщения об ошибке
0093    CB                        RET
0094                       QUADRATIC       ENDP
0094                       CODE    ENDS
                           END     QUADRATIC

                           Фиг. 7.26 Вычисление корней квадратного уравнения

В примере отсутствует обработка комплексных чисел, но имеется проверка дискриминанта (B**2 4*A*C) на отрицательность, и если это число отрицательно, программа завешается с сообщением об ошибке. Можно было бы ввести в программу комплексную арифметику, тем не менее, ее нет в данном примере. Необходимо помнить, что сопроцессор 8087 не обрабатывает автоматически комплексные или мнимые числа, и нужно писать программу раздельной обработки действительной и мнимой частей комплексного числа.

Команда FTST проверяет дискриминант на отрицательность; она подобна сравнению с встроенным нулевым операндом источника. Программа записывает слово состояния в память, а затем загружает его в регистр флагов микропроцессора 8088. После этого делается проверка JB (переход, если меньше), определяющая, меньше ли нуля дискриминант. Оставшаяся часть программы проделывает работу по вычислению двух корней уравнения, и здесь используется то преимущество, что коэффициенты находятся в памяти. Такой подход минимизирует объем используемого в сопроцессоре 8087 стека. Но если вы переделаете эту программу так, что она будет подпрограммой, вызываемой из другой программы, вам, вероятно, захочется передавать параметры ей с помощью стека сопроцессора 8087. В этом случае потребуется другой способ для загрузки подпрограммой некоторых величин.