Следующая подпрограмма берет число из вершины стека и  преобразует его в печатную строку символов.  Фактически,  подпрограмма извлекает число с вершины стека и посылает его на  дисплей. Далее эта подпрограмма будет использована в двух примерах  для вывода их результатов.  Исходный текст программы показан на  Фиг. 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) в самом начале, рассматривая  это, как специальный случай.