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 and Jakub Jelinek, jj@ultra.linux.cz.
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;
00041        int64_t hy,iy;
00042        u_int32_t lx;
00043        u_int64_t ly;
00044 
00045        EXTRACT_WORDS(hx,lx,x);
00046        GET_LDOUBLE_WORDS64(hy,ly,y);
00047        ix = hx&0x7fffffff;         /* |x| */
00048        iy = hy&0x7fffffffffffffffLL;      /* |y| */
00049 
00050        if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   /* x is nan */
00051           ((iy>=0x7fff000000000000LL)&&((iy-0x7fff000000000000LL)|ly)!=0))
00052                                                      /* y is nan */
00053           return x+y;
00054        if((long double) x==y) return y;   /* x=y, return y */
00055        if((ix|lx)==0) {                   /* x == 0 */
00056            double u;
00057            INSERT_WORDS(x,(u_int32_t)((hy>>32)&0x80000000),1);/* return +-minsub */
00058            u = math_opt_barrier (x);
00059            u = u * u;
00060            math_force_eval (u);           /* raise underflow flag */
00061            return x;
00062        }
00063        if(hx>=0) {                        /* x > 0 */
00064            if (hy<0||(ix>>20)>(iy>>48)-0x3c00
00065               || ((ix>>20)==(iy>>48)-0x3c00
00066                   && (((((int64_t)hx)<<28)|(lx>>4))>(hy&0x0000ffffffffffffLL)
00067                      || (((((int64_t)hx)<<28)|(lx>>4))==(hy&0x0000ffffffffffffLL)
00068                          && (lx&0xf)>(ly>>60))))) {     /* x > y, x -= ulp */
00069               if(lx==0) hx -= 1;
00070               lx -= 1;
00071            } else {                       /* x < y, x += ulp */
00072               lx += 1;
00073               if(lx==0) hx += 1;
00074            }
00075        } else {                           /* x < 0 */
00076            if (hy>=0||(ix>>20)>(iy>>48)-0x3c00
00077               || ((ix>>20)==(iy>>48)-0x3c00
00078                   && (((((int64_t)hx)<<28)|(lx>>4))>(hy&0x0000ffffffffffffLL)
00079                      || (((((int64_t)hx)<<28)|(lx>>4))==(hy&0x0000ffffffffffffLL)
00080                          && (lx&0xf)>(ly>>60))))) {     /* x < y, x -= ulp */
00081               if(lx==0) hx -= 1;
00082               lx -= 1;
00083            } else {                       /* x > y, x += ulp */
00084               lx += 1;
00085               if(lx==0) hx += 1;
00086            }
00087        }
00088        hy = hx&0x7ff00000;
00089        if(hy>=0x7ff00000) {
00090          x = x+x;    /* overflow  */
00091          if (FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1)
00092            /* Force conversion to double.  */
00093            asm ("" : "+m"(x));
00094          return x;
00095        }
00096        if(hy<0x00100000) {
00097            double u = x*x;                /* underflow */
00098            math_force_eval (u);           /* raise underflow flag */
00099        }
00100        INSERT_WORDS(x,hx,lx);
00101        return x;
00102 }
00103 weak_alias (__nexttoward, nexttoward)