/* $Header:fpnext.c 12.0$ */
/* $ACIS:fpnext.c 12.0$ */
/* $Source: /ibm/acis/usr/src/lib/libc/ca/gen/RCS/fpnext.c,v $ */

#ifndef lint
static char *rcsid = "$Header:fpnext.c 12.0$";
#endif

#include <ieee.h>

typedef union{
     double d;
     struct {
	unsigned long hi, lo;
	} ul;
} udouble;

typedef union{
     float f;
     unsigned long ul;
} ufloat;

double nextdouble(x,y)
udouble x,y;
{
	NUMCLASS classx, classy;
	unsigned long xsign;
	
	classx = classdouble(x.d);
	classy = classdouble(y.d);
	if (classx == SNAN)
	{
		swapfpflag(FPINVALID,FPINVALID);
		x.ul.hi |= 0x80000;
		return(x.d);
	}
	if (classy == SNAN)
	{
		swapfpflag(FPINVALID,FPINVALID);
		y.ul.hi |= 0x80000;
		return(y.d);
	}
	if (classx == QNAN)
		return(x.d);
	if (classy == QNAN)
		return(y.d);
	if ((x.ul.hi == y.ul.hi) && (x.ul.lo == y.ul.lo))
		return(x.d);
	if (classx == ZERONUM)
	{
		if (classy == ZERONUM)
			return(x.d);
		x.ul.lo++;
		x.ul.hi = (y.ul.hi & 0x80000000);
		swapfpflag(FPUNDERFLOW,FPUNDERFLOW);
		swapfpflag(FPINEXACT,FPINEXACT);
		return(x.d);
	}
	xsign = x.ul.hi & 0x80000000;
	if (xsign)
	{
		x.ul.hi &= 0x7fffffff;
		y.ul.hi ^= 0x80000000;
	}
	if (x.d < y.d)
	{
		x.ul.lo++;
		if (x.ul.lo == 0)
		{
			x.ul.hi++;
			if ((x.ul.hi & 0x7ff00000) == 0x7ff00000)
			{
				swapfpflag(FPOVERFLOW,FPOVERFLOW);
				swapfpflag(FPINEXACT,FPINEXACT);
			}
		}
	}
	else
	{
		if (x.ul.lo == 0)
			x.ul.hi--;
		x.ul.lo--;
	}
	x.ul.hi |= xsign;
	if ((x.ul.hi & 0x7ff00000) == 0)
	{
		swapfpflag(FPUNDERFLOW,FPUNDERFLOW);
		swapfpflag(FPINEXACT,FPINEXACT);
	}
	return(x.d);
}

float nextfloat(x,y)
double x,y;
{
	NUMCLASS classx, classy;
	unsigned long xsign;
	ufloat xf, yf;

	classx = classfloat(x);
	classy = classfloat(y);

	xf.f = (float) x;
	yf.f = (float) y;

	if (classx == QNAN)
		return(xf.f);
	if (classy == QNAN)
		return(yf.f);
	if (xf.ul == yf.ul)
		return(xf.f);
	if (classx == ZERONUM)
	{	if (classy == ZERONUM)
			return(xf.f);
		xf.ul = (yf.ul & 0x80000000) + 1;
		swapfpflag(FPUNDERFLOW,FPUNDERFLOW);
		swapfpflag(FPINEXACT,FPINEXACT);
		return(xf.f);
	}
	xsign = xf.ul & 0x80000000;
	if (xsign)
	{	xf.ul &= 0x7fffffff;
		yf.ul ^= 0x80000000;
	}
	if (xf.f < yf.f)
	{	xf.ul++;
		if ((xf.ul & 0x7f800000) == 0x7f800000)
		{	swapfpflag(FPOVERFLOW,FPOVERFLOW);
			swapfpflag(FPINEXACT,FPINEXACT);
		}
	}
	else
		xf.ul--;
	xf.ul |= xsign;
	if ((xf.ul & 0x7f800000) == 0)
	{	swapfpflag(FPUNDERFLOW,FPUNDERFLOW);
		swapfpflag(FPINEXACT,FPINEXACT);
	}
	return(xf.f);
}
