
Доцент
 
Профиль
Группа: Участник Клуба
Сообщений: 686
Регистрация: 7.4.2002
Где: Украина, Харьков
Репутация: нет Всего: 5
|
Вот, может пригодится: Код |
; ЛИСТИНГ 2.5 ; Набор подпрограмм, предназначенных для ; перевода целых и вещественных чисел из двоичной ; системы счисления в десятичную и наоборот ; ; Автор текста программы Кулаков Владимир Геннадьевич. ; Файл list2_05.inc, 24.05.2002.
DATASEG ; Количество разрядов мантиссы (1-18) MaxPositions DW 10 ; Количество знаков числа после запятой (1-17) NumberSymbolsAD DW 5 ; Машинный ноль Data_Minimum DQ 1.E-110 ; Константы (10 в степени N) MConst DQ 1.0E1,1.0E2,1.0E3,1.0E4,1.0E5 DQ 1.0E6,1.0E7,1.0E8,1.0E9,1.0E10 DQ 1.0E11,1.0E12,1.0E13,1.0E14,1.0E15 DQ 1.0E16,1.0E17,1.0E18,1.0E19,1.0E20 DQ 1.0E21,1.0E22,1.0E23,1.0E24,1.0E25 DQ 1.0E26,1.0E27,1.0E28,1.0E29,1.0E30 DQ 1.0E31,1.0E32,1.0E33,1.0E34,1.0E35 DQ 1.0E36,1.0E37,1.0E38,1.0E39,1.0E40 DQ 1.0E41,1.0E42,1.0E43,1.0E44,1.0E45 DQ 1.0E46,1.0E47,1.0E48,1.0E49,1.0E50 DQ 1.0E51,1.0E52,1.0E53,1.0E54,1.0E55 DQ 1.0E56,1.0E57,1.0E58,1.0E59,1.0E60 DQ 1.0E61,1.0E62,1.0E63,1.0E64,1.0E65 DQ 1.0E66,1.0E67,1.0E68,1.0E69,1.0E70 DQ 1.0E71,1.0E72,1.0E73,1.0E74,1.0E75 DQ 1.0E76,1.0E77,1.0E78,1.0E79,1.0E80 DQ 1.0E81,1.0E82,1.0E83,1.0E84,1.0E85 DQ 1.0E86,1.0E87,1.0E88,1.0E89,1.0E90 DQ 1.0E91,1.0E92,1.0E93,1.0E94,1.0E95 DQ 1.0E96,1.0E97,1.0E98,1.0E99,1.0E100 DQ 1.0E101,1.0E102,1.0E103,1.0E104,1.0E105 DQ 1.0E106,1.0E107,1.0E108,1.0E109,1.0E110 DQ 1.0E111,1.0E112,1.0E113,1.0E114,1.0E115 DQ 1.0E116,1.0E117,1.0E118,1.0E119,1.0E120 DQ 1.0E121,1.0E122,1.0E123,1.0E124,1.0E125 DQ 1.0E126,1.0E127,1.0E128 ; Данные передаются в математические процедуры ; через общую область памяти (главный сегмент данных) ; 32-разрядное целое число Data_Int32 DD ? ; Число с плавающей запятой двойной точности Data_Double DQ ? ; Модуль числа с плавающей запятой Data_Abs DQ ? ; Число в BCD-формате Data_BCD DT ? ; Управляющее слово сопроцессора Data_Control DW ? ; Вспомогательный флаг Data_Flag DB ? ; Целая часть десятичного логарифма числа Data_Log10 DW ? ; Знак результата (если не 0 - отрицательное число) Data_Sign DB ? ; Строка для хранения числа в коде ASCII Data_String DB 32 DUP (?) ; Структура для вывода результата OutD_String DB 34 DUP (?) EVEN
CODESEG ;*************************************************** ;* ПРЕОБРАЗОВАТЬ 32-РАЗРЯДНОЕ ЦЕЛОЕ ЧИСЛО В СТРОКУ * ;* Входные параметры: * ;* Data_Int32 - 32-разрядное число. * ;* Выходные параметры: * ;* Data_String - строка-результат. * ;*************************************************** PROC Int32_to_String near pushad push DS push ES mov AX,[CS:MainDataSeg] mov DS,AX mov ES,AX cld ; Перевести число из двоичного кода в код BCD fninit ;сброс сопроцессора ; Загрузить число в двоичном коде fild [Data_Int32] ; Извлечь число в коде BCD fbstp [Data_BCD] ; Результат записывать в строку Data_String mov DI,offset Data_String call BCD_to_ASCII ; Записать признак конца строки (код 0) xor AL,AL stosb pop ES pop DS popad ret ENDP Int32_to_String
;***************************************************** ;* ПРЕОБРАЗОВАТЬ СТРОКУ В 32-РАЗРЯДНОЕ ЦЕЛОЕ ЧИСЛО * ;* Входные параметры: * ;* Data_String - число в коде ASCII. * ;* Выходные параметры: * ;* Data_Int32 - 32-разрядное число в двоичном коде. * ;***************************************************** PROC String_to_Int32 near pushad push DS mov AX,[CS:MainDataSeg] mov DS,AX cld ; Очищаем Data_BCD mov [dword ptr Data_BCD],0 mov [dword ptr Data_BCD+4],0 mov [word ptr Data_BCD+8],0 ; Очищаем байт знака mov [Data_Sign],0 ; Заносим в SI указатель на строку mov SI,offset Data_String
; Пропускаем пробелы перед числом mov CX,64 ;защита от зацикливания @@ShiftIgnore: lodsb cmp AL,' ' jne @@ShiftIgnoreEnd loop @@ShiftIgnore jmp short @@Error @@ShiftIgnoreEnd: ; Проверяем знак числа cmp AL,'-' jne @@Positive mov [Data_Sign],80h lodsb @@Positive: ; 32-битное двоичное число соответствует ; десятичному, имеющему до 9 разрядов mov CX,9 @@ASCIItoBCDConversion: ; Символы числа должны быть цифрами cmp AL,'0' jb @@Error cmp AL,'9' ja @@Error ; Пишем очередную цифру в младшую тетраду BCD and AL,0Fh or [byte ptr Data_BCD],AL ; Проверка на конец строки cmp [byte ptr SI],0 je @@ASCIItoBCDConversionEnd ; Сдвигаем BCD на 4 разряда влево ; (сдвигаем старшие 2 байта) mov AX,[word ptr Data_BCD+6] shld [word ptr Data_BCD+8],AX,4 ; (сдвигаем средние 4 байта) mov EAX,[dword ptr Data_BCD] shld [dword ptr Data_BCD+4],EAX,4 ; (сдвигаем младшие 4 байта) shl [dword ptr Data_BCD],4 ; Загружаем следующий символ в AL lodsb loop @@ASCIItoBCDConversion cmp AL,0 jne @@Error ;переполнение разрядной сетки
; ПРЕОБРАЗОВАТЬ ЧИСЛО ИЗ КОДА BCD В ЦЕЛОЕ ЧИСЛО @@ASCIItoBCDConversionEnd: ; Вписать знак в старший байт mov AL,[Data_Sign] mov [byte ptr Data_BCD+9],AL ; Сбросить регистры сопроцессора fninit ; Загрузить в сопроцессор число в BCD-формате fbld [Data_BCD] ; Выгрузить число в двоичном формате fistp [Data_Int32] jmp short @@End
@@Error:; При любой ошибке обнулить результат mov [Data_Int32],0 @@End: pop DS popad ret ENDP String_to_Int32
;******************************************************* ;* ВЫВОД БАЙТА НА ЭКРАН В ДЕСЯТИЧНОМ КОДЕ * ;* Подпрограмма выводит содержимое регистра AL в * ;* шестнадцатеричном коде в указанную позицию экрана. * ;* Координаты позиции передаются через глобальные * ;* переменные ScreenString и ScreenColumn. После * ;* выполнения операции вывода байта происходит * ;* автоматическое приращение значений этих переменных. * ;******************************************************* PROC ShowDecByte NEAR push EAX and EAX,0FFh call ShowDecDWord pop EAX ret ENDP ShowDecByte
;***************************************************** ;* ВЫВОД 16-РАЗРЯДНОГО СЛОВА НА ЭКРАН * ;* В ДЕСЯТИЧНОМ КОДЕ * ;* Параметры: * ;* AX - число, которое будет выведено на экран. * ;* Номер строки передается через глобальную * ;* переменную ScreenString, номер столбца - через * ;* переменную ScreenColumn, цвет текста определяется * ;* глобальной переменой TextColorAndBackground. * ;***************************************************** PROC ShowDecWord NEAR push EAX and EAX,0FFFFh call ShowDecDWord pop EAX ret ENDP ShowDecWord
;***************************************************** ;* ВЫВОД 32-РАЗРЯДНОГО СЛОВА НА ЭКРАН * ;* В ДЕСЯТИЧНОМ КОДЕ * ;* Параметры: * ;* EAX - число, которое будет выведено на экран. * ;* Номер строки передается через глобальную * ;* переменную ScreenString, номер столбца - через * ;* переменную ScreenColumn, цвет текста определяется * ;* глобальной переменой TextColorAndBackground. * ;***************************************************** PROC ShowDecDWord NEAR pushad push DS push ES ; Настроить регистр DS на глобальный сегмент данных mov DI,[CS:MainDataSeg] mov DS,DI ; Перевести число в десятичный код mov [Data_Int32],EAX call Int32_to_String ; Настроить регистры ES:DI для ; прямого вывода в видеопамять ; Загрузить адрес сегмента видеоданных в ES mov AX,0B800h mov ES,AX ; Умножить номер строки на длину ; строки в байтах mov AX,[ScreenString] mov DX,160 mul DX ; Прибавить к полученному произведению номер ; колонки (дважды) add AX,[ScreenColumn] add AX,[ScreenColumn] ; Переписать результат в индексный регистр mov DI,AX cld ; Использовать цвет символов, заданный по умолчанию mov AH,[TextColorAndBackground] ; Вывести число на экран mov CX,10 mov SI,offset Data_String @@NextChar: lodsb ;загрузить цифру в AL and AL,AL ;проверка на 0 (конец строки) jz @@EndOfString stosw ;вывести цифру на экран loop @@NextChar @@EndOfString: pop ES pop DS popad ret ENDP ShowDecDWord
;******************************************************* ;* ПРЕОБРАЗОВАНИЕ ЧИСЛА С ПЛАВАЮЩЕЙ ЗАПЯТОЙ В СТРОКУ * ;* Число имеет формат с удвоенной точностью, результат * ;* выдается в десятичном коде, в "бытовом" формате с * ;* фиксированным количеством знаков после запятой. * ;* Входные параметры: * ;* Data_Double - преобразуемое число; * ;* NumberSymbolsAD - количество знаков после * ;* запятой (0-17). * ;* Выходные параметры: * ;* Data_String - строка-результат. * ;******************************************************* PROC DoubleFloat_to_String near pushad push DS push ES mov AX,[CS:MainDataSeg] mov DS,AX mov ES,AX ; Результат записывать в строку Data_String mov DI,offset Data_String
; Сдвигаем число влево на NumberSymbolsAD ; десятичных разрядов fninit ;сброс сопроцессора fld [Data_Double] ;загрузить число mov BX,[NumberSymbolsAD] cmp BX,0 je @@NoShifts ;нет цифр после запятой jl @@Error ;ошибка dec BX shl BX,3 ;умножаем на 8 add BX,offset MConst fmul [qword ptr BX] ;умножить на константу @@NoShifts: ; Извлечь число в коде BCD fbstp [Data_BCD] ; Проверить результат на переполнение mov AX,[offset Data_BCD + 8] cmp AX,0FFFFh ;"десятичное" переполнение? je @@Overflow ; Выделить знак числа и записать его в ASCII-коде mov AL,[offset Data_BCD + 9] and AL,AL jz @@NoSign mov AL,'-' stosb @@NoSign: ; Распаковать число в код ASCII mov BX,8 ;смещение последней пары цифр mov CX,9 ;счетчик пар цифр ; Определить позицию десятичной точки в числе mov DX,18 sub DX,[NumberSymbolsAD] js @@Error ;ошибка, если отрицательная jz @@Error ;или нулевая позиция @@NextPair: ; Загрузить очередную пару разрядов mov AL,[BX + offset Data_BCD] mov AH,AL ; Выделить, перевести в ASCII и ; сохранить старшую тетраду shr AL,4 add AL,'0' stosb dec DX jnz @@N0 mov AL,'.' stosb @@N0: ; Выделить, перевести в ASCII и ; сохранить младшую тетраду mov AL,AH and AL,0Fh add AL,'0' stosb dec DX jnz @@N1 mov AL,'.' stosb @@N1: dec BX loop @@NextPair mov AL,0 stosb
; Убрать незначащие нули слева mov DI,offset Data_String mov SI,offset Data_String ; Пропустить знак числа, если он есть cmp [byte ptr SI],'-' jne @@N2 inc SI inc DI @@N2: ; Загрузить в счетчик цикла количество разрядов ; числа плюс 1 (байт десятичной точки) mov CX,18+1+1 ; Пропустить незначащие нули @@N3: cmp [byte ptr SI],'0' jne @@N4 cmp [byte ptr SI+1],'.' je @@N4 inc SI loop @@N3 ; Ошибка - нет значащих цифр jmp short @@Error ; Скопировать значащую часть числа в начало строки @@N4: rep movsb jmp short @@End
; Ошибка @@Error: mov AL,'E' stosb mov AL,'R' stosb mov AL,'R' stosb xor AL,AL stosb jmp short @@End ; Переполнение разрядной сетки @@Overflow: mov AL,'#' stosb xor AL,AL stosb ; Конец процедуры @@End: pop ES pop DS popad ret ENDP DoubleFloat_to_String
;******************************************************* ;* ПРЕОБРАЗОВАТЬ ЧИСЛО С ПЛАВАЮЩЕЙ ЗАПЯТОЙ В СТРОКУ * ;* Число имеет формат с удвоенной точностью, результат * ;* выдается в десятичном коде в научном формате, т.е. * ;* с нормализованной мантиссой и порядком. * ;* Входные параметры: * ;* Data_Double - преобразуемое число; * ;* MaxPositions - количество разрядов мантиссы (1-18). * ;* Выходные параметры: * ;* Data_String - строка-результат. * ;******************************************************* PROC DoubleFloat_to_ExpForm near pushad push DS push ES mov AX,[CS:MainDataSeg] mov DS,AX mov ES,AX ; Результат записывать в строку Data_String mov DI,offset Data_String ; Определить знак числа fninit ;сброс сопроцессора fld [Data_Double] ;загрузить число fxam ;протестировать число fstsw AX test ah,10b ;проверить знак jz @@z0 ; Число отрицательное mov AL,'-' ;записать знак "минус" stosb ; Запомнить модуль числа fabs @@z0: fst [Data_Abs] ; Произвести проверку на "машинный ноль" fcom [Data_Minimum] fstsw AX and AH,1000001b jnz @@Zero
; Устанавить режим округления "вниз" (01) fstcw [Data_Control] ;считать слово состояния and [Data_Control],0F7FFh or [Data_Control],0400h fldcw [Data_Control]
; Вычислить десятичный логарифм числа fldlg2 fxch ST(1) fyl2x ; Записать десятичный порядок fistp [Data_Log10]
; Устанавить режим округления "к ближайшему" (00) fstcw [Data_Control] ;считать слово состояния and [Data_Control],0F3FFh fldcw [Data_Control]
; Нормализовать десятичную мантиссу fninit ;сброс сопроцессора fld [Data_Abs] ;загрузить модуль числа mov BX,[MaxPositions] sub BX,[Data_Log10] cmp BX,0 je @@z2 ;сдвиги не нужны jl @@z1 ;нужен сдвиг вправо ; Сдвинуть число влево ; на [BX] десятичных разрядов dec BX cmp BX,127 ja @@Zero ;машинный ноль shl BX,3 ;умножаем на 8 add BX,offset MConst fmul [qword ptr BX] ;умножить на константу jmp short @@z2 ; Сдвинуть число вправо ; на [BX] десятичных разрядов @@z1: neg BX dec BX cmp BX,127 ja @@Overflow ;переполнение shl BX,3 ;умножаем на 8 add BX,offset MConst fdiv [qword ptr BX] ;разделить на константу @@z2: fbstp [Data_BCD] ;извлечь число в коде BCD
; Записать точку перед мантиссой mov SI,DI ;запомнить позицию точки mov AL,'.' stosb ; Преобразовать мантиссу в код ASCII call BCD_to_ASCII ; Помнять местами точку и первую цифру мантиссы mov AX,[SI] xchg AL,AH mov [SI],AX
; Перевести порядок результата в код BCD ; Проверить значение порядка cmp [Data_Log10],0 je @@End ; Записать признак порядка mov AL,'e' stosb fninit ;сброс сопроцессора ; Загрузить десятичный порядок в двоичном коде fild [Data_Log10] ; Извлечь порядок в коде BCD fbstp [Data_BCD] ; Результат записать в строку Data_String call BCD_to_ASCII jmp short @@End
@@Zero: ; Машинный ноль mov AL,'0' stosb jmp short @@End @@Overflow: ; Переполнение разрядной сетки mov AL,'#' stosb @@End: ; Записать признак конца строки (код 0) xor AL,AL stosb
pop ES pop DS popad ret ENDP DoubleFloat_to_ExpForm
;**************************************************** ;* ПРЕОБРАЗОВАТЬ СТРОКУ В ЧИСЛО С ПЛАВАЮЩЕЙ ЗАПЯТОЙ * ;* (число имеет обычный, "бытовой" формат) * ;* Входные параметры: * ;* Data_String - число в коде ASCII. * ;* Выходные параметры: * ;* Data_Double - число в двоичном коде. * ;**************************************************** PROC String_to_DoubleFloat near pushad push DS mov AX,[CS:MainDataSeg] mov DS,AX cld ; Очищаем Data_BCD mov [dword ptr Data_BCD],0 mov [dword ptr Data_BCD+4],0 mov [word ptr Data_BCD+8],0 ; Очищаем байт знака mov [Data_Sign],0 ; Заносим в SI указатель на строку mov SI,offset Data_String ; Пропускаем пробелы перед числом mov CX,64 ;защита от зацикливания @@ShiftIgnore: lodsb cmp AL,' ' jne @@ShiftIgnoreEnd loop @@ShiftIgnore jmp @@Error @@ShiftIgnoreEnd: ; Проверяем знак числа cmp AL,'-' jne @@Positive mov [Data_Sign],80h lodsb @@Positive: mov [Data_Flag],0 ;признак наличия точки mov DX,0 ;позиция точки mov CX,18 ;макс. число разрядов @@ASCIItoBCDConversion: cmp AL,'.' ;точка? jne @@NotDot cmp [Data_Flag],0 ;точка не встречалась? jne @@Error mov [Data_Flag],1 lodsb cmp AL,0 ;конец строки? jne @@NotDot jmp @@ASCIItoBCDConversionEnd @@NotDot: ; Увеличить на 1 значение позиции точки, ; если она еще не встречалась cmp [Data_Flag],0 jnz @@Figures inc DX @@Figures: ; Символы числа должны быть цифрами cmp AL,'0' jb @@Error cmp AL,'9' ja @@Error ; Пишем очередную цифру в младшую тетраду BCD and AL,0Fh or [byte ptr Data_BCD],AL ; Проверка на конец строки cmp [byte ptr SI],0 je @@ASCIItoBCDConversionEnd ; Сдвигаем BCD на 4 разряда влево ; (сдвигаем старшие 2 байта) mov AX,[word ptr Data_BCD+6] shld [word ptr Data_BCD+8],AX,4 ; (сдвигаем средние 4 байта) mov EAX,[dword ptr Data_BCD] shld [dword ptr Data_BCD+4],EAX,4 ; (сдвигаем младшие 4 байта) shl [dword ptr Data_BCD],4 ; Загружаем следующий символ в AL lodsb loop @@ASCIItoBCDConversion ; Если 19-й символ не 0 и не точка, ; то ошибка переполнения cmp AL,'.' jne @@NotDot2 inc CX lodsb @@NotDot2: cmp AL,0 jne @@Error ;переполнение разрядной сетки
; ПРЕОБРАЗОВАТЬ ЧИСЛО ИЗ КОДА BCD В ВЕЩЕСТВЕННОЕ ЧИСЛО @@ASCIItoBCDConversionEnd: ; Вписать знак в старший байт mov AL,[Data_Sign] mov [byte ptr Data_BCD+9],AL ; Сбросить регистры сопроцессора fninit ; Загрузить в сопроцессор число в BCD-формате fbld [Data_BCD] ; Вычислить номер делителя mov BX,18+1 sub BX,CX sub BX,DX cmp BX,0 je @@NoDiv dec BX shl BX,3 ;умножаем на 8 add BX,offset MConst fdiv [qword ptr BX] ;разделить на константу @@NoDiv:; Выгрузить число в двоичном формате fstp [Data_Double] jmp short @@End
@@Error:; При любой ошибке обнулить результат fldz ;занести ноль с стек сопроцессора fstp [Data_Double] @@End: pop DS popad ret ENDP String_to_DoubleFloat
|
продолжение следует
--------------------
Как бы ты не старался быть хорошим и правильным человеком с принципами и уважительным отношением к другим, всегда найдется кто-то, кто бросит в тебя какашку
|