Back to index

glibc  2.9
s_nexttowardfd.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  *     __nexttowardfd(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 different binary type for double and
00019  * long double conditionally, y is long double equal to double.
00020  *   Special cases:
00021  */
00022 
00023 #include <math.h>
00024 #include <math_private.h>
00025 #include <math_ldbl_opt.h>
00026 #include <float.h>
00027 
00028 float __nldbl_nexttowardf(float x, double y);
00029 
00030 float __nldbl_nexttowardf(float x, double y)
00031 {
00032        int32_t hx,hy,ix,iy;
00033        u_int32_t ly;
00034 
00035        GET_FLOAT_WORD(hx,x);
00036        EXTRACT_WORDS(hy,ly,y);
00037        ix = hx&0x7fffffff;         /* |x| */
00038        iy = hy&0x7fffffff;         /* |y| */
00039 
00040        if((ix>0x7f800000) ||                               /* x is nan */
00041           ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0))    /* y is nan */
00042           return x+y;
00043        if((double) x==y) return y;        /* x=y, return y */
00044        if(ix==0) {                        /* x == 0 */
00045            float u;
00046            SET_FLOAT_WORD(x,(u_int32_t)(hy&0x80000000)|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(hy<0||(ix>>23)>(iy>>20)-0x380
00054               || ((ix>>23)==(iy>>20)-0x380
00055                  && (ix&0x7fffff)>(((hy<<3)|(ly>>29))&0x7fffff)))     /* x > y, x -= ulp */
00056               hx -= 1;
00057            else                           /* x < y, x += ulp */
00058               hx += 1;
00059        } else {                           /* x < 0 */
00060            if(hy>=0||(ix>>23)>(iy>>20)-0x380
00061               || ((ix>>23)==(iy>>20)-0x380
00062                  && (ix&0x7fffff)>(((hy<<3)|(ly>>29))&0x7fffff)))     /* x < y, x -= ulp */
00063               hx -= 1;
00064            else                           /* x > y, x += ulp */
00065               hx += 1;
00066        }
00067        hy = hx&0x7f800000;
00068        if(hy>=0x7f800000) {
00069          x = x+x;    /* overflow  */
00070          if (FLT_EVAL_METHOD != 0)
00071            /* Force conversion to float.  */
00072            asm ("" : "+m"(x));
00073          return x;
00074        }
00075        if(hy<0x00800000) {
00076            float u = x*x;                 /* underflow */
00077            math_force_eval (u);           /* raise underflow flag */
00078        }
00079        SET_FLOAT_WORD(x,hx);
00080        return x;
00081 }
00082 
00083 #if LONG_DOUBLE_COMPAT(libm, GLIBC_2_1)
00084 compat_symbol (libm, __nldbl_nexttowardf, nexttowardf, GLIBC_2_1);
00085 #endif