/***
*util.c - utilities for fp transcendentals
*
*	Copyright (c) 1991-2001, Microsoft Corporation.	All rights reserved.
*
*Purpose:
*   _set_exp and _add_exp are as those defined in Cody & Waite
*
*Revision History:
*   08-15-91	GDP	written
*   10-20-91	GDP	removed _rint, unsafe_intrnd
*   02-05-92	GDP	added _fpclass
*   03-27-92	GDP	added _d_min
*   06-23-92	GDP	added _d_mzero
*
*******************************************************************************/
#include "trans.h"

/* define special values */

_dbl _d_inf = {SET_DBL (0x7ff00000, 0x0) };	  //positive infinity
_dbl _d_ind = {SET_DBL (D_IND_HI, D_IND_LO)};	  //real indefinite
_dbl _d_max = {SET_DBL (0x7fefffff, 0xffffffff)}; //max double
_dbl _d_min = {SET_DBL (0x00100000, 0x00000000)}; //min normalized double
_dbl _d_mzero = {SET_DBL (0x80000000, 0x00000000)}; //negative zero



double _set_exp(double x, int exp)
/* does not check validity of exp */
{
    double retval;
    int biased_exp;
    retval = x;
    biased_exp = exp + D_BIASM1;
    *D_EXP(retval) = (unsigned short) (*D_EXP(x) & 0x800f | (biased_exp << 4));
    return retval;
}


int _get_exp(double x)
{
    signed short exp;
    exp = (signed short)((*D_EXP(x) & 0x7ff0) >> 4);
    exp -= D_BIASM1; //unbias
    return (int) exp;
}


double _add_exp(double x, int exp)
{
    return _set_exp(x, INTEXP(x)+exp);
}


double _set_bexp(double x, int bexp)
/* does not check validity of bexp */
{
    double retval;
    retval = x;
    *D_EXP(retval) = (unsigned short) (*D_EXP(x) & 0x800f | (bexp << 4));
    return retval;
}


int _sptype(double x)
{
    if (IS_D_INF(x))
	return T_PINF;
    if (IS_D_MINF(x))
	return T_NINF;
    if (IS_D_QNAN(x))
	return T_QNAN;
    if (IS_D_SNAN(x))
	return T_SNAN;
    return 0;
}



/***
*double _decomp(double x, double *expptr)
*
*Purpose:
*   decompose a number to a normalized mantisa and exponent
*
*Entry:
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/

double _decomp(double x, int *pexp)
{
    int exp;
    double man;

    if (x == 0) {
	man = 0;
	exp = 0;
    }
    else if (IS_D_DENORM(x)) {
	int neg;

	exp = 1-D_BIASM1;
	neg = x < 0.0;
	while((*D_EXP(x) & 0x0010) == 0) {
	    /* shift mantissa to the left until bit 52 is 1 */
	    (*D_HI(x)) <<= 1;
	    if (*D_LO(x) & 0x80000000)
		(*D_HI(x)) |= 0x1;
	    (*D_LO(x)) <<= 1;
	    exp--;
	}
	(*D_EXP(x)) &= 0xffef; /* clear bit 52 */
	if (neg) {
	    (*D_EXP(x)) |= 0x8000; /* set sign bit */
	}
	man = _set_exp(x,0);
    }
    else {
	man = _set_exp(x,0);
	exp = INTEXP(x);
    }

    *pexp = exp;
    return man;
}