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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include "lint.h" 28 #include "base_conversion.h" 29 30 /* translation table from hex values to hex chars */ 31 static const char *hexchar = "0123456789abcdef"; 32 33 /* 34 * Convert arg to a hexadecimal string. 35 * 36 * If arg is finite and nonzero, buf is filled with ndigits hexadecimal 37 * digits, representing the significand of arg, followed by a null byte 38 * (so ndigits must be at least 1 and buf must be large enough to hold 39 * ndigits + 1 characters). If ndigits is large enough, the representa- 40 * tion is exact; otherwise, the value is rounded according to the pre- 41 * vailing rounding mode to fit the requested number of digits. Either 42 * way, the result is normalized so that the first digit is '1'. The 43 * corresponding base two exponent is passed back in *exp. 44 * 45 * If arg is zero, buf is filled with ndigits zeros followed by a null, 46 * and *exp is set to zero. If arg is infinite or NaN, __infnanstring 47 * is called to place an appropriate string in buf, and *exp is set to 48 * zero. 49 * 50 * Regardless of the value of arg, its sign bit is stored in *sign. 51 */ 52 53 #if defined(__sparc) 54 55 void 56 __aconvert(double arg, int ndigits, int *exp, int *sign, char *buf) 57 { 58 union { 59 unsigned int i[2]; 60 long long l; 61 double d; 62 } a, c; 63 int ha, i, s; 64 unsigned int d; 65 66 a.d = arg; 67 *sign = s = a.i[0] >> 31; 68 ha = a.i[0] & ~0x80000000; 69 70 /* check for infinity or nan */ 71 if (ha >= 0x7ff00000) { 72 *exp = 0; 73 __infnanstring((ha == 0x7ff00000 && a.i[1] == 0)? 74 fp_infinity : fp_quiet, ndigits, buf); 75 return; 76 } 77 78 /* check for subnormal or zero */ 79 if (ha < 0x00100000) { 80 if ((ha | a.i[1]) == 0) { 81 *exp = 0; 82 for (i = 0; i < ndigits; i++) 83 buf[i] = '0'; 84 buf[ndigits] = '\0'; 85 return; 86 } 87 88 /* 89 * Normalize. It would be much simpler if we could just 90 * multiply by a power of two here, but some SPARC imple- 91 * mentations would flush the subnormal operand to zero 92 * when nonstandard mode is enabled. 93 */ 94 a.i[0] = ha; 95 a.d = (double)a.l; 96 if (s) 97 a.d = -a.d; 98 ha = a.i[0] & ~0x80000000; 99 *exp = (ha >> 20) - 0x3ff - 1074; 100 } else { 101 *exp = (ha >> 20) - 0x3ff; 102 } 103 104 if (ndigits < 14) { 105 /* 106 * Round the significand at the appropriate bit by adding 107 * and subtracting a power of two. This will also raise 108 * the inexact exception if anything is rounded off. 109 */ 110 c.i[0] = (0x43700000 | (s << 31)) - (ndigits << 22); 111 c.i[1] = 0; 112 a.i[0] = (a.i[0] & 0x800fffff) | 0x3ff00000; 113 a.d = (a.d + c.d) - c.d; 114 ha = a.i[0] & ~0x80000000; 115 if (ha >= 0x40000000) 116 (*exp)++; 117 } 118 119 /* convert to hex digits */ 120 buf[0] = '1'; 121 d = ha << 12; 122 for (i = 1; i < ndigits && i < 6; i++) { 123 buf[i] = hexchar[d >> 28]; 124 d <<= 4; 125 } 126 d = a.i[1]; 127 for (; i < ndigits && i < 14; i++) { 128 buf[i] = hexchar[d >> 28]; 129 d <<= 4; 130 } 131 for (; i < ndigits; i++) 132 buf[i] = '0'; 133 buf[ndigits] = '\0'; 134 } 135 136 void 137 __qaconvert(long double *arg, int ndigits, int *exp, int *sign, char *buf) 138 { 139 union { 140 unsigned int i[4]; 141 long double q; 142 } a; 143 enum fp_direction_type rd; 144 int ha, i, s; 145 unsigned int b, r, d; 146 147 a.q = *arg; 148 *sign = a.i[0] >> 31; 149 ha = a.i[0] &= ~0x80000000; 150 151 /* check for infinity or nan */ 152 if (ha >= 0x7fff0000) { 153 *exp = 0; 154 __infnanstring((ha == 0x7fff0000 && (a.i[1] | a.i[2] | a.i[3]) 155 == 0)? fp_infinity : fp_quiet, ndigits, buf); 156 return; 157 } 158 159 /* check for subnormal or zero */ 160 if (ha < 0x00010000) { 161 if ((ha | a.i[1] | a.i[2] | a.i[3]) == 0) { 162 *exp = 0; 163 for (i = 0; i < ndigits; i++) 164 buf[i] = '0'; 165 buf[ndigits] = '\0'; 166 return; 167 } 168 169 /* normalize */ 170 i = 0; 171 while ((a.i[0] | (a.i[1] & 0xffff0000)) == 0) { 172 a.i[0] = a.i[1]; 173 a.i[1] = a.i[2]; 174 a.i[2] = a.i[3]; 175 a.i[3] = 0; 176 i += 32; 177 } 178 while ((a.i[0] & 0x7fff0000) == 0) { 179 a.i[0] = (a.i[0] << 1) | (a.i[1] >> 31); 180 a.i[1] = (a.i[1] << 1) | (a.i[2] >> 31); 181 a.i[2] = (a.i[2] << 1) | (a.i[3] >> 31); 182 a.i[3] <<= 1; 183 i++; 184 } 185 *exp = -0x3ffe - i; 186 } else { 187 *exp = (ha >> 16) - 0x3fff; 188 } 189 190 if (ndigits < 29) { 191 /* 192 * Round the significand at the appropriate bit using 193 * integer arithmetic. Explicitly raise the inexact 194 * exception if anything is rounded off. 195 */ 196 a.i[0] = (a.i[0] & 0xffff) | 0x10000; 197 if (ndigits <= 5) { 198 /* 199 * i and b are the index and bit position in a.i[] 200 * of the last bit to be retained. r holds the bits 201 * to be rounded off, left-adjusted and sticky. 202 */ 203 i = 0; 204 s = (5 - ndigits) << 2; 205 b = 1 << s; 206 r = ((a.i[0] << 1) << (31 - s)) | (a.i[1] >> s); 207 if ((a.i[1] & (b - 1)) | a.i[2] | a.i[3]) 208 r |= 1; 209 a.i[0] &= ~(b - 1); 210 a.i[1] = a.i[2] = a.i[3] = 0; 211 } else if (ndigits <= 13) { 212 i = 1; 213 s = (13 - ndigits) << 2; 214 b = 1 << s; 215 r = ((a.i[1] << 1) << (31 - s)) | (a.i[2] >> s); 216 if ((a.i[2] & (b - 1)) | a.i[3]) 217 r |= 1; 218 a.i[1] &= ~(b - 1); 219 a.i[2] = a.i[3] = 0; 220 } else if (ndigits <= 21) { 221 i = 2; 222 s = (21 - ndigits) << 2; 223 b = 1 << s; 224 r = ((a.i[2] << 1) << (31 - s)) | (a.i[3] >> s); 225 if (a.i[3] & (b - 1)) 226 r |= 1; 227 a.i[2] &= ~(b - 1); 228 a.i[3] = 0; 229 } else { 230 i = 3; 231 s = (29 - ndigits) << 2; 232 b = 1 << s; 233 r = (a.i[3] << 1) << (31 - s); 234 a.i[3] &= ~(b - 1); 235 } 236 237 /* conversion is inexact if r is not zero */ 238 if (r) { 239 __base_conversion_set_exception( 240 (fp_exception_field_type)(1 << fp_inexact)); 241 242 /* massage the rounding direction based on the sign */ 243 rd = _QgetRD(); 244 if (*sign && (rd == fp_positive || rd == fp_negative)) 245 rd = fp_positive + fp_negative - rd; 246 247 /* decide whether to round up */ 248 if (rd == fp_positive || (rd == fp_nearest && 249 (r > 0x80000000u || (r == 0x80000000u && 250 (a.i[i] & b))))) { 251 a.i[i] += b; 252 while (a.i[i] == 0) 253 a.i[--i]++; 254 if (a.i[0] >= 0x20000) 255 (*exp)++; 256 } 257 } 258 } 259 260 /* convert to hex digits */ 261 buf[0] = '1'; 262 d = a.i[0] << 16; 263 for (i = 1; i < ndigits && i < 5; i++) { 264 buf[i] = hexchar[d >> 28]; 265 d <<= 4; 266 } 267 d = a.i[1]; 268 for (; i < ndigits && i < 13; i++) { 269 buf[i] = hexchar[d >> 28]; 270 d <<= 4; 271 } 272 d = a.i[2]; 273 for (; i < ndigits && i < 21; i++) { 274 buf[i] = hexchar[d >> 28]; 275 d <<= 4; 276 } 277 d = a.i[3]; 278 for (; i < ndigits && i < 29; i++) { 279 buf[i] = hexchar[d >> 28]; 280 d <<= 4; 281 } 282 for (; i < ndigits; i++) 283 buf[i] = '0'; 284 buf[ndigits] = '\0'; 285 } 286 287 #elif defined(__i386) || defined(__amd64) 288 289 /* 290 * The following code assumes the rounding precision mode is set 291 * to the default (round to 64 bits). 292 */ 293 void 294 __qaconvert(long double *arg, int ndigits, int *exp, int *sign, char *buf) 295 { 296 union { 297 unsigned int i[3]; 298 long double x; 299 } a, c; 300 int ea, i, s; 301 unsigned int d; 302 303 a.x = *arg; 304 *sign = s = (a.i[2] >> 15) & 1; 305 ea = a.i[2] & 0x7fff; 306 307 /* check for infinity or nan */ 308 if (ea == 0x7fff) { 309 *exp = 0; 310 __infnanstring((((a.i[1] << 1) | a.i[0]) == 0)? 311 fp_infinity : fp_quiet, ndigits, buf); 312 return; 313 } 314 315 /* check for subnormal or zero */ 316 if (ea == 0) { 317 if ((a.i[1] | a.i[0]) == 0) { 318 *exp = 0; 319 for (i = 0; i < ndigits; i++) 320 buf[i] = '0'; 321 buf[ndigits] = '\0'; 322 return; 323 } 324 325 /* normalize */ 326 a.x *= 18446744073709551616.0; /* 2^64 */ 327 ea = a.i[2] & 0x7fff; 328 *exp = ea - 0x403f; 329 } else { 330 *exp = ea - 0x3fff; 331 } 332 333 if (ndigits < 17) { 334 /* 335 * Round the significand at the appropriate bit by adding 336 * and subtracting a power of two. This will also raise 337 * the inexact exception if anything is rounded off. 338 */ 339 c.i[2] = (0x4042 | (s << 15)) - (ndigits << 2); 340 c.i[1] = 0x80000000; 341 c.i[0] = 0; 342 a.i[2] = 0x3fff | (s << 15); 343 a.x = (a.x + c.x) - c.x; 344 ea = a.i[2] & 0x7fff; 345 if (ea >= 0x4000) 346 (*exp)++; 347 } 348 349 /* convert to hex digits */ 350 buf[0] = '1'; 351 d = (a.i[1] << 1) | (a.i[0] >> 31); 352 for (i = 1; i < ndigits && i < 9; i++) { 353 buf[i] = hexchar[d >> 28]; 354 d <<= 4; 355 } 356 d = a.i[0] << 1; 357 for (; i < ndigits && i < 17; i++) { 358 buf[i] = hexchar[d >> 28]; 359 d <<= 4; 360 } 361 for (; i < ndigits; i++) 362 buf[i] = '0'; 363 buf[ndigits] = '\0'; 364 } 365 366 void 367 __aconvert(double arg, int ndigits, int *exp, int *sign, char *buf) 368 { 369 union { 370 int i[2]; 371 double d; 372 } a; 373 long double ldarg; 374 int ha; 375 376 /* avoid raising invalid operation exception for signaling nan */ 377 a.i[0] = *(int *)&arg; 378 a.i[1] = *(1+(int *)&arg); 379 ha = a.i[1] & ~0x80000000; 380 if (ha > 0x7ff00000 || (ha == 0x7ff00000 && a.i[0] != 0)) 381 a.i[1] |= 0x80000; /* make nan quiet */ 382 ldarg = a.d; 383 __qaconvert(&ldarg, ndigits, exp, sign, buf); 384 } 385 386 #else 387 #error Unknown architecture 388 #endif 389