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 nearbyintf = __nearbyintf 32 #endif 33 34 #include "libm.h" 35 #include "fenv_synonyms.h" 36 #include <fenv.h> 37 38 float 39 __nearbyintf(float x) { 40 union { 41 unsigned i; 42 float f; 43 } xx; 44 unsigned hx, sx, i, frac; 45 int rm; 46 47 xx.f = x; 48 sx = xx.i & 0x80000000; 49 hx = xx.i & ~0x80000000; 50 51 /* handle trivial cases */ 52 if (hx >= 0x4b000000) { /* x is nan, inf, or already integral */ 53 if (hx > 0x7f800000) /* x is nan */ 54 return (x * x); /* + -> * for Cheetah */ 55 return (x); 56 } else if (hx == 0) /* x is zero */ 57 return (x); 58 59 /* get the rounding mode */ 60 rm = fegetround(); 61 62 /* flip the sense of directed roundings if x is negative */ 63 if (sx && (rm == FE_UPWARD || rm == FE_DOWNWARD)) 64 rm = (FE_UPWARD + FE_DOWNWARD) - rm; 65 66 /* handle |x| < 1 */ 67 if (hx < 0x3f800000) { 68 if (rm == FE_UPWARD || (rm == FE_TONEAREST && hx > 0x3f000000)) 69 xx.i = sx | 0x3f800000; 70 else 71 xx.i = sx; 72 return (xx.f); 73 } 74 75 /* round x at the integer bit */ 76 i = 1 << (0x96 - (hx >> 23)); 77 frac = hx & (i - 1); 78 if (!frac) 79 return (x); 80 81 hx &= ~(i - 1); 82 if (rm == FE_UPWARD || (rm == FE_TONEAREST && (frac > (i >> 1) || 83 ((frac == (i >> 1)) && (hx & i))))) 84 xx.i = sx | (hx + i); 85 else 86 xx.i = sx | hx; 87 return (xx.f); 88 } 89 90 #if 0 91 92 /* 93 * Alternate implementations for SPARC, x86, using fp ops. These may 94 * be faster depending on how expensive saving and restoring the fp 95 * modes and status flags is. 96 */ 97 98 #include "libm.h" 99 #include "fma.h" 100 101 #if defined(__sparc) 102 103 float 104 __nearbyintf(float x) { 105 union { 106 unsigned i; 107 float f; 108 } xx, yy; 109 float z; 110 unsigned hx, sx, fsr, oldfsr; 111 int rm; 112 113 xx.f = x; 114 sx = xx.i & 0x80000000; 115 hx = xx.i & ~0x80000000; 116 117 /* handle trivial cases */ 118 if (hx >= 0x4b000000) /* x is nan, inf, or already integral */ 119 return (x + 0.0f); 120 else if (hx == 0) /* x is zero */ 121 return (x); 122 123 /* save the fsr */ 124 __fenv_getfsr(&oldfsr); 125 126 /* handle |x| < 1 */ 127 if (hx < 0x3f800000) { 128 /* flip the sense of directed roundings if x is negative */ 129 rm = oldfsr >> 30; 130 if (sx) 131 rm ^= rm >> 1; 132 if (rm == FSR_RP || (rm == FSR_RN && hx > 0x3f000000)) 133 xx.i = sx | 0x3f800000; 134 else 135 xx.i = sx; 136 return (xx.f); 137 } 138 139 /* clear the inexact trap */ 140 fsr = oldfsr & ~FSR_NXM; 141 __fenv_setfsr(&fsr); 142 143 /* round x at the integer bit */ 144 yy.i = sx | 0x4b000000; 145 z = (x + yy.f) - yy.f; 146 147 /* restore the old fsr */ 148 __fenv_setfsr(&oldfsr); 149 150 return (z); 151 } 152 153 #elif defined(__x86) 154 155 /* inline template */ 156 extern long double frndint(long double); 157 158 float 159 __nearbyintf(float x) { 160 long double z; 161 unsigned oldcwsw, cwsw; 162 163 /* save the control and status words, mask the inexact exception */ 164 __fenv_getcwsw(&oldcwsw); 165 cwsw = oldcwsw | 0x00200000; 166 __fenv_setcwsw(&cwsw); 167 168 z = frndint((long double) x); 169 170 /* 171 * restore the control and status words, preserving all but the 172 * inexact flag 173 */ 174 __fenv_getcwsw(&cwsw); 175 oldcwsw |= (cwsw & 0x1f); 176 __fenv_setcwsw(&oldcwsw); 177 178 /* note: the value of z is representable in single precision */ 179 return (z); 180 } 181 182 #else 183 #error Unknown architecture 184 #endif 185 186 #endif