1130613Smlaier/* s_nextafterl.c -- long double version of s_nextafter.c.
2130610Smlaier * Conversion to IEEE quad long double by Jakub Jelinek, jj@ultra.linux.cz.
3133573Smlaier */
4130610Smlaier
5130610Smlaier/*
6130610Smlaier * ====================================================
7130610Smlaier * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
8130610Smlaier *
9130610Smlaier * Developed at SunPro, a Sun Microsystems, Inc. business.
10130610Smlaier * Permission to use, copy, modify, and distribute this
11130610Smlaier * software is freely granted, provided that this notice
12130610Smlaier * is preserved.
13130610Smlaier * ====================================================
14130610Smlaier */
15130610Smlaier
16130610Smlaier#if defined(LIBM_SCCS) && !defined(lint)
17130610Smlaierstatic char rcsid[] = "NetBSD: ";
18130610Smlaier#endif
19130610Smlaier
20130610Smlaier/* IEEE functions
21130610Smlaier *	nextafterq(x,y)
22130610Smlaier *	return the next machine floating-point number of x in the
23130610Smlaier *	direction toward y.
24130610Smlaier *   Special cases:
25130610Smlaier */
26130610Smlaier
27130610Smlaier#include "quadmath-imp.h"
28130610Smlaier
29130610Smlaier__float128 nextafterq(__float128 x, __float128 y)
30130610Smlaier{
31130610Smlaier	int64_t hx,hy,ix,iy;
32130610Smlaier	uint64_t lx,ly;
33130610Smlaier
34130610Smlaier	GET_FLT128_WORDS64(hx,lx,x);
35130613Smlaier	GET_FLT128_WORDS64(hy,ly,y);
36130613Smlaier	ix = hx&0x7fffffffffffffffLL;		/* |x| */
37130613Smlaier	iy = hy&0x7fffffffffffffffLL;		/* |y| */
38130613Smlaier
39130613Smlaier	if(((ix>=0x7fff000000000000LL)&&((ix-0x7fff000000000000LL)|lx)!=0) ||   /* x is nan */
40130610Smlaier	   ((iy>=0x7fff000000000000LL)&&((iy-0x7fff000000000000LL)|ly)!=0))     /* y is nan */
41130610Smlaier	   return x+y;
42130613Smlaier	if(x==y) return y;		/* x=y, return y */
43130613Smlaier	if((ix|lx)==0) {			/* x == 0 */
44130613Smlaier	    __float128 u;
45130610Smlaier	    SET_FLT128_WORDS64(x,hy&0x8000000000000000ULL,1);/* return +-minsubnormal */
46130610Smlaier	    u = math_opt_barrier (x);
47130610Smlaier	    u = u * u;
48130610Smlaier	    math_force_eval (u);		/* raise underflow flag */
49130610Smlaier	    return x;
50130613Smlaier	}
51130610Smlaier	if(hx>=0) {			/* x > 0 */
52130613Smlaier	    if(hx>hy||((hx==hy)&&(lx>ly))) {	/* x > y, x -= ulp */
53130610Smlaier		if(lx==0) hx--;
54130610Smlaier		lx--;
55130610Smlaier	    } else {				/* x < y, x += ulp */
56130610Smlaier		lx++;
57133573Smlaier		if(lx==0) hx++;
58130610Smlaier	    }
59130610Smlaier	} else {				/* x < 0 */
60130610Smlaier	    if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */
61130610Smlaier		if(lx==0) hx--;
62130610Smlaier		lx--;
63130610Smlaier	    } else {				/* x > y, x += ulp */
64130610Smlaier		lx++;
65130610Smlaier		if(lx==0) hx++;
66130610Smlaier	    }
67130610Smlaier	}
68130610Smlaier	hy = hx&0x7fff000000000000LL;
69130610Smlaier	if(hy==0x7fff000000000000LL) {
70130610Smlaier	    __float128 u = x + x;		/* overflow  */
71130610Smlaier	    math_force_eval (u);
72130610Smlaier	    errno = ERANGE;
73130610Smlaier	}
74130610Smlaier	if(hy==0) {
75130610Smlaier	    __float128 u = x*x;		/* underflow */
76130610Smlaier	    math_force_eval (u);		/* raise underflow flag */
77130610Smlaier	    errno = ERANGE;
78130610Smlaier	}
79130610Smlaier	SET_FLT128_WORDS64(x,hx,lx);
80130610Smlaier	return x;
81130613Smlaier}
82130610Smlaier