Изображение чисел с плавающей точкой

      Следующая подпрограмма берет число из вершины стека и

    преобразует его в печатную строку символов.  Фактически,

    подпрограмма извлекает число с вершины стека и посылает его на

    дисплей.  Далее эта подпрограмма будет использована в двух примерах

    для вывода их результатов.      Исходный текст программы показан на

    Фиг. 7.25.

 

      Эта подпрограмма достаточно просто строит выводимую символьную

    строку.  Если исходное число NAN, либо бесконечность, или другое

    специальное число сопроцессора 8087, результат будет показан

    неверно.  Первая часть программы - удобное место для использования

    команды FXAM, которая определила бы тип числа в вершине стека.  Но

    в данном примере эта команда не используется, так как

    предполагается, что исходное число имеет нужный тип.

 

      Эта программа не приспособлена для оформления формата

    выводимого числа.  Результат всегда содержит знак (либо пробел,

    либо знак "-") и целую часть, состоящую из одной цифры.  После

    десятичной точки расположены восемь десятичных позиций, а затем

    буква E и три позиции цифр для степени 10.  Результат работы этой

    программы не так хорош, как можно было желать, но он позволяет

    видеть результат работы программы в читабельной форме.  Более

    красивое преобразование числа потребовало бы значительно больше

    команд, и лишь малая часть из них помогла бы пониманию работы

    сопроцессора 8087.

 

      Программа преобразования работает следующим образом.  Сначала

    она определяет порядок числа.  Например, число 1234 имеет порядок

    3; это означает, что оно находится между значениями 103 и 104.

    Найдя правильный порядок числа, программа сохраняет его значение

    (показатель степени результата) и делит исходное число на 10 в этой

    степени.  Теперь число находится в интервале от 1 до 10.  Затем

    программа умножает число на 108.  Запись этого числа в десятичной

    форме дает девять десятичных цифр; старшая цифра - целая часть,

    младшие восемь цифр - дробные разряды.

             Microsoft (R) Macro Assembler Version 5.00              1/1/80 04:04:46

             Фиг. 7.25 Преобразование плавающего формата в текстовый       Page     1-1

 

                                           PAGE    ,132

                                           TITLE   Фиг. 7.25 Преобразование плавающего формата в текстовый

            0000                     CODE    SEGMENT PUBLIC

                                           ASSUME  CS:CODE,DS:CODE,ES:CODE

                                           EXTRN   TEN_TO_X:NEAR

            0000  ????               OLD_CW            DW      ?

            0002  ????               NEW_CW            DW      ?

            0004  ????               EXPONENT        DW      ?

            0006  ???????????????????      BCD_RESULT      DT      ?

                  ?

            0010  ???????????????????      BCD_EXPONENT    DT      ?

                  ?

            001A  00E1F505                 TEN8        DD      100000000

            001E  20 20 20 20 20 20 20     PRINT_STRING    DB      '         E    ',10,13,'$'

                  20 20 45 20 20 20 20

                  0A 0D 24

 

         Фиг. 7.25 Преобразование плавающего формата в текстовый (начало)

                                     PUBLIC  FLOAT_ASCII

                                     ;--------------------------------------------

                                     ; Эта программа извлекает из вершины стека

                                     ;  сопроцессора 8087 число и выводит его на

                                     ;  экран в плавающем формате.

                                     ; Параметры: число в ST(0)

                                     ; Результат: изображение числа на экране;

                                     ;  число извлечено из стека сопроцессора 8087

                                     ;--------------------------------------------

            002F                     FLOAT_ASCII     PROC    NEAR

                                                             ;-----ST(0)-----;-----ST(1)-----;--ST(2)--

                                                             ; X         ; ?         ; ?

            002F  9B D9 C0                       FLD     ST(0)           ; X         ; X         ; ?

            0032  9B D9 E1                       FABS              ; |X|             ; X         ; ?

            0035  9B D9 E8                       FLD1              ; 1         ; |X|             ; X

            0038  9B D9 C9                       FXCH    ST(1)           ; |X|             ; 1             ; X

            003B  9B D9 F1                       FYL2X                   ; LOG2(X)       ; X             ; ?

            003E  9B D9 E9                       FLDL2T                  ; LOG2(10)      ; LOG2(X)       ; X

            0041  9B DE F1                       FDIVRP  ST(1),ST(0)     ; E=LOGX/LOG10  ; X             ; ?

            0044  D9 3E 0000 R                   FNSTCW  OLD_CW          ;           ;           ;

            0048  9B                       FWAIT                   ;           ;           ;

            0049  A1 0000 R                MOV     AX,OLD_CW       ;           ;           ;

            004C  25 F3FF                        AND     AX,NOT 0C00H    ;           ;           ;

            004F  0D 0400                        OR      AX,0400H        ;           ;           ;

            0052  A3 0002 R                MOV     NEW_CW,AX       ;           ;           ;

            0055  9B D9 2E 0002 R                FLDCW   NEW_CW          ;           ;           ;

            005A  9B D9 FC                       FRNDINT                 ; I = INT(E)    ; X             ; ?

            005D  9B D9 2E 0000 R                FLDCW   OLD_CW          ;           ;           ;

            0062  9B DF 16 0004 R                FIST    EXPONENT        ; I         ; X         ; ?

            0067  9B D9 E0                       FCHS              ; -I        ; X         ; ?

            006A  E8 0000 E                CALL    TEN_TO_X        ; 10 ** (-I)    ; X           ; ?

            006D  9B DE C9                       FMULP   ST(1),ST(0)     ; X/10**I       ; ?             ; ?

            0070  9B DA 0E 001A R                FIMUL   TEN8            ; Мантисса      ; ?             ; ?

            0075  9B DF 36 0006 R                FBSTP   BCD_RESULT      ; ?         ; ?         ; ?

            007A  9B DF 06 0004 R                FILD    EXPONENT        ; I         ; ?         ; ?

            007F  9B DF 36 0010 R                FBSTP   BCD_EXPONENT    ; ?         ; ?         ; ?

                                     ;-----  Вывод на экран значений,запомненных как упакованные

                                     ;       целые двоично-десятичные числа

            0084  FC                       CLD

            0085  8D 3E 001E R                   LEA     DI,PRINT_STRING                   ; Указатель на выводимую

                                                                         ;  строку

            0089  A0 000F R                MOV     AL,BYTE PTR BCD_RESULT+9

            008C  E8 00C3 R                CALL    PRINT_SIGN                  ; Печать знака

            008F  A0 000A R                MOV     AL,BYTE PTR BCD_RESULT+4

            0092  E8 00DF R                CALL    PRINT_NYBBLE                ; Печать первой цифры

            0095  B0 2E                    MOV     AL,'.'                          ; Десятичная точка

            0097  AA                       STOSB

            0098  8D 1E 0009 R                   LEA     BX,BCD_RESULT+3

            009C  B9 0004                        MOV     CX,4                        ; Печать 8 байт (16 цифр)

            009F                     DO_BYTE:                            ;  после десятичной точки

            009F  E8 00CD R                CALL    PRINT_BYTE

            00A2  E2 FB                    LOOP    DO_BYTE

            00A4  B0 45                    MOV     AL,'E'                          ; Символ экспоненты

            00A6  AA                       STOSB

 

         Фиг. 7.25 Преобразование плавающего формата в текстовый (продолжение)

            00A7  A0 0019 R                MOV     AL,BYTE PTR BCD_EXPONENT+9

            00AA  E8 00C3 R                CALL    PRINT_SIGN                  ; Печать знака экспоненты

            00AD  A0 0011 R                MOV     AL,BYTE PTR BCD_EXPONENT+1

            00B0  E8 00DF R                CALL    PRINT_NYBBLE                ; Первая цифра экспоненты

            00B3  8D 1E 0010 R                   LEA     BX,BCD_EXPONENT

            00B7  E8 00CD R                CALL    PRINT_BYTE                  ; Оставшиеся цифры

            00BA  8D 16 001E R                   LEA     DX,PRINT_STRING

            00BE  B4 09                    MOV     AH,9H

            00C0  CD 21                    INT     21H                         ; Вывод всей строки на экран

            00C2  C3                       RET

            00C3                     FLOAT_ASCII     ENDP

 

                                     ;-----  Эта подпрограмма выводит ' ' или '+'

            00C3                     PRINT_SIGN      PROC    NEAR

            00C3  3C 00                    CMP     AL,0                 ; Проверка на знак

            00C5  B0 20                    MOV     AL,' '                 ; Занесение положительного знака

            00C7  74 02                    JZ      POSITIVE

            00C9  B0 2D                    MOV     AL,'-'                 ; Занесение минуса

            00CB                     POSITIVE:

            00CB  AA                       STOSB                         ; Сохранение в выводимой строке

            00CC  C3                       RET

            00CD                     PRINT_SIGN      ENDP

 

                                     ;-----  Эта программа печатает две десятичные цифры,

                                     ;       находящиеся в памяти по адресу [BX]

 

            00CD                     PRINT_BYTE      PROC    NEAR

            00CD  8A 07                    MOV     AL,[BX]              ; Выборка байта

            00CF  51                       PUSH    CX

            00D0  B1 04                    MOV     CL,4

            00D2  D2 E8                    SHR     AL,CL                ; Сдвиг старшей цифры

            00D4  59                       POP     CX

            00D5  E8 00DF R                CALL    PRINT_NYBBLE          ; Печать старшей цифры

            00D8  8A 07                    MOV     AL,[BX]              ; Выборка младшей цифры

            00DA  E8 00DF R                CALL    PRINT_NYBBLE          ; Печать младшей цифры

            00DD  4B                       DEC     BX              ; Переход на следующую пару цифр

            00DE  C3                       RET

            00DF                     PRINT_BYTE      ENDP

 

                                     ;-----  Печать одной десятичной цифры из регистра AL

 

            00DF                     PRINT_NYBBLE    PROC    NEAR

            00DF  24 0F                    AND     AL,0FH               ; Выделение младшей цифры

            00E1  04 30                    ADD     AL,'0'                 ; Преобразование в символ

            00E3  AA                       STOSB                         ; Сохранение в выводимой строке

            00E4  C3                       RET

            00E5                     PRINT_NYBBLE    ENDP

            00E5                     CODE    ENDS

                                           END

 

         Фиг. 7.25 Преобразование плавающего формата в текстовый (продолжение)

 

      Первая часть программы определяет правильный порядок исходного

    числа.  В программе логарифм числа по основанию 10 находится с

    помощью формулы

      Log10(X) = Log2(X)/Log2(10)

 

      Затем округляется порядок в направлении минус бесконечности,

    опять используя управление округлением.  В предыдущем примере,

    вычисляя 10X, мы пользовались умножением для переноса исходного

    числа в нужный диапазон.  Теперь мы используем константу TENB

    (которая содержит целое число 108) для того, чтобы вернуть число в

    нужный диапазон.  Наконец, команда FBSTP дважды преобразует числа в

    десятичное представление; сначала она дает нам девять цифр мантиссы

    числа, а затем - три цифры порядка.

 

      Остальная часть программы выполняет символьную обработку,

    необходимую для преобразования десятичного представления в строки

    символов.  Программа определяет и показывает знаки числа и порядка.

    Она распаковывает десятичные байты и преобразует их в символы;

    подпрограмма PRINT_BYTE делает распаковку, а подпрограмма

    PRINT_NYBBLE выполняте преобразование в символы.  Заметим, что в

    этом случае не нужна команда XLAT, так как все цифры имеют значения

    между 0 и 9.  (Но если исходное число - одно из неопределенных

    чисел, символьная строка будет содержать некоторые непонятные

    символы).

 

      Эта программа верно печатает любое число, лежащее в диапазоне

    длинных действительных чисел.  Любое число, выходящее за пределы

    возможностей этого представления (например 101234) имеет поле

    порядка, сокращенное до трех цифр.    Конечно, вы можете изменить

    программу так, чтобы она обрабатывала четыре цифры поля порядка,

    если вы этого желаете.  Но существует все же число, которое

    программой обрабатывается верно, но вы, возможно, пожелаетет

    изменить его изображение.  Если исходное число 0, результат

    печатается в виде 0.00000000E-932.    Так происходит потому, что поле

    порядка имеет смещение; процессор 8087 представляет число 0 с

    минимально возможным порядком (-4932) и с нулевой мантиссой.  Когда

    программа преобразует число в код ASCII, она верно печатает

    мантиссу и порядок (за исключением того, что ей приходится усекать

    порядок до трех цифр).  Если вы захотите обрабатывать такой порядок

    отдельно, то измените программу, вставив в нее проверку на нуль

    (чаще всего, с помощью команды FTST) в самом начале, рассматривая

    это, как специальный случай.

Hosted by uCoz