1 /* s_nexttowardf.c -- float version of s_nextafter.c.
2 * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com
3 * and Jakub Jelinek, jj@ultra.linux.cz.
4 */
5
6 /*
7 * ====================================================
8 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
9 *
10 * Developed at SunPro, a Sun Microsystems, Inc. business.
11 * Permission to use, copy, modify, and distribute this
12 * software is freely granted, provided that this notice
13 * is preserved.
14 * ====================================================
15 */
16
17 #if defined(LIBM_SCCS) && !defined(lint)
18 static char rcsid[] = "$NetBSD: $";
19 #endif
20
21 #include <errno.h>
22 #include <math.h>
23 #include <math-barriers.h>
24 #include <math_private.h>
25 #include <math_ldbl_opt.h>
26 #include <float.h>
27
__nexttowardf(float x,long double y)28 float __nexttowardf(float x, long double y)
29 {
30 int32_t hx,ix;
31 int64_t hy,iy;
32 double yhi;
33
34 GET_FLOAT_WORD(hx,x);
35 yhi = ldbl_high (y);
36 EXTRACT_WORDS64 (hy, yhi);
37 ix = hx&0x7fffffff; /* |x| */
38 iy = hy&0x7fffffffffffffffLL; /* |y| */
39
40 if((ix>0x7f800000) || /* x is nan */
41 (iy>0x7ff0000000000000LL))
42 /* y is nan */
43 return x+y;
44 if((long double) x==y) return y; /* x=y, return y */
45 if(ix==0) { /* x == 0 */
46 float u;
47 SET_FLOAT_WORD(x,(uint32_t)((hy>>32)&0x80000000)|1);/* return +-minsub*/
48 u = math_opt_barrier (x);
49 u = u * u;
50 math_force_eval (u); /* raise underflow flag */
51 return x;
52 }
53 if(hx>=0) { /* x > 0 */
54 if(x > y) { /* x -= ulp */
55 hx -= 1;
56 } else { /* x < y, x += ulp */
57 hx += 1;
58 }
59 } else { /* x < 0 */
60 if(x < y) { /* x -= ulp */
61 hx -= 1;
62 } else { /* x > y, x += ulp */
63 hx += 1;
64 }
65 }
66 hy = hx&0x7f800000;
67 if(hy>=0x7f800000) {
68 float u = x+x; /* overflow */
69 math_force_eval (u);
70 __set_errno (ERANGE);
71 }
72 if(hy<0x00800000) { /* underflow */
73 float u = x*x;
74 math_force_eval (u); /* raise underflow flag */
75 __set_errno (ERANGE);
76 }
77 SET_FLOAT_WORD(x,hx);
78 return x;
79 }
80 long_double_symbol (libm, __nexttowardf, nexttowardf);
81