xref: /illumos-gate/usr/src/lib/libc/port/fp/econvert.c (revision 1e56f352c1c208679012bca47d552e127f5b1072)
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 #include <string.h>
30 #include <sys/types.h>
31 #include "libc.h"
32 
33 /*
34  * Copies the appropriate string for a datum of class cl into *buf,
35  * choosing "Inf" or "Infinity" according to ndigits, the desired
36  * output string length.
37  */
38 void
39 __infnanstring(enum fp_class_type cl, int ndigits, char *buf)
40 {
41 	if (cl == fp_infinity) {
42 		if (ndigits < 8)
43 			(void) memcpy(buf, "Inf", 4);
44 		else
45 			(void) memcpy(buf, "Infinity", 9);
46 		__inf_written = 1;
47 	} else {
48 		(void) memcpy(buf, "NaN", 4);
49 		__nan_written = 1;
50 	}
51 }
52 
53 char *
54 econvert(double arg, int ndigits, int *decpt, int *sign, char *buf)
55 {
56 	decimal_mode    dm;
57 	decimal_record  dr;
58 	fp_exception_field_type ef;
59 	int		i;
60 
61 #if defined(__sparc)
62 	dm.rd = _QgetRD();
63 #elif defined(__i386) || defined(__amd64)
64 	dm.rd = __xgetRD();
65 #else
66 #error Unknown architecture
67 #endif
68 	dm.df = floating_form;	/* E format. */
69 	if (ndigits <= 0)
70 		ndigits = 1;
71 	else if (ndigits >= DECIMAL_STRING_LENGTH)
72 		ndigits = DECIMAL_STRING_LENGTH - 1;
73 	dm.ndigits = ndigits;	/* Number of significant digits. */
74 	double_to_decimal(&arg, &dm, &dr, &ef);
75 	*sign = dr.sign;
76 	switch (dr.fpclass) {
77 	case fp_normal:
78 	case fp_subnormal:
79 		*decpt = dr.exponent + ndigits;
80 		for (i = 0; i < ndigits; i++)
81 			buf[i] = dr.ds[i];
82 		buf[ndigits] = 0;
83 		break;
84 	case fp_zero:
85 		*decpt = 1;
86 		for (i = 0; i < ndigits; i++)
87 			buf[i] = '0';
88 		buf[ndigits] = 0;
89 		break;
90 	default:
91 		*decpt = 0;
92 		__infnanstring(dr.fpclass, ndigits, buf);
93 		break;
94 	}
95 	return (buf);
96 }
97 
98 char *
99 seconvert(single *arg, int ndigits, int *decpt, int *sign, char *buf)
100 {
101 	decimal_mode    dm;
102 	decimal_record  dr;
103 	fp_exception_field_type ef;
104 	int		i;
105 
106 #if defined(__sparc)
107 	dm.rd = _QgetRD();
108 #elif defined(__i386) || defined(__amd64)
109 	dm.rd = __xgetRD();
110 #else
111 #error Unknown architecture
112 #endif
113 	dm.df = floating_form;	/* E format. */
114 	if (ndigits <= 0)
115 		ndigits = 1;
116 	else if (ndigits >= DECIMAL_STRING_LENGTH)
117 		ndigits = DECIMAL_STRING_LENGTH - 1;
118 	dm.ndigits = ndigits;	/* Number of significant digits. */
119 	single_to_decimal(arg, &dm, &dr, &ef);
120 	*sign = dr.sign;
121 	switch (dr.fpclass) {
122 	case fp_normal:
123 	case fp_subnormal:
124 		*decpt = dr.exponent + ndigits;
125 		for (i = 0; i < ndigits; i++)
126 			buf[i] = dr.ds[i];
127 		buf[ndigits] = 0;
128 		break;
129 	case fp_zero:
130 		*decpt = 1;
131 		for (i = 0; i < ndigits; i++)
132 			buf[i] = '0';
133 		buf[ndigits] = 0;
134 		break;
135 	default:
136 		*decpt = 0;
137 		__infnanstring(dr.fpclass, ndigits, buf);
138 		break;
139 	}
140 	return (buf);
141 }
142 
143 char *
144 qeconvert(quadruple *arg, int ndigits, int *decpt, int *sign, char *buf)
145 {
146 	decimal_mode	dm;
147 	decimal_record	dr;
148 	fp_exception_field_type ef;
149 	int		i;
150 
151 #if defined(__sparc)
152 	dm.rd = _QgetRD();
153 #elif defined(__i386) || defined(__amd64)
154 	dm.rd = __xgetRD();
155 #else
156 #error Unknown architecture
157 #endif
158 	dm.df = floating_form;	/* E format. */
159 	if (ndigits <= 0)
160 		ndigits = 1;
161 	else if (ndigits >= DECIMAL_STRING_LENGTH)
162 		ndigits = DECIMAL_STRING_LENGTH - 1;
163 	dm.ndigits = ndigits;	/* Number of significant digits. */
164 #if defined(__sparc)
165 	quadruple_to_decimal(arg, &dm, &dr, &ef);
166 #elif defined(__i386) || defined(__amd64)
167 	extended_to_decimal((extended *)arg, &dm, &dr, &ef);
168 #else
169 #error Unknown architecture
170 #endif
171 	*sign = dr.sign;
172 	switch (dr.fpclass) {
173 	case fp_normal:
174 	case fp_subnormal:
175 		*decpt = dr.exponent + ndigits;
176 		for (i = 0; i < ndigits; i++)
177 			buf[i] = dr.ds[i];
178 		buf[ndigits] = 0;
179 		break;
180 	case fp_zero:
181 		*decpt = 1;
182 		for (i = 0; i < ndigits; i++)
183 			buf[i] = '0';
184 		buf[ndigits] = 0;
185 		break;
186 	default:
187 		*decpt = 0;
188 		__infnanstring(dr.fpclass, ndigits, buf);
189 		break;
190 	}
191 	return (buf);
192 }
193