xref: /illumos-gate/usr/src/lib/libc/port/fp/econvert.c (revision 24da5b34f49324ed742a340010ed5bd3d4e06625)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 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 #pragma weak econvert = _econvert
30 #pragma weak seconvert = _seconvert
31 #pragma weak qeconvert = _qeconvert
32 
33 #include "synonyms.h"
34 #include "base_conversion.h"
35 #include <string.h>
36 #include <sys/types.h>
37 #include "libc.h"
38 
39 /*
40  * Copies the appropriate string for a datum of class cl into *buf,
41  * choosing "Inf" or "Infinity" according to ndigits, the desired
42  * output string length.
43  */
44 void
45 __infnanstring(enum fp_class_type cl, int ndigits, char *buf)
46 {
47 	if (cl == fp_infinity) {
48 		if (ndigits < 8)
49 			(void) memcpy(buf, "Inf", 4);
50 		else
51 			(void) memcpy(buf, "Infinity", 9);
52 		__inf_written = 1;
53 	} else {
54 		(void) memcpy(buf, "NaN", 4);
55 		__nan_written = 1;
56 	}
57 }
58 
59 char *
60 econvert(double arg, int ndigits, int *decpt, int *sign, char *buf)
61 {
62 	decimal_mode    dm;
63 	decimal_record  dr;
64 	fp_exception_field_type ef;
65 	int		i;
66 
67 #if defined(__sparc)
68 	dm.rd = _QgetRD();
69 #elif defined(__i386) || defined(__amd64)
70 	dm.rd = __xgetRD();
71 #else
72 #error Unknown architecture
73 #endif
74 	dm.df = floating_form;	/* E format. */
75 	if (ndigits <= 0)
76 		ndigits = 1;
77 	else if (ndigits >= DECIMAL_STRING_LENGTH)
78 		ndigits = DECIMAL_STRING_LENGTH - 1;
79 	dm.ndigits = ndigits;	/* Number of significant digits. */
80 	double_to_decimal(&arg, &dm, &dr, &ef);
81 	*sign = dr.sign;
82 	switch (dr.fpclass) {
83 	case fp_normal:
84 	case fp_subnormal:
85 		*decpt = dr.exponent + ndigits;
86 		for (i = 0; i < ndigits; i++)
87 			buf[i] = dr.ds[i];
88 		buf[ndigits] = 0;
89 		break;
90 	case fp_zero:
91 		*decpt = 1;
92 		for (i = 0; i < ndigits; i++)
93 			buf[i] = '0';
94 		buf[ndigits] = 0;
95 		break;
96 	default:
97 		*decpt = 0;
98 		__infnanstring(dr.fpclass, ndigits, buf);
99 		break;
100 	}
101 	return (buf);
102 }
103 
104 char *
105 seconvert(single *arg, int ndigits, int *decpt, int *sign, char *buf)
106 {
107 	decimal_mode    dm;
108 	decimal_record  dr;
109 	fp_exception_field_type ef;
110 	int		i;
111 
112 #if defined(__sparc)
113 	dm.rd = _QgetRD();
114 #elif defined(__i386) || defined(__amd64)
115 	dm.rd = __xgetRD();
116 #else
117 #error Unknown architecture
118 #endif
119 	dm.df = floating_form;	/* E format. */
120 	if (ndigits <= 0)
121 		ndigits = 1;
122 	else if (ndigits >= DECIMAL_STRING_LENGTH)
123 		ndigits = DECIMAL_STRING_LENGTH - 1;
124 	dm.ndigits = ndigits;	/* Number of significant digits. */
125 	single_to_decimal(arg, &dm, &dr, &ef);
126 	*sign = dr.sign;
127 	switch (dr.fpclass) {
128 	case fp_normal:
129 	case fp_subnormal:
130 		*decpt = dr.exponent + ndigits;
131 		for (i = 0; i < ndigits; i++)
132 			buf[i] = dr.ds[i];
133 		buf[ndigits] = 0;
134 		break;
135 	case fp_zero:
136 		*decpt = 1;
137 		for (i = 0; i < ndigits; i++)
138 			buf[i] = '0';
139 		buf[ndigits] = 0;
140 		break;
141 	default:
142 		*decpt = 0;
143 		__infnanstring(dr.fpclass, ndigits, buf);
144 		break;
145 	}
146 	return (buf);
147 }
148 
149 char *
150 qeconvert(quadruple *arg, int ndigits, int *decpt, int *sign, char *buf)
151 {
152 	decimal_mode	dm;
153 	decimal_record	dr;
154 	fp_exception_field_type ef;
155 	int		i;
156 
157 #if defined(__sparc)
158 	dm.rd = _QgetRD();
159 #elif defined(__i386) || defined(__amd64)
160 	dm.rd = __xgetRD();
161 #else
162 #error Unknown architecture
163 #endif
164 	dm.df = floating_form;	/* E format. */
165 	if (ndigits <= 0)
166 		ndigits = 1;
167 	else if (ndigits >= DECIMAL_STRING_LENGTH)
168 		ndigits = DECIMAL_STRING_LENGTH - 1;
169 	dm.ndigits = ndigits;	/* Number of significant digits. */
170 #if defined(__sparc)
171 	quadruple_to_decimal(arg, &dm, &dr, &ef);
172 #elif defined(__i386) || defined(__amd64)
173 	extended_to_decimal((extended *)arg, &dm, &dr, &ef);
174 #else
175 #error Unknown architecture
176 #endif
177 	*sign = dr.sign;
178 	switch (dr.fpclass) {
179 	case fp_normal:
180 	case fp_subnormal:
181 		*decpt = dr.exponent + ndigits;
182 		for (i = 0; i < ndigits; i++)
183 			buf[i] = dr.ds[i];
184 		buf[ndigits] = 0;
185 		break;
186 	case fp_zero:
187 		*decpt = 1;
188 		for (i = 0; i < ndigits; i++)
189 			buf[i] = '0';
190 		buf[ndigits] = 0;
191 		break;
192 	default:
193 		*decpt = 0;
194 		__infnanstring(dr.fpclass, ndigits, buf);
195 		break;
196 	}
197 	return (buf);
198 }
199