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