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