home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pcmagazi
/
1990
/
05
/
pp905
/
ftrig.asm
< prev
next >
Wrap
Assembly Source File
|
1989-10-26
|
11KB
|
294 lines
title FTRIG.ASM 80x87 Sine, Cosine, Tangent
page 55,132
; FTRIG.ASM --- 80x87 Sine, Cosine, Tangent Functions
;
; Copyright (C) 1989 Ziff Davis Communications
; PC Magazine * Ray Duncan
;
; Procedure FSIN calculates sine(x)
; Procedure FCOS calculates cosine(x)
; Procedure FTAN calculates tangent(x)
;
; All three procedures have the same calling sequence:
;
; Call with: ST(0) = argument in radians
;
; Returns: ST(0) = result
;
; Uses: AX, BX. Other registers preserved.
;
; Make sure coprocessor has been properly initialized
; with a previous call to INIT87!
_DATA segment word public 'DATA'
piby2 dq 3ff921fb54442d18h ; constant pi / 2
piby4 dq 3fe921fb54442d18h ; constant pi / 4
plusinf dd 07f800000h ; +infinity encoding
neginf dd 0ff800000h ; -infinity encoding
oldcw dw 0 ; old control word
newcw dw 0 ; new control word
temp dw 0 ; scratch storage
cctab db 0,4,1,5,2,6,3,7 ; relates condition code
; bits to octant numbers
fsintab label word ; sine dispatch table
dw fsin0 ; octant 0
dw fsin1 ; octant 1
dw fsin2 ; octant 2
dw fsin3 ; octant 3
dw fsin4 ; octant 4
dw fsin5 ; octant 5
dw fsin6 ; octant 6
dw fsin7 ; octant 7
ftantab label word ; tangent dispatch table
; for reduced angle <> 0
dw ftan0 ; octant 0
dw ftan1 ; octant 1
dw ftan2 ; octant 2
dw ftan3 ; octant 3
dw ftan4 ; octant 4
dw ftan5 ; octant 5
dw ftan6 ; octant 6
dw ftan7 ; octant 7
ftanztab label word ; tangent dispatch table
; for reduced angle = 0
dw ftanz0 ; octant 0
dw ftanz1 ; octant 1
dw ftanz2 ; octant 2
dw ftanz3 ; octant 3
dw ftanz4 ; octant 4
dw ftanz5 ; octant 5
dw ftanz6 ; octant 6
dw ftanz7 ; octant 7
_DATA ends
_TEXT segment word public 'CODE'
assume cs:_TEXT,ds:_DATA
public fsin
fsin proc near ; calculate sine of ST(0)
call octant ; reduce angle, find octant
shl bx,1 ; form index to jump table
jmp [bx+fsintab] ; branch to correct sequence
fsin0: call psin ; octant 0
ret ; sin(x) = psin(x)
fsin1: fsubr piby4 ; octant 1
call pcos ; sin(x) = pcos((pi/4)-x)
ret
fsin2: call pcos ; octant 2
ret ; sin(x) = pcos(x)
fsin3: fsubr piby4 ; octant 3
call psin ; sin(x) = psin((pi/4)-x)
ret
fsin4: call psin ; octant 4
fchs ; sin(x) = -(psin(x))
ret
fsin5: fsubr piby4 ; octant 5
call pcos ; sin(x) = -(pcos((pi/4)-x)
fchs
ret
fsin6: call pcos ; octant 6
fchs ; sin(x) = -(pcos(x))
ret
fsin7: fsubr piby4 ; octant 7
call psin ; sin(x) = -(psin((pi/4)-x))
fchs
ret
fsin endp
public fcos
fcos proc near ; calculate cosine of ST(0)
call octant ; reduce angle, find octant
add bx,2 ; add pi/2 (90 degrees) and
and bx,7 ; then use sine routines
shl bx,1 ; form index to jump table
jmp [bx+fsintab] ; branch to correct sequence
fcos endp
public ftan
ftan proc near ; calculate tangent of ST(0)
call octant ; reduce angle, find octant
shl bx,1 ; form index for jump table
ftst ; is reduced angle = 0?
fstsw temp
fwait
mov ax,temp
sahf
je ftanz ; reduced angle = 0
jmp [bx+ftantab] ; reduced angle <> 0
ftan0: ; octant 0
ftan4: ; octant 4
fptan ; get Y/X
fdivp st(1),st(0)
ret
ftan1: ; octant 1
ftan5: ; octant 5
fsubr piby4 ; (pi/4) - angle
fptan ; get (Y/X)
fdivp st(1),st(0) ; 1/(Y/X)
fld1
fdivrp st(1),st(0)
ret
ftan2: ; octant 2
ftan6: ; octant 6
fptan ; get Y/X
fdivp st(1),st(0)
fld1 ; -(1/(Y/X))
fdivrp st(1),st(0)
fchs
ret
ftan3: ; octant 3
ftan7: ; octant 7
fsubr piby4 ; (pi/4) - angle
fptan ; get Y/X
fdivp st(1),st(0) ; -(Y/X)
fchs
ret
ftanz: ; reduced angle = 0
fstp st(0) ; discard angle and
jmp [bx+ftanztab] ; go load special value
ftanz0: fldz ; 0 degrees
ret ; load constant 0
ftanz1: fld1 ; 45 degrees
ret ; load constant 1
ftanz2: fld plusinf ; 90 degrees
ret ; load constant +infinity
ftanz3: fld1 ; 135 degrees
fchs ; load constant -1
ret
ftanz4: fldz ; 180 degrees
ret ; load constant 0
ftanz5: fld1 ; 225 degrees
ret ; load constant 1
ftanz6: fld neginf ; 270 degrees
ret ; load constant -infinity
ftanz7: fld1 ; 315 degrees
fchs ; load constant -1
ret
ftan endp
;
; PSIN: Partial sine
; Call with: ST(0) = angle in range 0 <= x < pi/4
; Returns: ST(0) = sine
;
psin proc near
fptan ; get fraction Y/X
fld st(1) ; sin = Y/sqrt(X*X+Y*Y)
fmul st(0),st(0)
fxch st(1)
fmul st(0),st(0)
faddp st(1),st(0)
fsqrt
fdivp st(1),st(0)
ret ; leave divide running
psin endp
;
; PCOS: Partial cosine
; Call with: ST(0) = angle in range 0 <= x < pi/4
; Returns: ST(0) = cosine
;
pcos proc near
fptan ; get fraction Y/X
fxch st(1) ; cos = X/sqrt(X*X+Y*Y)
fld st(1)
fmul st(0),st(0)
fxch st(1)
fmul st(0),st(0)
faddp st(1),st(0)
fsqrt
fdivp st(1),st(0)
ret ; leave divide running
pcos endp
;
; OCTANT: Find octant occupied by angle.
; Call with: ST(0) = angle in radians
; Returns: ST(0) = reduced angle, 0 <= angle < pi/4
; BX = octant(0-7)
;
octant proc near
push ax ; save register
ftst ; test sign of angle
fstsw temp ; unload FTST status
fabs ; force angle positive
push temp ; save FTST status
fld piby4 ; load constant pi/4
fxch st(1) ; put angle on top
fprem ; reduce to 0<=angle<pi/4
fstsw temp ; unload FPREM status
fwait ; wait till it arrives
mov bx,temp ; retrieve status word
and bx,4300h ; shift C3, C1, C0 status
rol bx,1 ; bits (which contain
rol bx,1 ; low 3 bits of quotient
shl bh,1 ; from FPREM) to form
shl bh,1 ; index in range 0-7,
shl bh,1 ; then look up octant
shl bh,1
rol bx,1
rol bx,1
mov bl,[bx+cctab] ; now BX = actual octant
pop ax ; get back FTST status
sahf ; force CPU flags
jae oct1 ; jump, orig. angle >= 0
fsubr st(0),st(1) ; angle was negative,
sub bx,7 ; adjust reduced angle
neg bx ; and octant
oct1: fstp st(1) ; discard pi/4 constant
pop ax ; restore register, return
ret ; BX=octant, ST(0)=angle
octant endp
_TEXT ends
end