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 <math_ldbl_opt.h>
00031 #include <float.h>
00032 
00033 #ifdef __STDC__
00034        double __nexttoward(double x, long double y)
00035 #else
00036        double __nexttoward(x,y)
00037        double x;
00038        long double y;
00039 #endif
00040 {
00041        int32_t hx,ix;
00042        int64_t hy,iy;
00043        u_int32_t lx;
00044        u_int64_t ly,uly;
00045 
00046        EXTRACT_WORDS(hx,lx,x);
00047        GET_LDOUBLE_WORDS64(hy,ly,y);
00048        ix = hx&0x7fffffff;         /* |x| */
00049        iy = hy&0x7fffffffffffffffLL;      /* |y| */
00050        uly = ly&0x7fffffffffffffffLL;     /* |y| */
00051 
00052        if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   /* x is nan */
00053           ((iy>=0x7ff0000000000000LL)&&((iy-0x7ff0000000000000LL)|uly)!=0))
00054                                                      /* y is nan */
00055           return x+y;
00056        if((long double) x==y) return y;   /* x=y, return y */
00057        if((ix|lx)==0) {                   /* x == 0 */
00058            double u;
00059            INSERT_WORDS(x,(u_int32_t)((hy>>32)&0x80000000),1);/* return +-minsub */
00060            u = math_opt_barrier (x);
00061            u = u * u;
00062            math_force_eval (u);           /* raise underflow flag */
00063            return x;
00064        }
00065        if(hx>=0) {                        /* x > 0 */
00066            if (hy<0||(ix>>20)>(iy>>52)
00067               || ((ix>>20)==(iy>>52)
00068                   && (((((int64_t)hx)<<32)|(lx))>(hy&0x000fffffffffffffLL)
00069                      || (((((int64_t)hx)<<32)|(lx))==(hy&0x000fffffffffffffLL)
00070                          )))) {    /* x > y, x -= ulp */
00071               if(lx==0) hx -= 1;
00072               lx -= 1;
00073            } else {                       /* x < y, x += ulp */
00074               lx += 1;
00075               if(lx==0) hx += 1;
00076            }
00077        } else {                           /* x < 0 */
00078            if (hy>=0||(ix>>20)>(iy>>52)
00079               || ((ix>>20)==(iy>>52)
00080                   && (((((int64_t)hx)<<32)|(lx))>(hy&0x000fffffffffffffLL)
00081                      || (((((int64_t)hx)<<32)|(lx))==(hy&0x000fffffffffffffLL)
00082                         )))) {     /* x < y, x -= ulp */
00083               if(lx==0) hx -= 1;
00084               lx -= 1;
00085            } else {                       /* x > y, x += ulp */
00086               lx += 1;
00087               if(lx==0) hx += 1;
00088            }
00089        }
00090        hy = hx&0x7ff00000;
00091        if(hy>=0x7ff00000) {
00092          x = x+x;    /* overflow  */
00093          if (FLT_EVAL_METHOD != 0 && FLT_EVAL_METHOD != 1)
00094            /* Force conversion to double.  */
00095            asm ("" : "+m"(x));
00096          return x;
00097        }
00098        if(hy<0x00100000) {
00099            double u = x*x;                /* underflow */
00100            math_force_eval (u);           /* raise underflow flag */
00101        }
00102        INSERT_WORDS(x,hx,lx);
00103        return x;
00104 }
00105 long_double_symbol (libm, __nexttoward, nexttoward);