Back to index

glibc  2.9
s_nexttowardf.c
Go to the documentation of this file.
00001 /* s_nexttowardf.c -- float version of s_nextafter.c.
00002  * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
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 #include "math.h"
00021 #include <math_private.h>
00022 #include <float.h>
00023 
00024 #ifdef __STDC__
00025        float __nexttowardf(float x, long double y)
00026 #else
00027        float __nexttowardf(x,y)
00028        float x;
00029        long double y;
00030 #endif
00031 {
00032        int32_t hx,ix,iy;
00033        u_int32_t hy,ly,esy;
00034 
00035        GET_FLOAT_WORD(hx,x);
00036        GET_LDOUBLE_WORDS(esy,hy,ly,y);
00037        ix = hx&0x7fffffff;         /* |x| */
00038        iy = esy&0x7fff;            /* |y| */
00039 
00040        if((ix>0x7f800000) ||                     /* x is nan */
00041           (iy>=0x7fff&&((hy|ly)!=0)))            /* y is nan */
00042           return x+y;
00043        if((long double) x==y) return y;   /* x=y, return y */
00044        if(ix==0) {                        /* x == 0 */
00045            float u;
00046            SET_FLOAT_WORD(x,((esy&0x8000)<<16)|1);/* return +-minsub*/
00047            u = math_opt_barrier (x);
00048            u = u * u;
00049            math_force_eval (u);           /* raise underflow flag */
00050            return x;
00051        }
00052        if(hx>=0) {                        /* x > 0 */
00053            if(esy>=0x8000||((ix>>23)&0xff)>iy-0x3f80
00054               || (((ix>>23)&0xff)==iy-0x3f80
00055                  && ((ix&0x7fffff)<<8)>(hy&0x7fffffff))) {/* x > y, x -= ulp */
00056               hx -= 1;
00057            } else {                       /* x < y, x += ulp */
00058               hx += 1;
00059            }
00060        } else {                           /* x < 0 */
00061            if(esy<0x8000||((ix>>23)&0xff)>iy-0x3f80
00062               || (((ix>>23)&0xff)==iy-0x3f80
00063                  && ((ix&0x7fffff)<<8)>(hy&0x7fffffff))) {/* x < y, x -= ulp */
00064               hx -= 1;
00065            } else {                       /* x > y, x += ulp */
00066               hx += 1;
00067            }
00068        }
00069        hy = hx&0x7f800000;
00070        if(hy>=0x7f800000) {
00071          x = x+x;    /* overflow  */
00072          if (FLT_EVAL_METHOD != 0)
00073            /* Force conversion to float.  */
00074            asm ("" : "+m"(x));
00075          return x;
00076        }
00077        if(hy<0x00800000) {
00078            float u = x*x;                 /* underflow */
00079            math_force_eval (u);           /* raise underflow flag */
00080        }
00081        SET_FLOAT_WORD(x,hx);
00082        return x;
00083 }
00084 weak_alias (__nexttowardf, nexttowardf)