; math_cos_csc.asm
;
; Assembly language source for the cosine 
; and cosecant functions:


            include math.inc
            include aoalib.inc
            
; cos-                                                         
;                                                              
; The x87 fcos instruction requires the operand to be in the   
; range -2**63..2**63. If it is outside this range, the cos    
; 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 fcos).              


            .code
math_cos    proc
            push    rax

; Because the vast majority of the time, cos
; is invoked for small values (e.g., less than 360 degrees),
; we'll just execute fcos and adjust things if fcos
; fails.

            fcos
            fstsw   ax
            test    ah, 100b
            jz      goodcos
                    
; fcos 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
            fldpi
            faddp
            fld     st(1)
mod2pi:
            fprem1
            fstsw   ax      ;We are done if (c2=0)
            and     ah, 100b
            jnz     mod2pi
            
            fstp    st(2)
            fstp    st(0)                   

; Okay, now that we've got it in range,
; recompute the cos value.
             
            fcos                    

goodcos:
            pop     rax
            ret
math_cos    endp


; The cosecant is just 1/cos.

math_csc    proc
            call    math_cos
            fld1
            fdivrp
            ret
math_csc    endp

            end