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  * 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 #include "math.h"
00022 #include <math_private.h>
00023 #include <math_ldbl_opt.h>
00024 #include <float.h>
00025 
00026 #ifdef __STDC__
00027        float __nexttowardf(float x, long double y)
00028 #else
00029        float __nexttowardf(x,y)
00030        float x;
00031        long double y;
00032 #endif
00033 {
00034        int32_t hx,ix;
00035        int64_t hy,iy;
00036        u_int64_t ly, uly;
00037 
00038        GET_FLOAT_WORD(hx,x);
00039        GET_LDOUBLE_WORDS64(hy,ly,y);
00040        ix = hx&0x7fffffff;         /* |x| */
00041        iy = hy&0x7fffffffffffffffLL;      /* |y| */
00042        uly = ly&0x7fffffffffffffffLL;     /* |y| */
00043 
00044        if((ix>0x7f800000) ||   /* x is nan */
00045           ((iy>=0x7ff0000000000000LL)&&((iy-0x7ff0000000000000LL)|uly)!=0))
00046                             /* y is nan */
00047           return x+y;
00048        if((long double) x==y) return y;   /* x=y, return y */
00049        if(ix==0) {                        /* x == 0 */
00050            float u;
00051            SET_FLOAT_WORD(x,(u_int32_t)((hy>>32)&0x80000000)|1);/* return +-minsub*/
00052            u = math_opt_barrier (x);
00053            u = u * u;
00054            math_force_eval (u);           /* raise underflow flag */
00055            return x;
00056        }
00057        if(hx>=0) {                        /* x > 0 */
00058            if(hy<0||(ix>>23)>(iy>>52)-0x380
00059               || ((ix>>23)==(iy>>52)-0x380
00060                  && (ix&0x7fffff)>((hy>>29)&0x7fffff))) {/* x > y, x -= ulp */
00061               hx -= 1;
00062            } else {                       /* x < y, x += ulp */
00063               hx += 1;
00064            }
00065        } else {                           /* x < 0 */
00066            if(hy>=0||(ix>>23)>(iy>>52)-0x380
00067               || ((ix>>23)==(iy>>52)-0x380
00068                  && (ix&0x7fffff)>((hy>>29)&0x7fffff))) {/* x < y, x -= ulp */
00069               hx -= 1;
00070            } else {                       /* x > y, x += ulp */
00071               hx += 1;
00072            }
00073        }
00074        hy = hx&0x7f800000;
00075        if(hy>=0x7f800000) {
00076          x = x+x;    /* overflow  */
00077          if (FLT_EVAL_METHOD != 0)
00078            /* Force conversion to float.  */
00079            asm ("" : "+m"(x));
00080          return x;
00081        }
00082        if(hy<0x00800000) {         /* underflow */
00083            float u = x*x;
00084            math_force_eval (u);    /* raise underflow flag */
00085        }
00086        SET_FLOAT_WORD(x,hx);
00087        return x;
00088 }
00089 long_double_symbol (libm, __nexttowardf, nexttowardf);