/*
 * PROJECT C Library, X68000 PROGRAMMING INTERFACE DEFINITION
 * --------------------------------------------------------------------
 * This file is written by the Project C Library Group,  and completely
 * in public domain. You can freely use, copy, modify, and redistribute
 * the whole contents, without this notice.
 * --------------------------------------------------------------------
 * $Id: $
 */

#ifndef __sys_math_fe_h__
#define __sys_math_fe_h__

#ifndef __GNUC__
#error You lose. This file can be compiled only by GNU-C compiler.
#endif

#ifndef __cdecl_h__
#include <cdecl.h>
#endif


#define __FPACK(func, x)					\
    (__extension__ ({						\
	register double f __asm ("d0") = (x);			\
	__asm (".dc %c1" : "=d" (f) : "i" (func), "d" (f));	\
	f;							\
    }))

#define __FPACK2(func, x, y)					\
    (__extension__ ({						\
	register double f1 __asm ("d0") = (x);			\
	register double f2 __asm ("d2") = (y);			\
	__asm (".dc %c1" : "=d" (f1) : "i" (func), "d" (f1), "d" (f2));	\
	f1;							\
    }))


static __inline __const double __inline_acos (double x)
{
    return __FPACK (__ACOS, x);
}

static __inline __const double __inline_acosh (double x)
{
    return __FPACK (__LOG, x + __FPACK (__SQR, (x * x) - 1.0));
}

static __inline __const double __inline_asin (double x)
{
    return __FPACK (__ASIN, x);
}

static __inline __const double __inline_asinh (double x)
{
    return __FPACK (__LOG, x + __FPACK (__SQR, (x * x) + 1.0));
}

static __inline __const double __inline_atan (double x)
{
    return __FPACK (__ATAN, x);
}

static __inline __const double __inline_atan2 (double y, double x)
{
    if (x > 0.0)
	return __FPACK (__ATAN, y / x);
    else if (x < 0.0) {
	if (y > 0.0)
	    return __FPACK (__ATAN, y / x) + M_PI;
	else if (y < 0.0)
	    return __FPACK (__ATAN, y / x) - M_PI;
	else
	    return M_PI;
    }
    else {
	if (y < 0.0)
	    return -M_PI_2;
	else if (y > 0.0)
	    return +M_PI_2;
	else
	    return _NAN;
    }
}

static __inline __const double __inline_atanh (double x)
{
    return __FPACK (__ATANH, x);
}

static __inline __const double __inline_ceil (double x)
{
    return __FPACK (__DCEIL, x);
}

static __inline __const double __inline_cos (double x)
{
    return __FPACK (__COS, x);
}

static __inline __const double __inline_cosh (double x)
{
    return __FPACK (__COSH, x);
}

static __inline __const double __inline_exp (double x)
{
    return __FPACK (__EXP, x);
}

static __inline __const double __inline_fabs (double x)
{
    ((xdouble_t*)&x)->w[0] &= 0x7fff;
    return x;
}

static __inline __const double __inline_floor (double x)
{
    return __FPACK (__DFLOOR, x);
}

static __inline __const double __inline_fmod (double x, double y)
{
    return __FPACK2 (__DMOD, x, y);
}

static __inline __const double __inline_ldexp (double x, int_ exp)
{
    xdouble_t value;

    if ((value.d = x) == 0.0)
	return 0;

    if ((exp += value.ieee.exp) < 1)
	return HUGE_VAL;
    else if (exp > 0x7ff)
	return HUGE_VAL;

    value.ieee.exp = exp;

    return value.d;
}

static __inline __const double __inline_log (double x)
{
    return __FPACK (__LOG, x);
}

static __inline __const double __inline_log10 (double x)
{
    return __FPACK (__LOG10, x);
}

static __inline __const double __inline_pow (double x, double y)
{
    return __FPACK2 (__POWER, x, y);
}

static __inline __const double __inline_sin (double x)
{
    return __FPACK (__SIN, x);
}

static __inline __const double __inline_sinh (double x)
{
    return __FPACK (__SINH, x);
}

static __inline __const double __inline_sqrt (double x)
{
    return __FPACK (__SQR, x);
}

static __inline __const double __inline_tan (double x)
{
    return __FPACK (__TAN, x);
}

static __inline __const double __inline_tanh (double x)
{
    return __FPACK (__TANH, x);
}

static __inline double __inline_frexp (double x, int_ *exp)
{
    xdouble_t value;

    if ((value.d = x) == 0.0)
	*exp = 0;
    else {
	*exp = value.ieee.exp - 0x03fe;
	value.ieee.exp = 0x3fe;
    }

    return value.d;
}

static __inline double __inline_modf (double x, double *iptr)
{
    double value = __FPACK (__DFIX, x);

    *iptr = value;
    return x - value;
}

static __inline __const int_ __inline_isinf (double x)
{
    xdouble_t value = { x };

    return (value.l[1] == 0 && (((value.l[0] ^ 0x7ff0_0000) << 1) == 0));
}

static __inline __const int_ __inline_isnan (double x)
{
    xdouble_t value = { x };

    return (value.w[0] & 0x7ff0) == 0x7ff0
	&& ((value.l[0] & 0x000f_ffff) || value.l[1]);
}

#endif
