; math_tan_cot.asm
;
; Assembly language source for the tangent 
; and cotangent functions:


            include math.inc
            include aoalib.inc
            
; tan-                                                          
;                                                               
; Computes tan(st0) by using the fsincos instruction.           
;                                                               
; The x87 fsincos instruction requires the operand to be in the 
; range -2**63..2**63. If it is outside this range, the sincos  
; instruction leaves ST0 unchanged and sets the C2 flag in the  
; FP status register. This function will handle the case of     
; st0 being outside this range (it will compute the remainder   
; of st0 divided by 2pi prior to computing fsincos).            


            .code
math_tan    proc
            push    rax

                    
; Because the vast majority of the time, tan(x)
; is invoked for small values (e.g., less than 360 degrees),
; we'll just execute fptan and adjust things if fptan
; fails.
            
            fptan
            fstsw   ax
            test    ah, 100b
            jz      goodTan
                    
; fptan failed. We need to reduce the value
; to a range smaller than _/+2**63. We'll
; put it in the range -2pi..+2pi.
;
; Get the value into the range -2pi..2pi:

            fldpi           ; Compute 2pi (the divisor)
            fldpi
            faddp
            fld     st(1)
mod2pi:
            fprem1
            fstsw   ax      ; Determine if we are done (c2=0)
            and     ah, 100b
            jnz     mod2pi
            
            fstp    st(2)
            fstp    st(0)                   

; Okay, now that we've got it in range,
; recompute the sincos value.
             
            fptan                   
            
goodTan:
            fstp    st(0)   ; Remove the 1.0 pushed on the stack.
            pop     rax
            ret
math_tan    endp


; The cotangent is just 1/tan.

math_cot    proc
            call    math_tan
            fld1
            fdivrp
            ret
math_cot    endp
            end