#ifndef __FDLIBM_H__
#include "fdlibm.h"
#endif

#ifndef __NO_LONG_DOUBLE_MATH

#ifndef __have_fpu_floor

long double __ieee754_floorl(long double x)
{
	int32_t j0;
	uint32_t i, j, se, i0, i1, sx;

	static const long double hugeval = 1.0e4930L;
	
	GET_LDOUBLE_WORDS(se, i0, i1, x);
	sx = (se >> 15) & 1;
	j0 = (se & IEEE854_LONG_DOUBLE_MAXEXP) - IEEE854_LONG_DOUBLE_BIAS;
	if (j0 < 31)
	{
		if (j0 < 0)
		{								/* raise inexact if x != 0 */
			if (hugeval + x > 0.0)
			{							/* return 0*sign(x) if |x|<1 */
				if (sx == 0)
				{
					se = 0;
					i0 = i1 = 0;
				} else if (((se & IEEE854_LONG_DOUBLE_MAXEXP) | i0 | i1) != 0)
				{
					se = 0xbfff;
					i0 = IC(0x80000000); /* explicit */
					i1 = 0;
				}
			}
		} else
		{
			i = UC(0x7fffffff) >> j0;
			if (((i0 & i) | i1) == 0)
				return x;				/* x is integral */
			if (hugeval + x > 0.0)
			{							/* raise inexact flag */
				if (sx)
				{
					if (j0 > 0 && (i0 + (UC(0x80000000) >> j0)) > i0)
						i0 += UC(0x80000000) >> j0;
					else
					{
						i = UC(0x7fffffff);
						++se;
					}
				}
				i0 &= (~i);
				i1 = 0;
			}
		}
	} else if (j0 > 62)
	{
		if (j0 == (IEEE854_LONG_DOUBLE_MAXEXP - IEEE854_LONG_DOUBLE_BIAS))
			return x + x;				/* inf or NaN */
		else
			return x;					/* x is integral */
	} else
	{
		i = UC(0xffffffff) >> (j0 - 31);
		if ((i1 & i) == 0)
			return x;					/* x is integral */
		if (hugeval + x > 0.0)
		{								/* raise inexact flag */
			if (sx)
			{
				if (j0 == 31)
					i0 += 1;
				else
				{
					j = i1 + (UC(1) << (63 - j0));
					if (j < i1)
						i0 += 1;		/* got a carry */
					i1 = j;
				}
			}
			i1 &= (~i);
		}
	}
	SET_LDOUBLE_WORDS(x, se, i0, i1);
	return x;
}

#endif

long double __floorl(long double x)
{
	return __ieee754_floorl(x);
}

__typeof(__floorl) floorl __attribute__((weak, alias("__floorl")));

#endif
