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 nexttowardf = __nexttowardf 32 #endif 33 34 #include "libm.h" 35 36 static union { 37 unsigned i; 38 float f; 39 } C[] = { 40 0x00800000, 41 0x7f000000, 42 0x7fffffff 43 }; 44 45 #define tiny C[0].f 46 #define huge C[1].f 47 #define qnan C[2].f 48 49 #if defined(__sparc) 50 51 enum fcc_type { 52 fcc_equal = 0, 53 fcc_less = 1, 54 fcc_greater = 2, 55 fcc_unordered = 3 56 }; 57 58 #ifdef __sparcv9 59 #define _Q_cmp _Qp_cmp 60 #endif 61 62 extern enum fcc_type _Q_cmp(const long double *, const long double *); 63 64 float 65 __nexttowardf(float x, long double y) { 66 union { 67 unsigned i; 68 float f; 69 } xx; 70 union { 71 unsigned i[4]; 72 long double q; 73 } yy; 74 long double lx; 75 unsigned hx; 76 volatile float dummy; 77 enum fcc_type rel; 78 79 /* 80 * It would be somewhat more efficient to check for NaN and 81 * zero operands before converting x to long double and then 82 * to code the comparison in line rather than calling _Q_cmp. 83 * However, since this code probably won't get used much, 84 * I'm opting in favor of simplicity instead. 85 */ 86 lx = xx.f = x; 87 hx = xx.i & ~0x80000000; 88 89 /* check for each of four possible orderings */ 90 rel = _Q_cmp(&lx, &y); 91 if (rel == fcc_unordered) 92 return (qnan); 93 94 if (rel == fcc_equal) { 95 if (hx == 0) { /* x is zero; return zero with y's sign */ 96 yy.q = y; 97 xx.i = yy.i[0]; 98 return (xx.f); 99 } 100 return (x); 101 } 102 103 if (rel == fcc_less) { 104 if (hx == 0) /* x is zero */ 105 xx.i = 0x00000001; 106 else if ((int) xx.i >= 0) /* x is positive */ 107 xx.i++; 108 else 109 xx.i--; 110 } else { 111 if (hx == 0) /* x is zero */ 112 xx.i = 0x80000001; 113 else if ((int) xx.i >= 0) /* x is positive */ 114 xx.i--; 115 else 116 xx.i++; 117 } 118 119 /* raise exceptions as needed */ 120 hx = xx.i & ~0x80000000; 121 if (hx == 0x7f800000) { 122 dummy = huge; 123 dummy *= huge; 124 } else if (hx < 0x00800000) { 125 dummy = tiny; 126 dummy *= tiny; 127 } 128 129 return (xx.f); 130 } 131 132 #elif defined(__x86) 133 134 float 135 __nexttowardf(float x, long double y) { 136 union { 137 unsigned i; 138 float f; 139 } xx; 140 unsigned hx; 141 long double lx; 142 volatile float dummy; 143 144 lx = xx.f = x; 145 hx = xx.i & ~0x80000000; 146 147 /* check for each of four possible orderings */ 148 if (isunordered(lx, y)) 149 return ((float) (lx + y)); 150 151 if (lx == y) 152 return ((float) y); 153 154 if (lx < y) { 155 if (hx == 0) /* x is zero */ 156 xx.i = 0x00000001; 157 else if ((int) xx.i >= 0) /* x is positive */ 158 xx.i++; 159 else 160 xx.i--; 161 } else { 162 if (hx == 0) /* x is zero */ 163 xx.i = 0x80000001; 164 else if ((int) xx.i >= 0) /* x is positive */ 165 xx.i--; 166 else 167 xx.i++; 168 } 169 170 /* raise exceptions as needed */ 171 hx = xx.i & ~0x80000000; 172 if (hx == 0x7f800000) { 173 dummy = huge; 174 dummy *= huge; 175 } else if (hx < 0x00800000) { 176 dummy = tiny; 177 dummy *= tiny; 178 } 179 180 return (xx.f); 181 } 182 183 #else 184 #error Unknown architecture 185 #endif 186