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