#include <9pm/u.h>
#include <9pm/libc.h>

#define	MASK	0x7ffL
#define	SHIFT	(64-11-1)
#define	BIAS	1022L

double
frexp(double d, int *ep)
{
	uvlong x;

	if(d == 0) {
		*ep = 0;
		return 0;
	}
	x = *(uvlong*)&d;
	*ep = (int)((x >> SHIFT) & MASK) - BIAS;
	x &= ~((uvlong)MASK << SHIFT);
	x |= (uvlong)BIAS << SHIFT;
	return *(double*)&x;
}

double
ldexp(double d, int e)
{
	uvlong x;

	if(d == 0)
		return 0;
	x = *(uvlong*)&d;
	e += (int)(x >> SHIFT) & MASK;
	if(e <= 0)
		return 0;	/* underflow */
	if(e >= MASK){		/* overflow */
		if(d < 0)
			return Inf(-1);
		return Inf(1);
	}
	x &= ~((uvlong)MASK << SHIFT);
	x |= (uvlong)e << SHIFT;
	return *(double*)&x;
}

double
modf(double d, double *ip)
{
	double dd;
	uvlong x;
	int e;

	if(d < 1) {
		if(d < 0) {
			d = modf(-d, ip);
			*ip = -*ip;
			return -d;
		}
		*ip = 0;
		return d;
	}
	x = *(uvlong*)&d;
	e = (int)((x >> SHIFT) & MASK) - BIAS;
	/*
	 * Keep the top 11+e bits; clear the rest.
	 */
	if(e <= 64-11)
		x &= ~((uvlong)1 << (64-11-e))-1;
	dd = *(double*)&x;
	*ip = dd;
	return d - dd;
}
