1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24 */ 25 /* 26 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 */ 29 30 #if defined(ELFOBJ) 31 #pragma weak nexttoward = __nexttoward 32 #endif 33 34 /* 35 * nexttoward(x, y) delivers the next representable number after x 36 * in the direction of y. If x and y are both zero, the result is 37 * zero with the same sign as y. If either x or y is NaN, the result 38 * is NaN. 39 * 40 * If x != y and the result is infinite, overflow is raised; if 41 * x != y and the result is subnormal or zero, underflow is raised. 42 * (This is wrong, but it's what C99 apparently wants.) 43 */ 44 45 #include "libm.h" 46 47 #if defined(__sparc) 48 49 static union { 50 unsigned i[2]; 51 double d; 52 } C[] = { 53 0x00100000, 0, 54 0x7fe00000, 0, 55 0x7fffffff, 0xffffffff 56 }; 57 58 #define tiny C[0].d 59 #define huge C[1].d 60 #define qnan C[2].d 61 62 enum fcc_type { 63 fcc_equal = 0, 64 fcc_less = 1, 65 fcc_greater = 2, 66 fcc_unordered = 3 67 }; 68 69 #ifdef __sparcv9 70 #define _Q_cmp _Qp_cmp 71 #endif 72 73 extern enum fcc_type _Q_cmp(const long double *, const long double *); 74 75 double 76 __nexttoward(double x, long double y) { 77 union { 78 unsigned i[2]; 79 double d; 80 } xx; 81 union { 82 unsigned i[4]; 83 long double q; 84 } yy; 85 long double lx; 86 unsigned hx; 87 volatile double dummy; 88 enum fcc_type rel; 89 90 /* 91 * It would be somewhat more efficient to check for NaN and 92 * zero operands before converting x to long double and then 93 * to code the comparison in line rather than calling _Q_cmp. 94 * However, since this code probably won't get used much, 95 * I'm opting in favor of simplicity instead. 96 */ 97 lx = xx.d = x; 98 hx = (xx.i[0] & ~0x80000000) | xx.i[1]; 99 100 /* check for each of four possible orderings */ 101 rel = _Q_cmp(&lx, &y); 102 if (rel == fcc_unordered) 103 return (qnan); 104 105 if (rel == fcc_equal) { 106 if (hx == 0) { /* x is zero; return zero with y's sign */ 107 yy.q = y; 108 xx.i[0] = yy.i[0]; 109 return (xx.d); 110 } 111 return (x); 112 } 113 114 if (rel == fcc_less) { 115 if (hx == 0) { /* x is zero */ 116 xx.i[0] = 0; 117 xx.i[1] = 0x00000001; 118 } else if ((int)xx.i[0] >= 0) { /* x is positive */ 119 if (++xx.i[1] == 0) 120 xx.i[0]++; 121 } else { 122 if (xx.i[1]-- == 0) 123 xx.i[0]--; 124 } 125 } else { 126 if (hx == 0) { /* x is zero */ 127 xx.i[0] = 0x80000000; 128 xx.i[1] = 0x00000001; 129 } else if ((int)xx.i[0] >= 0) { /* x is positive */ 130 if (xx.i[1]-- == 0) 131 xx.i[0]--; 132 } else { 133 if (++xx.i[1] == 0) 134 xx.i[0]++; 135 } 136 } 137 138 /* raise exceptions as needed */ 139 hx = xx.i[0] & ~0x80000000; 140 if (hx == 0x7ff00000) { 141 dummy = huge; 142 dummy *= huge; 143 } else if (hx < 0x00100000) { 144 dummy = tiny; 145 dummy *= tiny; 146 } 147 148 return (xx.d); 149 } 150 151 #elif defined(__x86) 152 153 static union { 154 unsigned i[2]; 155 double d; 156 } C[] = { 157 0, 0x00100000, 158 0, 0x7fe00000, 159 }; 160 161 #define tiny C[0].d 162 #define huge C[1].d 163 164 double 165 __nexttoward(double x, long double y) { 166 union { 167 unsigned i[2]; 168 double d; 169 } xx; 170 unsigned hx; 171 long double lx; 172 volatile double dummy; 173 174 lx = xx.d = x; 175 hx = (xx.i[1] & ~0x80000000) | xx.i[0]; 176 177 /* check for each of four possible orderings */ 178 if (isunordered(lx, y)) 179 return ((double) (lx + y)); 180 181 if (lx == y) 182 return ((double) y); 183 184 if (lx < y) { 185 if (hx == 0) { /* x is zero */ 186 xx.i[0] = 0x00000001; 187 xx.i[1] = 0; 188 } else if ((int)xx.i[1] >= 0) { /* x is positive */ 189 if (++xx.i[0] == 0) 190 xx.i[1]++; 191 } else { 192 if (xx.i[0]-- == 0) 193 xx.i[1]--; 194 } 195 } else { 196 if (hx == 0) { /* x is zero */ 197 xx.i[0] = 0x00000001; 198 xx.i[1] = 0x80000000; 199 } else if ((int)xx.i[1] >= 0) { /* x is positive */ 200 if (xx.i[0]-- == 0) 201 xx.i[1]--; 202 } else { 203 if (++xx.i[0] == 0) 204 xx.i[1]++; 205 } 206 } 207 208 /* raise exceptions as needed */ 209 hx = xx.i[1] & ~0x80000000; 210 if (hx == 0x7ff00000) { 211 dummy = huge; 212 dummy *= huge; 213 } else if (hx < 0x00100000) { 214 dummy = tiny; 215 dummy *= tiny; 216 } 217 218 return (xx.d); 219 } 220 221 #else 222 #error Unknown architecture 223 #endif