Back to index

glibc  2.9
s_nexttoward.c
Go to the documentation of this file.
00001 /* s_nexttoward.c
00002  * Conversion from s_nextafter.c by Ulrich Drepper, Cygnus Support,
00003  * drepper@cygnus.com.
00004  */
00005 
00006 /*
00007  * ====================================================
00008  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
00009  *
00010  * Developed at SunPro, a Sun Microsystems, Inc. business.
00011  * Permission to use, copy, modify, and distribute this
00012  * software is freely granted, provided that this notice
00013  * is preserved.
00014  * ====================================================
00015  */
00016 
00017 #if defined(LIBM_SCCS) && !defined(lint)
00018 static char rcsid[] = "$NetBSD: $";
00019 #endif
00020 
00021 /* IEEE functions
00022  *     nexttoward(x,y)
00023  *     return the next machine floating-point number of x in the
00024  *     direction toward y.
00025  *   Special cases:
00026  */
00027 
00028 #include "math.h"
00029 #include <math_private.h>
00030 #include <float.h>
00031 
00032 #ifdef __STDC__
00033        double __nexttoward(double x, long double y)
00034 #else
00035        double __nexttoward(x,y)
00036        double x;
00037        long double y;
00038 #endif
00039 {
00040        int32_t hx,ix,iy;
00041        u_int32_t lx,hy,ly,esy;
00042 
00043        EXTRACT_WORDS(hx,lx,x);
00044        GET_LDOUBLE_WORDS(esy,hy,ly,y);
00045        ix = hx&0x7fffffff;         /* |x| */
00046        iy = esy&0x7fff;            /* |y| */
00047 
00048        if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   /* x is nan */
00049           ((iy>=0x7fff)&&(hy|ly)!=0))        /* y is nan */
00050           return x+y;
00051        if((long double) x==y) return y;   /* x=y, return y */
00052        if((ix|lx)==0) {                   /* x == 0 */
00053            double u;
00054            INSERT_WORDS(x,(esy&0x8000)<<16,1); /* return +-minsub */
00055            u = math_opt_barrier (x);
00056            u = u * u;
00057            math_force_eval (u);           /* raise underflow flag */
00058            return x;
00059        }
00060        if(hx>=0) {                        /* x > 0 */
00061            if (esy>=0x8000||((ix>>20)&0x7ff)>iy-0x3c00
00062               || (((ix>>20)&0x7ff)==iy-0x3c00
00063                   && (((hx<<11)|(lx>>21))>(hy&0x7fffffff)
00064                      || (((hx<<11)|(lx>>21))==(hy&0x7fffffff)
00065                          && (lx<<11)>ly)))) {    /* x > y, x -= ulp */
00066               if(lx==0) hx -= 1;
00067               lx -= 1;
00068            } else {                       /* x < y, x += ulp */
00069               lx += 1;
00070               if(lx==0) hx += 1;
00071            }
00072        } else {                           /* x < 0 */
00073            if (esy<0x8000||((ix>>20)&0x7ff)>iy-0x3c00
00074               || (((ix>>20)&0x7ff)==iy-0x3c00
00075                   && (((hx<<11)|(lx>>21))>(hy&0x7fffffff)
00076                      || (((hx<<11)|(lx>>21))==(hy&0x7fffffff)
00077                          && (lx<<11)>ly))))      {/* x < y, x -= ulp */
00078               if(lx==0) hx -= 1;
00079               lx -= 1;
00080            } else {                       /* x > y, x += ulp */
00081               lx += 1;
00082               if(lx==0) hx += 1;
00083            }
00084        }
00085        hy = hx&0x7ff00000;
00086        if(hy>=0x7ff00000) {
00087          x = x+x;    /* overflow  */
00088          if (FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1)
00089            /* Force conversion to double.  */
00090            asm ("" : "+m"(x));
00091          return x;
00092        }
00093        if(hy<0x00100000) {
00094            double u = x*x;                /* underflow */
00095            math_force_eval (u);           /* raise underflow flag */
00096        }
00097        INSERT_WORDS(x,hx,lx);
00098        return x;
00099 }
00100 weak_alias (__nexttoward, nexttoward)