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 */
31static 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
55void
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
136void
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 */
293void
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
366void
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