;
;=============================================================
; Р Е А Л И З А Ц И Я
;
#.MODEL SMALL
;
#.CODE
;
;*************************************************************
; DEC2FLT - Преобразует целое десятичное с экспонентой в
; вещественное число с плавающей запятой. Записывает
; экспоненту и указатель в строку упакованного BCD в
; стеке. Возвращает результат в ST(0).
;
; Использовать: push offset (tbyte ptr packed_BCD)
; push exponent
; call dec2flt
;
; Требования: 3 ячейки стека
; Обозначения: N ..... экспонента для 10**N
; S ..... мантисса вещественного числа
;-------------------------------------------------------------
;
#.DATA
D2FLTD STRUCT
d2fltbp dw ? ; прежний базовый указатель
dw ? ; возвратить адрес
d2fltex dw ? ; экспонента
d2fltpd dw ? ; указатель для упакованного BCD
D2FLTD ENDS
;
#.CODE
dec2flt PROC NEAR
push bp
mov bp,sp ; параметры адреса
cmp word ptr [bp].d2fltex,0 ; проверить знак
; ... экспоненты
jz d2flt_npx ; если ноль, то 10**N
; ... не нужно
pushf ; сохранить знак экспоненты
jg d2flt_pos ; если положительное,
; ... начать 10**N
neg word ptr [bp].d2fltex ; в противном случае
; ... сделать экспоненту положительной
d2flt_pos:
FILD word ptr [bp].d2fltex ; получить экспоненту 10
call exp10 ; вычислить 10**N
d2flt_npx: ; войти сюда, если экспонента 0
push si
mov si,[bp].d2fltpd ; получить указатель
; ... упакованного BCD
FBLD tbyte ptr [si] ; ST => S; ST(1) = 10**N
pop si
- 10-40 -
popf ; восстановить знак экспоненты
jz d2flt_end ; выполнено, если экспонента 0
jl d2flt_neg ; если отрицательная, разделить
FMUL ; ST => мантисса * 10**N
jmp d2flt_end ; и выполнено
d2flt_neg:
FDIVR ; ST => мантисса / 10**N
d2flt_end:
pop bp ; восстановить bp
ret 4
dec2flt ENDP
;
;*************************************************************
; FLT2DEC - Преобразует вещественное число с плавающей запятой
; в целое с экспонентой. ST(0) содержит преобразуемое
: число. Стек содержит количество требуемых двоичных
; цифр и указатель расположения экспоненты 10.
; Результат возвращается ST(0), преобразованный в целое,
; и пишет экспоненту в указанном месте.
;
; Использовать: push sig_digits
; push offset (word ptr to exponent)
; call flt2dec
;
; Требования: 4 ячейки стека
; Обозначения: R ..... Отображаемое вещественное число
; N ..... Экспонента 10 для перевода R в целое
; I ..... Целая часть результата
; n(N) .. Ближайшее к N целое
;-------------------------------------------------------------
;
#.DATA
F2DECD STRUC
f2deccw dw ? ; оригинальное слово управления
f2decbp dw ? ; прежний базовый указатель
dw ? ; адрес возврата
f2decex dw ? ; указатель экспоненты
f2decsd dw ? ; количество значащих двоичных цифр
F2DECD ENDS
;
#.CODE
;* проверить управление округлением сейчас - применить другой?
F2DECCT EQU 03BFh ; новое слово управления - округлить
; ... ближайшее
;
flt2dec PROC NEAR
;
; Установить слово управления NPX и открыть запись в стек:
push bp ; сохранить прежний базовый указатель
STKADJ1 EQU f2decbp-F2DECD
sub sp,STKADJ1 ; сделать запись в стеке
mov bp,sp ; адрес новой структуры
push ax ; сохранить AX
mov ax,F2DECCT ; поместить новое слово управления
; ... в стек
push ax
FSTCW word ptr [bp].f2deccw
- 10-41 -
FLDCW word ptr [bp-4] ; установить округление к
; ... ближайшему целому
pop ax ; очистить стек
pop ax ; восстановить AX
;
; Найти N для 10**N в целях преобразования в целое:
FLD ST(0) ; продублировать R (сохранить до конца)
FXTRACT ; ST(1) => экспоненциальная часть R
FSTP ST(0) ; ST => экспоненциальная часть R
FISUBR word ptr [bp].f2decsd ; значащие ...
; ... цифры - экспонента = # цифр масштаба
FLDL2T ; ST => log2 (10), ST(1) => масштаб
FDIV ; ST => масштаб / log2 (10) = N
FRNDINT ; ST => n(N)
;
; Сохранить nint(N) как экспоненту и вычислить 10**nint(N)
push si
mov si,[bp],f2decex ; получить указатель экспоненты
FIST word ptr [si] ; сохранить масштаб основания 10
FWAIT
neg word ptr [si] ; указание двигать десятичную
; ... запятую
pop si
call exp10 ; вычислить 10**N (масштаб)
;
; В ST(1) теперь находится R (первоначальное вещественное
; число) - масштабировать его:
FMUL ; ST => R * 10**N = целое
FLDCW word ptr [bp].f2deccw ; восстановить слово
; ... управления
STKADJ2 EQU f2decbp-F2DECD
add sp,STKADJ2 ; восстановить первоначальный стек
pop bp ; восстановить базовый указатель
ret 4 ; очистить стек для возврата
flt2dec ENDP
;
;*************************************************************
; EXP10 - Возводит число 10 в степень ST(0).
; Возвращает результат в ST(0).
;
; Использует формулу: 10**N = 2**(N*log2(10))
;
; ВЫЗЫВАЕТ: EXP2
;
; Требования: 3 ячейки стека
; Обозначения: N ...... экспонента для 10**N
; X ...... эквивалентная экспонента для 2**X
; n(x) ... ближайшее к Х целое
; f(x) ... дробная часть Х
;-------------------------------------------------------------
exp10 PROC NEAR
FLDL2T ; ST > log2 (10); ST(1) => N
FMUL ; ST => N * log2 (10) => X
call exp2 ; возвести 2 в степень ST
ret ; ... для 10**N
exp10 ENDP
;
- 10-42 -
;*************************************************************
; EXPE - Возводит число E в степень ST(0).
; Возвращает результат в ST(0).
;
; Использует формулу: E**N = 2**(N*log2(E))
;
; ВЫЗЫВАЕТ: EXP2
;
; Требования: 3 ячейки стека
; Обозначения: N ...... экспонента для E**N
; X ...... эквивалентная экспонента для 2**X
; n(x) ... ближайшее к Х целое
; f(x) ... дробная часть Х
;-------------------------------------------------------------
expE PROC NEAR
FLDL2E ; ST > log2 (e); ST(1) => N
FMUL ; ST => N * log2 (e) => X
call exp2 ; возвести 2 в степень ST
ret ; ... для E ** N
expE ENDP
;
;*************************************************************
; EXPY - Возводит Y [ST(0)] в степень N [ST(1)]
; Возвращает результат в ST(0)
; ST(1) (значение N) теряется!
;
; Использует формулу: Y**N = 2**(N*log2(Y))
;
; **** ПРИМЕЧАНИЕ: Y ДОЛЖНО БЫТЬ ПОЛОЖИТЕЛЬНОЕ ****
;
; ВЫЗЫВАЕТ: EXP2
;
; Требования: 3 ячейки стека
; Обозначения: N ...... экспонента для Y**N
; X ...... эквивалентная экспонента для 2**Y
; n(x) ... ближайшее к Х целое
; f(x) ... дробная часть Х
;-------------------------------------------------------------
expY PROC NEAR
FYL2X ; ST => N * log2 (Y); (Y) => X
call exp2 ; возвести 2 в степень ST
ret ; ... для Y ** N
expY ENDP
;
;*************************************************************
; EXP2 - Возводит число 2 в степень ST(0).
; Возвращает результат в ST(0).
;
; Требования: 3 ячейки стека
; Обозначения: X ...... экспонента для 2**X
; n(x) ... ближайшее к Х целое
; f(x) ... дробная часть Х
;-------------------------------------------------------------
;
#.DATA
EXP2D STRIC
exp2cc dw ? ; коды условий
- 10-43 -
exp2cw dw ? ; оригинальное слово управления
exp2bp dw ? ; прежний базовый указатель
dw ? ; адрес возврата
EXP2D ENDS
;
#.CODE
EXP2CT EQU 03BFh ; новое слово управления - округлять к
; ... ближайшему
exp2 PROC NEAR
;
; Установить слово управления NPX и открыть запись в стек:
push bp ; сохранить прежний базовый указатель
STKADJ3 EQU exp2bp-EXP2D
sub sp,STKADJ3 ; сделать запись в стеке
mov bp,sp ; адрес новой структуры
push ax ; сохранить AX
mov ax,EXP2CT ; поместить новое слово управления
; ... в стек