/*							ceil()
 *							floor()
 *							frexp()
 *							ldexp()
 *
 *	Floating point numeric utilities
 *
 *
 *
 * SYNOPSIS:
 *
 * double x, y;
 * double ceil(), floor(), frexp(), ldexp();
 * int expnt, n;
 *
 * y = floor(x);
 * y = ceil(x);
 * y = frexp( x, &expnt );
 * y = ldexp( x, n );
 *
 *
 *
 * DESCRIPTION:
 *
 * All four routines return a double precision floating point
 * result.
 *
 * floor() returns the largest integer less than or equal to x.
 * It truncates toward minus infinity.
 *
 * ceil() returns the smallest integer greater than or equal
 * to x.  It truncates toward plus infinity.
 *
 * frexp() extracts the exponent from x.  It returns an integer
 * power of two to expnt and the significand between 0.5 and 1
 * to y.  Thus  x = y * 2**expn.
 *
 * ldexp() multiplies x by 2**n.
 *
 * These functions are part of the standard C run time library
 * for many but not all C compilers.  The ones supplied are
 * written in C for either DEC or IEEE arithmetic.  They should
 * be used only if your compiler library does not already have
 * them.
 *
 * The IEEE versions assume that denormal numbers are implemented
 * in the arithmetic.  Some modifications will be required if
 * the arithmetic has abrupt rather than gradual underflow.
 */


/*
Cephes Math Library Release 2.1:  December, 1988
Copyright 1984, 1987, 1988 by Stephen L. Moshier
Direct inquiries to 30 Frost Street, Cambridge, MA 02140
*/


#include "mconf.h"
#define DENORMAL 1

#ifdef UNK
char *unkmsg = "ceil(), floor(), frexp(), ldexp() must be rewritten!\n";
#endif

#ifdef DEC
#define EXPMSK 0x807f
#define MEXP 255
#define NBITS 56
#endif

#ifdef IBMPC
#define EXPMSK 0x800f
#define MEXP 0x7ff
#define NBITS 53
#endif

#ifdef MIEEE
#define EXPMSK 0x800f
#define MEXP 0x7ff
#define NBITS 53
#endif

extern double MAXNUM;





double ceil(x)
double x;
{
double y;
double floor();

#ifdef UNK
mtherr( "ceil", DOMAIN );
return(0.0);
#endif

y = floor(x);
if( y < x )
	y += 1.0;
return(y);
}




/* Bit clearing masks: */

static unsigned short bmask[] = {
0xffff,
0xfffe,
0xfffc,
0xfff8,
0xfff0,
0xffe0,
0xffc0,
0xff80,
0xff00,
0xfe00,
0xfc00,
0xf800,
0xf000,
0xe000,
0xc000,
0x8000,
0x0000,
};




double floor(x)
double x;
{
unsigned short *p;
double y;
int e, i;

#ifdef UNK
mtherr( "floor", DOMAIN );
return(0.0);
#endif

y = x;
/* find the exponent (power of 2) */
#ifdef DEC
p = (unsigned short *)&y;
e = (( *p  >> 7) & 0377) - 0201;
p += 3;
#endif

#ifdef IBMPC
p = (unsigned short *)&y + 3;
e = (( *p >> 4) & 0x7ff) - 0x3ff;
p -= 3;
#endif

#ifdef MIEEE
p = (unsigned short *)&y;
e = (( *p >> 4) & 0x7ff) - 0x3ff;
p += 3;
#endif

if( e < 0 )
	{
	if( y < 0.0 )
		return( -1.0 );
	else
		return( 0.0 );
	}

e = (NBITS -1) - e;
/* clean out 16 bits at a time */
while( e >= 16 )
	{
#ifdef IBMPC
	*p++ = 0;
#endif

#ifdef DEC
	*p-- = 0;
#endif

#ifdef MIEEE
	*p-- = 0;
#endif
	e -= 16;
	}

/* clear the remaining bits */
if( e > 0 )
	*p &= bmask[e];

if( (x < 0) && (y != x) )
	y -= 1.0;

return(y);
}



double frexp( x, pw2 )
double x;
int *pw2;
{
double y;
int i, k;
short *q;

y = x;

#ifdef UNK
mtherr( "frexp", DOMAIN );
return(0.0);
#endif

#ifdef IBMPC
q = (short *)&y + 3;
#endif

#ifdef DEC
q = (short *)&y;
#endif

#ifdef MIEEE
q = (short *)&y;
#endif

/* find the exponent (power of 2) */
#ifdef DEC
i  = ( *q >> 7) & 0377;
if( i == 0 )
	{
	*pw2 = 0;
	return(0.0);
	}
i -= 0200;
*pw2 = i;
*q &= 0x807f;	/* strip all exponent bits */
*q |= 040000;	/* mantissa between 0.5 and 1 */
return(y);
#endif

#ifdef IBMPC
i  = ( *q >> 4) & 0x7ff;
if( i != 0 )
	goto ieeedon;
#endif

#ifdef MIEEE
i  =  *q >> 4;
i &= 0x7ff;
if( i != 0 )
	goto ieeedon;
#if DENORMAL

#else
*pw2 = 0;
return(0.0);
#endif

#endif


#ifndef DEC
/* Number is denormal or zero */
#if DENORMAL
if( y == 0.0 )
	{
iszero:
	*pw2 = 0;
	return( 0.0 );
	}


/* Handle denormal number. */
do
	{
	y *= 2.0;
	i -= 1;
	k  = ( *q >> 4) & 0x7ff;
	}
while( k == 0 );
i = i + k;
#endif /* DENORMAL */

ieeedon:

i -= 0x3fe;
*pw2 = i;
*q &= 0x800f;
*q |= 0x3fe0;
return( y );
#endif
}






double ldexp( x, pw2 )
double x;
int pw2;
{
double y;
short *q;
int e;

#ifdef UNK
mtherr( "ldexp", DOMAIN );
return(0.0);
#endif

y = x;
#ifdef DEC
q = (short *)&y;
e  = ( *q >> 7) & 0377;
if( e == 0 )
	return(0.0);
#else

#ifdef IBMPC
q = (short *)&y + 3;
#endif
#ifdef MIEEE
q = (short *)&y;
#endif
while( (e = (*q & 0x7ff0) >> 4) == 0 )
	{
	if( y == 0.0 )
		{
		return( 0.0 );
		}
/* Input is denormal. */
	if( pw2 > 0 )
		{
		y *= 2.0;
		pw2 -= 1;
		}
	if( pw2 < 0 )
		{
		if( pw2 < -53 )
			return(0.0);
		y /= 2.0;
		pw2 += 1;
		}
	if( pw2 == 0 )
		return(y);
	}
#endif /* not DEC */

e += pw2;

/* Handle overflow */
if( e > MEXP )
	{
	return( MAXNUM );
	}

/* Handle denormalized results */
if( e < 1 )
	{
#if DENORMAL
	if( e < -53 )
		return(0.0);
	*q &= 0x800f;
	*q |= 0x10;
	while( e < 1 )
		{
		y /= 2.0;
		e += 1;
		}
	return(y);
#else
	return(0.0);
#endif
	}
else
	{
#ifdef DEC
	*q &= 0x807f;	/* strip all exponent bits */
	*q |= (e & 0xff) << 7;
#else
	*q &= 0x800f;
	*q |= (e & 0x7ff) << 4;
#endif
	return(y);
	}
}
