/*------------------------------------------------------------------------
 * filename - atan2.cas
 *
 * function(s)
 *        atan2 - trigonometric function
 *-----------------------------------------------------------------------*/

/*
 *      C/C++ Run Time Library - Version 5.0
 *
 *      Copyright (c) 1987, 1992 by Borland International
 *      All Rights Reserved.
 *
 */


#pragma inline
#include <asmrules.h>

#include <_math.h>
#include <math.h>
#include <errno.h>

static  unsigned short  piBy2 [] = {0xC235, 0x2168, 0xDAA2, 0xC90F, 0x3FFF};
static  unsigned short  NANINVTRIG [4] = {0,0,0x0440, 0x7FF8};


/*--------------------------------------------------------------------------*

Name            atan2 - trigonometric function

Usage           double atan2(double y, double x);

Prototype in    math.h

Description     atan2  returns the  arc tangent   of y/x  and will  produce
                correct results even  when resulting is near pi/2  or -pi/2
                (x near 0).

Return value    atan2 returns a value in the range -pi to pi.
                If a ratio of 0/0  is supplied then _RANGE_VAL is returned
                and errno is set to:
                        EDOM Domain error

Caution: atan2(+0,-1) = +pi but atan2(-0,-1) = -pi.

*---------------------------------------------------------------------------*/
#pragma warn -rvl
#pragma warn -use

double _FARFUNC atan2( double y, double x )
{

asm     FLD     DOUBLE (x)
asm     mov     ax, x [6]       /* select MSW of x ..   */
asm     and     al, 0F0h        /* ignore fraction      */
asm     mov     bx, y [6]       /* .. and of y          */
asm     and     bl, 0F0h
asm     shl     bx, 1           /* discard sign         */
asm     FLD     DOUBLE (y)
asm     jz      at2_yIsZero
asm     shl     ax, 1           /* discard sign         */
asm     jz      at2_xIsZero
asm     cmp     ax, 0FFE0h
asm     jnb     at2_xIsInf
asm     cmp     bx, 0FFE0h
asm     jnb     at2_yIsInf

asm     FDIVRP  ST(1), ST(0)

#ifdef _Windows
        _f87_ArcTan();
#else
asm     _FAST_  (_FATAN_)
#endif

/* convert the simple answer to a four quadrant answer. */

at2_setQuad:
asm     test    BY0 (x [7]), 80h                /* the sign bit */
asm     jz      at2_end

asm     FLDPI

asm     test    BY0 (y [7]), 80h
asm     jz      at2_2ndQuad

at2_3rdQuad:
asm     FSUBP   ST(1), ST
asm     jmp     short   at2_end

at2_2ndQuad:
asm     FADDP   ST(1), ST

at2_end:
        return;


/*      Special cases.
*/
at2_yIsZero:
asm     rcl     cx, 1                   /* save sign of y = 0 */
asm     shl     ax, 1
asm     jz      at2_indeterminate       /* if both are zero     */
asm     jc      at2_retPi               /* x<0, return Pi */
asm     FSTP    ST(1)                   /* else y is result     */
asm     jmp     short   at2_end

at2_retPi:                      /* y = 0, x < 0 */
asm     FSTP    ST(0)           /* discard x and y */
asm     FSTP    ST(0)
asm     FLDPI                   /* and return PI */
asm     shr     cx, 1           /* was y +0 or -0 ? */
asm     jnc     at2_end
asm     FCHS
asm     jmp     short at2_end

at2_xIsZero:                            /* and y is not zero    */
                                        /*      or              */
at2_yIsInf:                             /* and x is finite      */
asm     FSTP    ST(0)           /* discard x and y */
asm     FSTP    ST(0)
asm     FLD     tbyte ptr (piBy2)
asm     test    BY0 (y [7]), 80h                /* check sign of Y */
asm     jz      at2_HPi         /* positive - return PI/2 */
asm     FCHS                    /* negative - return -PI/2 */
at2_HPi:
asm     jmp     short   at2_end

at2_xIsInf:
asm     cmp     bx, 0FFE0h
asm     jnb     at2_indeterminate       /* if both are infinite */
asm     FSTP    ST(0)           /* discard x and y */
asm     FSTP    ST(0)
asm     FLDZ
asm     jmp     short   at2_setQuad

/*
  There are two cases considered irresolvable: both operands zero, or
  both operands infinite.
*/
at2_indeterminate:                      /* either equal or both infinite */
asm     FSTP    ST(0)           /* discard x and y */
asm     FSTP    ST(0)
#pragma warn -ret
        return _matherr (DOMAIN, "atan2", &x, &y,  *((double *) NANINVTRIG));
#pragma warn .ret
}
#pragma warn .rvl
#pragma warn .use
