xref: /illumos-gate/usr/src/lib/libc/port/fp/hex_bin.c (revision 9ec394dbf343c1f23c6e13c39df427f238e5a369)
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 
32 /* conversion from hex chars to hex values */
33 #define	HEXVAL(c)	(('0' <= c && c <= '9')? c - '0' : \
34 			10 + (('a' <= c && c <= 'f')? c - 'a' : c - 'A'))
35 
36 /*
37  * Convert a hexadecimal record in *pd to unpacked form in *pu.
38  *
39  * Up to 30 hexadecimal digits from pd->ds are converted to a binary
40  * value in px->significand, which is then normalized so that the most
41  * significant bit is 1.  If there are additional, unused digits in
42  * pd->ds, the least significant bit of px->significand will be set.
43  */
44 static void
45 __hex_to_unpacked(decimal_record *pd, unpacked *pu)
46 {
47 	int	i, n;
48 
49 	pu->sign = pd->sign;
50 	pu->fpclass = pd->fpclass;
51 
52 	/*
53 	 * Adjust the (base two) exponent to reflect the fact that the
54 	 * radix point in *pd lies to the right of the last (base sixteen)
55 	 * digit while the radix point in *pu lies to the right of the
56 	 * most significant bit.
57 	 */
58 	pu->exponent = pd->exponent + (pd->ndigits << 2) - 1;
59 
60 	/* fill in the significand */
61 	for (i = 0; i < 5; i++)
62 		pu->significand[i] = 0;
63 
64 	n = pd->ndigits;
65 	if (n > 30)
66 		n = 30;
67 	for (i = 0; i < n; i++) {
68 		pu->significand[i >> 3] |= HEXVAL(pd->ds[i]) <<
69 		    ((7 - (i & 7)) << 2);
70 	}
71 
72 	/* sanity check */
73 	if (pu->significand[0] == 0) {
74 		pu->fpclass = fp_zero;
75 		return;
76 	}
77 
78 	/* normalize so the most significant bit is set */
79 	while (pu->significand[0] < 0x80000000u) {
80 		pu->significand[0] = (pu->significand[0] << 1) |
81 		    (pu->significand[1] >> 31);
82 		pu->significand[1] = (pu->significand[1] << 1) |
83 		    (pu->significand[2] >> 31);
84 		pu->significand[2] = (pu->significand[2] << 1) |
85 		    (pu->significand[3] >> 31);
86 		pu->significand[3] <<= 1;
87 		pu->exponent--;
88 	}
89 
90 	/* if there are any unused digits, set a sticky bit */
91 	if (pd->ndigits > 30 || pd->more)
92 		pu->significand[4] = 1;
93 }
94 
95 /*
96  * The following routines convert the hexadecimal value encoded in the
97  * decimal record *pd to a floating point value *px observing the round-
98  * ing mode specified in rd and passing back any exceptions raised via
99  * *ps.
100  *
101  * These routines assume pd->fpclass is either fp_zero or fp_normal.
102  * If pd->fpclass is fp_zero, *px is set to zero with the sign indicated
103  * by pd->sign and no exceptions are raised.  Otherwise, pd->ds must
104  * contain a string of hexadecimal digits of length pd->ndigits > 0, and
105  * the first digit must be nonzero.  Let m be the integer represented by
106  * this string.  Then *px is set to a correctly rounded approximation to
107  *
108  *  (-1)^(pd->sign) * m * 2^(pd->exponent)
109  *
110  * with inexact, underflow, and/or overflow raised as appropriate.
111  */
112 
113 void
114 __hex_to_single(decimal_record *pd, enum fp_direction_type rd, single *px,
115     fp_exception_field_type *ps)
116 {
117 	single_equivalence	kluge;
118 	unpacked		u;
119 
120 	*ps = 0;
121 	if (pd->fpclass == fp_zero) {
122 		kluge.f.msw.sign = pd->sign? 1 : 0;
123 		kluge.f.msw.exponent = 0;
124 		kluge.f.msw.significand = 0;
125 		*px = kluge.x;
126 	} else {
127 		__hex_to_unpacked(pd, &u);
128 		__pack_single(&u, px, rd, ps);
129 		if (*ps != 0)
130 			__base_conversion_set_exception(*ps);
131 	}
132 }
133 
134 void
135 __hex_to_double(decimal_record *pd, enum fp_direction_type rd, double *px,
136     fp_exception_field_type *ps)
137 {
138 	double_equivalence	kluge;
139 	unpacked		u;
140 
141 	*ps = 0;
142 	if (pd->fpclass == fp_zero) {
143 		kluge.f.msw.sign = pd->sign? 1 : 0;
144 		kluge.f.msw.exponent = 0;
145 		kluge.f.msw.significand = 0;
146 		kluge.f.significand2 = 0;
147 		*px = kluge.x;
148 	} else {
149 		__hex_to_unpacked(pd, &u);
150 		__pack_double(&u, px, rd, ps);
151 		if (*ps != 0)
152 			__base_conversion_set_exception(*ps);
153 	}
154 }
155 
156 #if defined(__sparc)
157 
158 void
159 __hex_to_quadruple(decimal_record *pd, enum fp_direction_type rd, quadruple *px,
160     fp_exception_field_type *ps)
161 {
162 	quadruple_equivalence	kluge;
163 	unpacked		u;
164 
165 	*ps = 0;
166 	if (pd->fpclass == fp_zero) {
167 		kluge.f.msw.sign = pd->sign? 1 : 0;
168 		kluge.f.msw.exponent = 0;
169 		kluge.f.msw.significand = 0;
170 		kluge.f.significand2 = 0;
171 		kluge.f.significand3 = 0;
172 		kluge.f.significand4 = 0;
173 		*px = kluge.x;
174 	} else {
175 		__hex_to_unpacked(pd, &u);
176 		__pack_quadruple(&u, px, rd, ps);
177 		if (*ps != 0)
178 			__base_conversion_set_exception(*ps);
179 	}
180 }
181 
182 #elif defined(__i386) || defined(__amd64)
183 
184 void
185 __hex_to_extended(decimal_record *pd, enum fp_direction_type rd, extended *px,
186     fp_exception_field_type *ps)
187 {
188 	extended_equivalence	kluge;
189 	unpacked		u;
190 
191 	*ps = 0;
192 	if (pd->fpclass == fp_zero) {
193 		kluge.f.msw.sign = pd->sign? 1 : 0;
194 		kluge.f.msw.exponent = 0;
195 		kluge.f.significand = 0;
196 		kluge.f.significand2 = 0;
197 		(*px)[0] = kluge.x[0];
198 		(*px)[1] = kluge.x[1];
199 		(*px)[2] = kluge.x[2];
200 	} else {
201 		__hex_to_unpacked(pd, &u);
202 		__pack_extended(&u, px, rd, ps);
203 		if (*ps != 0)
204 			__base_conversion_set_exception(*ps);
205 	}
206 }
207 
208 #else
209 #error Unknown architecture
210 #endif
211