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 nearbyintl = __nearbyintl 31 32 #include "libm.h" 33 #include "fma.h" 34 #include "fenv_inlines.h" 35 36 #if defined(__sparc) 37 38 static union { 39 unsigned i; 40 float f; 41 } snan = { 0x7f800001 }; 42 43 long double 44 __nearbyintl(long double x) { 45 union { 46 unsigned i[4]; 47 long double q; 48 } xx; 49 unsigned hx, sx, i, frac; 50 unsigned int fsr; 51 int rm, j; 52 volatile float dummy; 53 54 xx.q = x; 55 sx = xx.i[0] & 0x80000000; 56 hx = xx.i[0] & ~0x80000000; 57 58 /* handle trivial cases */ 59 if (hx >= 0x406f0000) { /* x is nan, inf, or already integral */ 60 /* check for signaling nan */ 61 if ((hx > 0x7fff0000 || (hx == 0x7fff0000 && 62 (xx.i[1] | xx.i[2] | xx.i[3]))) && !(hx & 0x8000)) { 63 dummy = snan.f; 64 dummy += snan.f; 65 xx.i[0] = sx | hx | 0x8000; 66 } 67 return (xx.q); 68 } else if ((hx | xx.i[1] | xx.i[2] | xx.i[3]) == 0) /* x is zero */ 69 return (x); 70 71 /* get the rounding mode */ 72 __fenv_getfsr32(&fsr); 73 rm = fsr >> 30; 74 75 /* flip the sense of directed roundings if x is negative */ 76 if (sx) 77 rm ^= rm >> 1; 78 79 /* handle |x| < 1 */ 80 if (hx < 0x3fff0000) { 81 if (rm == FSR_RP || (rm == FSR_RN && (hx >= 0x3ffe0000 && 82 ((hx & 0xffff) | xx.i[1] | xx.i[2] | xx.i[3])))) 83 xx.i[0] = sx | 0x3fff0000; 84 else 85 xx.i[0] = sx; 86 xx.i[1] = xx.i[2] = xx.i[3] = 0; 87 return (xx.q); 88 } 89 90 /* round x at the integer bit */ 91 j = 0x406f - (hx >> 16); 92 if (j >= 96) { 93 i = 1 << (j - 96); 94 frac = ((xx.i[0] << 1) << (127 - j)) | (xx.i[1] >> (j - 96)); 95 if ((xx.i[1] & (i - 1)) | xx.i[2] | xx.i[3]) 96 frac |= 1; 97 if (!frac) 98 return (x); 99 xx.i[1] = xx.i[2] = xx.i[3] = 0; 100 xx.i[0] &= ~(i - 1); 101 if (rm == FSR_RP || (rm == FSR_RN && (frac > 0x80000000u || 102 (frac == 0x80000000 && (xx.i[0] & i))))) 103 xx.i[0] += i; 104 } else if (j >= 64) { 105 i = 1 << (j - 64); 106 frac = ((xx.i[1] << 1) << (95 - j)) | (xx.i[2] >> (j - 64)); 107 if ((xx.i[2] & (i - 1)) | xx.i[3]) 108 frac |= 1; 109 if (!frac) 110 return (x); 111 xx.i[2] = xx.i[3] = 0; 112 xx.i[1] &= ~(i - 1); 113 if (rm == FSR_RP || (rm == FSR_RN && (frac > 0x80000000u || 114 (frac == 0x80000000 && (xx.i[1] & i))))) { 115 xx.i[1] += i; 116 if (xx.i[1] == 0) 117 xx.i[0]++; 118 } 119 } else if (j >= 32) { 120 i = 1 << (j - 32); 121 frac = ((xx.i[2] << 1) << (63 - j)) | (xx.i[3] >> (j - 32)); 122 if (xx.i[3] & (i - 1)) 123 frac |= 1; 124 if (!frac) 125 return (x); 126 xx.i[3] = 0; 127 xx.i[2] &= ~(i - 1); 128 if (rm == FSR_RP || (rm == FSR_RN && (frac > 0x80000000u || 129 (frac == 0x80000000 && (xx.i[2] & i))))) { 130 xx.i[2] += i; 131 if (xx.i[2] == 0) 132 if (++xx.i[1] == 0) 133 xx.i[0]++; 134 } 135 } else { 136 i = 1 << j; 137 frac = (xx.i[3] << 1) << (31 - j); 138 if (!frac) 139 return (x); 140 xx.i[3] &= ~(i - 1); 141 if (rm == FSR_RP || (rm == FSR_RN && (frac > 0x80000000u || 142 (frac == 0x80000000 && (xx.i[3] & i))))) { 143 xx.i[3] += i; 144 if (xx.i[3] == 0) 145 if (++xx.i[2] == 0) 146 if (++xx.i[1] == 0) 147 xx.i[0]++; 148 } 149 } 150 151 return (xx.q); 152 } 153 154 #elif defined(__x86) 155 156 /* inline template */ 157 extern long double frndint(long double); 158 159 long double 160 __nearbyintl(long double x) { 161 long double z; 162 unsigned oldcwsw, cwsw; 163 164 /* save the control and status words, mask the inexact exception */ 165 __fenv_getcwsw(&oldcwsw); 166 cwsw = oldcwsw | 0x00200000; 167 __fenv_setcwsw(&cwsw); 168 169 z = frndint(x); 170 171 /* 172 * restore the control and status words, preserving all but the 173 * inexact flag 174 */ 175 __fenv_getcwsw(&cwsw); 176 oldcwsw |= (cwsw & 0x1f); 177 __fenv_setcwsw(&oldcwsw); 178 179 return (z); 180 } 181 182 #else 183 #error Unknown architecture 184 #endif