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