Back to index

glibc  2.9
s_nextafterl.c
Go to the documentation of this file.
00001 /* s_nextafterl.c -- long double version of s_nextafter.c.
00002  * Conversion to IEEE quad long double by Jakub Jelinek, jj@ultra.linux.cz.
00003  */
00004 
00005 /*
00006  * ====================================================
00007  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
00008  *
00009  * Developed at SunPro, a Sun Microsystems, Inc. business.
00010  * Permission to use, copy, modify, and distribute this
00011  * software is freely granted, provided that this notice
00012  * is preserved.
00013  * ====================================================
00014  */
00015 
00016 #if defined(LIBM_SCCS) && !defined(lint)
00017 static char rcsid[] = "$NetBSD: $";
00018 #endif
00019 
00020 /* IEEE functions
00021  *     nextafterl(x,y)
00022  *     return the next machine floating-point number of x in the
00023  *     direction toward y.
00024  *   Special cases:
00025  */
00026 
00027 #include <math.h>
00028 #include <math_private.h>
00029 #include <math_ldbl_opt.h>
00030 
00031 #ifdef __STDC__
00032        long double __nextafterl(long double x, long double y)
00033 #else
00034        long double __nextafterl(x,y)
00035        long double x,y;
00036 #endif
00037 {
00038        int64_t hx,hy,ihx,ihy,ilx;
00039        u_int64_t lx,ly;
00040 
00041        GET_LDOUBLE_WORDS64(hx,lx,x);
00042        GET_LDOUBLE_WORDS64(hy,ly,y);
00043        ihx = hx&0x7fffffffffffffffLL;            /* |hx| */
00044        ilx = lx&0x7fffffffffffffffLL;            /* |lx| */
00045        ihy = hy&0x7fffffffffffffffLL;            /* |hy| */
00046 
00047        if((((ihx&0x7ff0000000000000LL)==0x7ff0000000000000LL)&&
00048            ((ihx&0x000fffffffffffffLL)!=0)) ||   /* x is nan */
00049           (((ihy&0x7ff0000000000000LL)==0x7ff0000000000000LL)&&
00050            ((ihy&0x000fffffffffffffLL)!=0)))     /* y is nan */
00051            return x+y; /* signal the nan */
00052        if(x==y)
00053            return y;        /* x=y, return y */
00054        if(ihx == 0 && ilx == 0) {                /* x == 0 */
00055            long double u;
00056            hy = (hy & 0x8000000000000000ULL) | 1;
00057            SET_LDOUBLE_WORDS64(x,hy,0ULL);/* return +-minsubnormal */
00058            u = math_opt_barrier (x);
00059            u = u * u;
00060            math_force_eval (u);           /* raise underflow flag */
00061            return x;
00062        }
00063        
00064        long double u;
00065        if(x > y) {   /* x > y, x -= ulp */
00066            if((hx==0xffefffffffffffffLL)&&(lx==0xfc8ffffffffffffeLL))
00067              return x+x;    /* overflow, return -inf */
00068            if (hx >= 0x7ff0000000000000LL) {
00069              SET_LDOUBLE_WORDS64(u,0x7fefffffffffffffLL,0x7c8ffffffffffffeLL);
00070              return u;
00071            }
00072            if(ihx <= 0x0360000000000000LL) {  /* x <= LDBL_MIN */
00073              u = math_opt_barrier (x);
00074              x -= __LDBL_DENORM_MIN__;
00075              if (ihx < 0x0360000000000000LL
00076                 || (hx > 0 && (int64_t) lx <= 0)
00077                 || (hx < 0 && (int64_t) lx > 1)) {
00078               u = u * u;
00079               math_force_eval (u);        /* raise underflow flag */
00080              }
00081              return x;
00082            }
00083            if (ihx < 0x06a0000000000000LL) { /* ulp will denormal */
00084              SET_LDOUBLE_WORDS64(u,(hx&0x7ff0000000000000LL),0ULL);
00085              u *= 0x1.0000000000000p-105L;
00086            } else
00087              SET_LDOUBLE_WORDS64(u,(hx&0x7ff0000000000000LL)-0x0690000000000000LL,0ULL);
00088            return x - u;
00089        } else {                           /* x < y, x += ulp */
00090            if((hx==0x7fefffffffffffffLL)&&(lx==0x7c8ffffffffffffeLL))
00091              return x+x;    /* overflow, return +inf */
00092            if ((u_int64_t) hx >= 0xfff0000000000000ULL) {
00093              SET_LDOUBLE_WORDS64(u,0xffefffffffffffffLL,0xfc8ffffffffffffeLL);
00094              return u;
00095            }
00096            if(ihx <= 0x0360000000000000LL) {  /* x <= LDBL_MIN */
00097              u = math_opt_barrier (x);
00098              x += __LDBL_DENORM_MIN__;
00099              if (ihx < 0x0360000000000000LL
00100                 || (hx > 0 && (int64_t) lx < 0 && lx != 0x8000000000000001LL)
00101                 || (hx < 0 && (int64_t) lx >= 0)) {
00102               u = u * u;
00103               math_force_eval (u);        /* raise underflow flag */
00104              }
00105              if (x == 0.0L) /* handle negative __LDBL_DENORM_MIN__ case */
00106               x = -0.0L;
00107              return x;
00108            }
00109            if (ihx < 0x06a0000000000000LL) { /* ulp will denormal */
00110              SET_LDOUBLE_WORDS64(u,(hx&0x7ff0000000000000LL),0ULL);
00111              u *= 0x1.0000000000000p-105L;
00112            } else
00113              SET_LDOUBLE_WORDS64(u,(hx&0x7ff0000000000000LL)-0x0690000000000000LL,0ULL);
00114            return x + u;
00115        }
00116 }
00117 strong_alias (__nextafterl, __nexttowardl)
00118 long_double_symbol (libm, __nextafterl, nextafterl);
00119 long_double_symbol (libm, __nexttowardl, nexttowardl);