📄 fp.asm
字号:
dw -256
;
dw 0e4a1h, 64bch, 467ch, 0ddd0h, 7e55h ; 1e-128
db 0
dw -128
;
dw 0e9a5h, 0a539h, 0ea27h, 0a87fh, 7f2ah ; 1e-64
db 0
dw -64
;
dw 94bah, 4539h, 1eadh, 0cfb1h, 7f94h ; 1e-32
db 0
dw -32
;
dw 0e15bh, 0c44dh, 94beh, 0e695h, 7fc9h ; 1e-16
db 0
dw -16
;
dw 0cefdh, 8461h, 7711h, 0abcch, 7fe4h ; 1e-8
db 0
dw -8
;
dw 652ch, 0e219h, 1758h, 0d1b7h, 7ff1h ; 1e-4
db 0
dw -4
;
dw 0d70ah, 70a3h, 0a3dh, 0a3d7h, 7ff8h ; 1e-2
db 0
dw -2
;
Div10Value dw 0cccdh, 0cccch, 0cccch, 0cccch, 7ffbh ; 1e-1
db 0
dw -1
;
dw 0, 0, 0, 8000h, 7fffh ; 1e0
db 0
dw 0
;
;
; PotTblP- Power of ten table. Holds powers of ten raised to positive
; powers of two;
;
; i.e., x(12-n) = 10 ** (2 ** n) for 0 <= n <= 12.
; x(13) = 1.0
; x(-1) = 10 ** (2 ** -4096)
;
; There is a -1 entry since it is possible for the algorithm to back up
; before the table.
;
dw 979bh, 8a20h, 5202h, 0c460h, 0b525h ; 1e+4096
db 0
dw 4096
;
PotTblP dw 979bh, 8a20h, 5202h, 0c460h, 0b525h ; 1e+4096
db 0
dw 4096
;
dw 5de5h, 0c53dh, 3b5dh, 9e8bh, 09a92h ; 1e+2048
db 0
dw 2048
;
dw 0c17h, 8175h, 7586h, 0c976h, 08d48h ; 1e+1024
db 0
dw 1024
;
dw 91c7h, 0a60eh, 0a0aeh, 0e319h, 086a3h ; 1e+512
db 0
dw 512
;
dw 0de8eh, 9df9h, 0ebfbh, 0aa7eh, 08351h ; 1e+256
db 0
dw 256
;
dw 8ce0h, 80e9h, 47c9h, 93bah, 081a8h ; 1e+128
db 0
dw 128
;
dw 0a6d5h, 0ffcfh, 1f49h, 0c278h, 080d3h ; 1e+64
db 0
dw 64
;
dw 0b59eh, 2b70h, 0ada8h, 9dc5h, 08069h ; 1e+32
db 0
dw 32
;
dw 0, 400h, 0c9bfh, 8e1bh, 08034h ; 1e+16
db 0
dw 16
;
dw 0, 0, 2000h, 0bebch, 08019h ; 1e+8
db 0
dw 8
;
dw 0, 0, 0, 9c40h, 0800ch ; 1e+4
db 0
dw 4
;
dw 0, 0, 0, 0c800h, 08005h ; 1e+2
db 0
dw 2
;
dw 0, 0, 0, 0a000h, 08002h ; 1e+1
db 0
dw 1
;
dw 0, 0, 0, 8000h, 7fffh ; 1e0
db 0
dw 0
;
;
;
;
;
;
;
; SL_FTOA- Converts extended precision value in FPACC to a decimal
; string. AL contains the field width, AH contains the
; number of positions after the decimal point. The format
; of the converted string is:
;
; sd.e
;
; where "s" is a single character which is either a space
; or "=", "e" is some number of digits which is equal to
; the value passed in AL, and "d" is the number of digits
; given by (AL-AH-2). If the field width is too small,
; this routine creates a string of "#" characters AH long.
;
; ES:DI contains the address where we're supposed to put
; the resulting string. This code assumes that there is
; sufficient memory to hold (AL+1) characters at this address.
;
;
;
public sl_ftoa
sl_ftoa proc far
push di
call far ptr sl_ftoa2
pop di
ret
sl_ftoa endp
;
public sl_ftoa2
sl_ftoa2 proc far
assume ds:StdGrp
;
pushf
push ds
push ax
push bx
push cx
push dx
push si
;
cld
mov bx, StdGrp
mov ds, bx
;
; Save fpacc 'cause it gets munged.
;
push fpacc.Mantissa [0]
push fpacc.Mantissa [2]
push fpacc.Mantissa [4]
push fpacc.Mantissa [6]
push fpacc.Exponent
push word ptr fpacc.Sign
;
mov cx, ax ;Save field width/dec pts here.
;
call fpdigits ;Convert fpacc to digit string.
;
; Round the string of digits to the number of significant digits we want to
; display for this number:
;
mov bx, DecExponent
cmp bx, 18
jb PosRS
xor bx, bx ;Force to zero if negative or too big.
;
PosRS: add bl, ch ;Compute position where we should start
adc bh, 0 ; the rounding.
inc bx ;Tweak next digit.
cmp bx, 18 ;Don't bother rounding if we have
jae RoundDone ; more than 18 digits here.
;
; Add 5 to the digit after the last digit we want to print. Then propogate
; any overflow through the remaining digits.
;
mov al, DecDigits [bx]
add al, 5
mov DecDigits [bx], al
cmp al, "9"
jbe RoundDone
sub DecDigits [bx], 10
RoundLoop: dec bx
js FirstDigit
inc DecDigits[bx]
cmp DecDigits[bx], "9"
jbe RoundDone
sub DecDigits[bx], 10
jmp RoundLoop
;
; If we hit the first digit in the string, we've got to shift all the
; characters down one position and put a "1" in the first character
; position.
;
FirstDigit: mov bx, DecExponent
cmp bx, 18
jb FDOkay
xor bx, bx
;
FDOkay: mov bl, ch
mov bh, 0
inc bx
FDLp: mov al, byte ptr DecDigits[bx-1]
mov DecDigits [bx], al
dec bx
jnz FDLp
mov DecDigits, "1"
inc DecExponent ;Cause we just added a digit.
;
RoundDone:
;
; See if we're dealing with values greater than one (abs) or between 0 & 1.
;
cmp DecExponent, 0 ;Handle positive/negative exponents
jge PositiveExp ; separately.
;
; Handle values between 0 & 1 here (negative powers of ten).
;
mov dl, ch ;Compute #'s width = DecPlaces+3
add dl, 3 ;Make room for "-0."
jc BadFieldWidth
cmp dl, 4
jae LengthOk
mov dl, 4 ;Minimum string is "-0.0"
LengthOK: mov al, ' '
PutSpcs2: cmp dl, cl
jae PS2Done
stosb
inc dl
jmp PutSpcs2
;
PS2Done: mov al, DecSign
stosb
mov al, "0" ;Output "0." before the number.
stosb
mov al, "."
stosb
mov ah, 0 ;Used to count output digits
lea bx, stdGrp:DecDigits ;Pointer to number string.
PutDigits2: inc DecExponent
jns PutTheDigit
;
; If the exponent value is still negative, output zeros because we've yet
; to reach the beginning of the number.
;
PutZero2: mov al, '0'
stosb
jmp TestDone2
;
PutTheDigit: cmp ah, 18 ;If more than 18 digits so far, just
jae PutZero2 ; output zeros.
;
mov al, [bx]
inc bx
stosb
;
TestDone2: inc ah
dec ch
jnz PutDigits2
mov byte ptr es:[di], 0
jmp ftoaDone
;
;
; Okay, we've got a positive exponent here. First, let's adjust the field
; width value (in CH) so that it includes the sign and possible decimal point.
;
PositiveExp: mov dx, DecExponent ;Get actual # of digits to left of "."
inc dx ;Allow for sign and the fact that there
inc dx ; is always one digit to left of ".".
cmp ch, 0 ;# of chars after "." = 0?
je NoDecPt
add dl, ch ;Add in number of chars after "."
adc dh, 0
inc dx ;Make room for "."
NoDecPt:
;
;
; Make sure the field width is bigger than the number of decimal places to
; print.
;
cmp cl, ch
jb BadFieldWidth
;
;
; Okay, now see if the user is trying to print a value which is too large
; to fit in the given field width:
;
cmp dh, 0
jne BadFieldWidth ;Sorry, no output >= 256 chars.
cmp dl, cl ;Need field width > specified FW?
jbe GoodFieldWidth
;
; If we get down here, then we've got a number which will not fit in the
; specified field width. Fill the string with #'s (sorta like FORTRAN).
;
BadFieldWidth: mov ch, 0 ;Set CX=field width.
mov al, "#"
rep stosb
mov byte ptr es:[di], 0
jmp ftoaDone
;
;
; Print any necessary spaces in front of the number.
;
GoodFieldWidth: call PutSpaces
;
; Output the sign character (" " or "-"):
;
mov al, DecSign
stosb
;
; Okay, output the digits for this number here.
;
mov ah, 0 ;Counts off output characters.
lea bx, stdgrp:DecDigits ;Pointer to digit string.
mov cl, ch ;CX := # of chars after "."
mov ch, 0 ; plus number of characters before
add cx, DecExponent ; the ".".
inc cx ;Always at least one digit before "."
OutputLp: cmp ah, 18 ;Exceeded 18 digits?
jae PutZeros
mov al, [bx]
inc bx
jmp PutChar
;
PutZeros: mov al, '0'
PutChar: stosb
cmp DecExponent, 0
jne DontPutPoint
mov al, '.'
stosb
;
DontPutPoint: dec DecExponent
inc ah
loop OutputLp
mov byte ptr es:[di], 0 ;Output the zero byte.
;
ftoaDone: pop word ptr fpacc.Sign
pop fpacc.Exponent
pop fpacc.Mantissa [6]
pop fpacc.Mantissa [4]
pop fpacc.Mantissa [2]
pop fpacc.Mantissa [0]
pop si
pop dx
pop cx
pop bx
pop ax
pop ds
popf
ret
sl_ftoa2 endp
;
;
;
;
; Okay, now we need to insert any necessary leading spaces. We need to
; put (FieldWidth - ActualWidth) spaces before the string of digits.
;
PutSpaces proc near
cmp dl, cl ;See if print width >= field width
jae NoSpaces
mov ah, cl
sub ah, dl ;Compute # of spaces to print.
mov al, ' '
PSLp: stosb
dec ah
jnz PSLp
NoSpaces: ret
PutSpaces endp
;
;
;
;
;
;
;
;
;
;
;
;
;
;
; SL_ETOA- Converts value in FPACC to exponential form. AL contains
; the number of print positions. ES:DI points to the array
; which will hold this string (it must be at least AL+1 chars
; long).
;
; The output string takes the format:
;
; {" "|-} [0-9] "." [0-9]* "E" [+|-] [0-9]{2,4}
;
; (The term "[0-9]{2,4}" means either two or four digits)
;
; AL must be at least eight or this code outputs #s.
;
public sl_etoa
sl_etoa proc far
push di
call far ptr sl_etoa2
pop di
ret
sl_etoa endp
;
;
public sl_etoa2
sl_etoa2 proc far
assume ds:StdGrp
;
pushf
push ds
push ax
push bx
push cx
push si
;
cld
mov bx, StdGrp
mov ds, bx
;
push fpacc.Mantissa [0]
push fpacc.Mantissa [2]
push fpacc.Mantissa [4]
push fpacc.Mantissa [6]
push fpacc.Exponent
push word ptr fpacc.Sign
;
call fpdigits
;
; See if we have sufficient room for the number-
;
mov ah, 0
mov cx, ax
;
; Okay, take out spots for sign, ".", "E", sign, and at least four exponent
; digits and the exponent's sign:
;
Subtract2: sub ax, 8
jc BadEWidth
jnz DoTheRound ;Make sure at least 1 digit left!
;
BadEWidth: mov ch, 0
mov al, "#"
rep stosb
mov al, 0
stosb
jmp etoaDone
;
; Round the number to the specified number of places.
;
DoTheRound: mov ch, al ;# of decimal places is # of posns.
mov bl, ch ;Compute position where we should start
mov bh, 0 ; the rounding.
cmp bx, 18 ;Don't bother rounding if we have
jae eRoundDone ; more than 18 digits here.
;
; Add 5 to the digit after the last digit we want to print. Then propogate
; any overflow through the remaining digits.
;
mov al, DecDigits [bx]
add al, 5
mov DecDigits [bx], al
cmp al, "9"
jbe eRoundDone
sub DecDigits [bx], 10
eRoundLoop: dec bx
js eFirstDigit
inc DecDigits[bx]
cmp DecDigits[bx], "9"
jbe eRoundDone
sub DecDigits[bx], 10
jmp eRoundLoop
;
; If we hit the first digit in the string, we've got to shift all the
; characters down one position and put a "1" in the first character
; position.
;
eFirstDigit: mov bl, ch
mov bh, 0
inc bx
eFDLp: mov al, byte ptr DecDigits[bx-1]
mov DecDigits [bx], al
dec bx
jnz eFDLp
mov DecDigits, "1"
inc DecExponent ;Cause we just added a digit.
;
eRoundDone:
;
; Okay, output the value here.
;
mov cl, ch ;Set CX=Number of output chars
mov ch, 0
mov al, DecSign
stosb
lea si, stdgrp:DecDigits
movsb ;Output first char.
dec cx ;See if we're done!
jz PutExponent
;
; Output the fractional part here
;
mov al, "."
stosb
mov ah, 17 ;Max # of chars to output.
PutFractional: cmp ah, 0
jz NoMoreDigs
movsb
dec ah
jmp NextFraction
;
; If we've output more than 18 digits, just output zeros.
;
NoMoreDigs: mov al, "0"
stosb
;
NextFraction: loop PutFractional
PutExponent: mov al, "E"
stosb
mov al, "+"
cmp DecExponent, 0
jge NoNegExp
mov al, "-"
neg DecExponent
;
NoNegExp: stosb
mov ax, DecExponent
cwd ;Sets DX := 0.
mov cx, 1000
div cx
or al, "0"
stosb ;Output 1000's digit
xchg ax, dx
cwd
mov cx, 100
div cx
or al, "0" ;Output 100's digit
stosb
xchg ax, dx
cwd
mov cx, 10
div cx
or al, "0" ;Output 10's digit
stosb
xchg ax, dx
or al, "0" ;Output 1's digit
stosb
mov byte ptr es:[di], 0 ;Output zero byte.
;
etoaDone: pop word ptr fpacc.Sign
pop fpacc.Exponent
pop fpacc.Mantissa [6]
pop fpacc.Mantissa [4]
pop fpacc.Mantissa [2]
pop fpacc.Mantissa [0]
pop si
pop cx
pop bx
pop ax
pop ds
popf
ret
sl_etoa2 endp
;
;
;
;
;
; FPDigits- Converts the floating point number in FPACC to a string of
; digits (in DecDigits), an integer exponent value (DecExp),
; and a sign character (DecSign). The decimal point is assumed
; to be between the first and second characters in the string.
;
FPDigits proc near
assume ds:StdGrp
push ds
push ax
push bx
push cx
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -