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