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