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
__aconvert(double arg,int ndigits,int * exp,int * sign,char * buf)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
__qaconvert(long double * arg,int ndigits,int * exp,int * sign,char * buf)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
__qaconvert(long double * arg,int ndigits,int * exp,int * sign,char * buf)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
__aconvert(double arg,int ndigits,int * exp,int * sign,char * buf)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