Back to index

glibc  2.9
s_nexttowardf.c
Go to the documentation of this file.
00001 /* Single precision version of nexttoward.c.
00002    Conversion to IEEE single float by Jakub Jelinek, jj@ultra.linux.cz. */
00003 /*
00004  * ====================================================
00005  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
00006  *
00007  * Developed at SunPro, a Sun Microsystems, Inc. business.
00008  * Permission to use, copy, modify, and distribute this
00009  * software is freely granted, provided that this notice
00010  * is preserved.
00011  * ====================================================
00012  */
00013 
00014 /* IEEE functions
00015  *     nexttowardf(x,y)
00016  *     return the next machine floating-point number of x in the
00017  *     direction toward y.
00018  * This is for machines which use the same binary type for double and
00019  * long double.
00020  *   Special cases:
00021  */
00022 
00023 #include <math.h>
00024 #include <math_private.h>
00025 #include <float.h>
00026 
00027 #ifdef __STDC__
00028        float __nexttowardf(float x, long double y)
00029 #else
00030        float __nexttowardf(x,y)
00031        float x;
00032        long double y;
00033 #endif
00034 {
00035        int32_t hx,hy,ix,iy;
00036        u_int32_t ly;
00037 
00038        GET_FLOAT_WORD(hx,x);
00039        EXTRACT_WORDS(hy,ly,y);
00040        ix = hx&0x7fffffff;         /* |x| */
00041        iy = hy&0x7fffffff;         /* |y| */
00042 
00043        if((ix>0x7f800000) ||                               /* x is nan */
00044           ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0))    /* y is nan */
00045           return x+y;
00046        if((long double) x==y) return y;   /* x=y, return y */
00047        if(ix==0) {                        /* x == 0 */
00048            float u;
00049            SET_FLOAT_WORD(x,(u_int32_t)(hy&0x80000000)|1);/* return +-minsub*/
00050            u = math_opt_barrier (x);
00051            u = u * u;
00052            math_force_eval (u);            /* raise underflow flag */
00053            return x;
00054        }
00055        if(hx>=0) {                        /* x > 0 */
00056            if(hy<0||(ix>>23)>(iy>>20)-0x380
00057               || ((ix>>23)==(iy>>20)-0x380
00058                  && (ix&0x7fffff)>(((hy<<3)|(ly>>29))&0x7fffff)))     /* x > y, x -= ulp */
00059               hx -= 1;
00060            else                           /* x < y, x += ulp */
00061               hx += 1;
00062        } else {                           /* x < 0 */
00063            if(hy>=0||(ix>>23)>(iy>>20)-0x380
00064               || ((ix>>23)==(iy>>20)-0x380
00065                  && (ix&0x7fffff)>(((hy<<3)|(ly>>29))&0x7fffff)))     /* x < y, x -= ulp */
00066               hx -= 1;
00067            else                           /* x > y, x += ulp */
00068               hx += 1;
00069        }
00070        hy = hx&0x7f800000;
00071        if(hy>=0x7f800000) {
00072          x = x+x;    /* overflow  */
00073          if (FLT_EVAL_METHOD != 0)
00074            /* Force conversion to float.  */
00075            asm ("" : "+m"(x));
00076          return x;
00077        }
00078        if(hy<0x00800000) {
00079            float u = x*x;                 /* underflow */
00080            math_force_eval (u);           /* raise underflow flag */
00081        }
00082        SET_FLOAT_WORD(x,hx);
00083        return x;
00084 }
00085 weak_alias (__nexttowardf, nexttowardf)