xref: /titanic_50/usr/src/lib/libbc/libc/gen/common/_base_sup.c (revision 5d54f3d8999eac1762fe0a8c7177d20f1f201fae)
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 1988 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 "base_conversion.h"
30 
31 #ifdef DEBUG
32 
33 void
_display_big_float(_big_float * pbf,unsigned base)34 _display_big_float(_big_float *pbf, unsigned base)
35 {
36 	int             i;
37 
38 	for (i = 0; i < pbf->blength; i++) {
39 		switch (base) {
40 		case 2:
41 			printf(" + %d * 2** %d", pbf->bsignificand[i], (16 * i + pbf->bexponent));
42 			break;
43 		case 10:
44 			printf(" + %d * 10** %d", pbf->bsignificand[i], (4 * i + pbf->bexponent));
45 			break;
46 		}
47 		if ((i % 4) == 3)
48 			printf("\n");
49 	}
50 	printf("\n");
51 }
52 
53 #endif
54 
55 void
_integerstring_to_big_decimal(char ds[],unsigned ndigs,unsigned nzin,unsigned * pnzout,_big_float * pd)56 _integerstring_to_big_decimal(char ds[], unsigned ndigs, unsigned nzin,
57     unsigned *pnzout, _big_float *pd)
58 {
59 	/*
60 	 * Convert ndigs decimal digits from ds, and up to 3 trailing zeros,
61 	 * into a decimal big_float in *pd.  nzin tells how many implicit
62 	 * trailing zeros may be used, while *pnzout tells how many were
63 	 * actually absorbed.  Up to 3 are used if available so that
64 	 * (ndigs+*pnzout) % 4 = 0.
65 	 */
66 
67 	int             extras, taken, id, ids;
68 
69 #ifdef DEBUG
70 	printf(" _integerstring_to_big_decimal: ndigs %d nzin %d ds %s \n", ndigs, nzin, ds);
71 #endif
72 
73 	/* Compute how many trailing zeros we're going to put in *pd. */
74 
75 	extras = ndigs % 4;
76 	if ((extras > 0) && (nzin != 0)) {
77 		taken = 4 - extras;
78 		if (taken > nzin)
79 			taken = nzin;
80 	} else
81 		taken = 0;
82 
83 	*pnzout = nzin - taken;
84 
85 #define IDIGIT(i) ((i < 0) ? 0 : ((i < ndigs) ? (ds[i] - '0') : 0))
86 
87 	pd->bexponent = 0;
88 	pd->blength = (ndigs + taken + 3) / 4;
89 
90 	ids = (ndigs + taken) - 4 * pd->blength;
91 	id = pd->blength - 1;
92 
93 #ifdef DEBUG
94 	printf(" _integerstring_to_big_decimal exponent %d ids %d id %d \n", pd->bexponent, ids, id);
95 #endif
96 
97 	pd->bsignificand[id] = 1000 * IDIGIT(ids) + 100 * IDIGIT(ids + 1) + 10 * IDIGIT(ids + 2) + IDIGIT(ids + 3);
98 	ids += 4;
99 
100 	for (; ids < (int) (ndigs + taken - 4); ids += 4) {	/* Additional digits to
101 								 * be found. Main loop. */
102 		id--;
103 		pd->bsignificand[id] = 1000 * ds[ids] + 100 * ds[ids + 1] + 10 * ds[ids + 2] + ds[ids + 3] - 1111 * '0';
104 	}
105 
106 #ifdef DEBUG
107 	assert((id == 1) || (id == 0));
108 #endif
109 	if (id != 0)
110 		pd->bsignificand[0] = 1000 * IDIGIT(ids) + 100 * IDIGIT(ids + 1) + 10 * IDIGIT(ids + 2) + IDIGIT(ids + 3);
111 
112 #ifdef DEBUG
113 	printf(" _integerstring_to_big_decimal: ");
114 	_display_big_float(pd, 10);
115 #endif
116 }
117 
118 void
_fractionstring_to_big_decimal(char ds[],unsigned ndigs,unsigned nzin,_big_float * pbf)119 _fractionstring_to_big_decimal(char ds[], unsigned ndigs, unsigned nzin,
120     _big_float *pbf)
121 {
122 	/*
123 	 * Converts a decimal string containing an implicit point, nzin
124 	 * leading implicit zeros, and ndigs explicit digits, into a big
125 	 * float.
126 	 */
127 
128 	int             ids, ibf;
129 
130 #ifdef DEBUG
131 	printf(" _fractionstring_to_big_decimal ndigs %d nzin %d s %s \n", ndigs, nzin, ds);
132 #endif
133 
134 	pbf->bexponent = -(int) (nzin + ndigs);
135 	pbf->blength = (ndigs + 3) / 4;
136 
137 	ids = nzin + ndigs - 4 * pbf->blength;
138 	ibf = pbf->blength - 1;
139 
140 #ifdef DEBUG
141 	printf(" _fractionstring_to_big_decimal exponent %d ids %d ibf %d \n", pbf->bexponent, ids, ibf);
142 #endif
143 
144 #define FDIGIT(i) ((i < nzin) ? 0 : ((i < (nzin+ndigs)) ? (ds[i-nzin] - '0') : 0))
145 
146 	pbf->bsignificand[ibf] = 1000 * FDIGIT(ids) + 100 * FDIGIT(ids + 1) + 10 * FDIGIT(ids + 2) + FDIGIT(ids + 3);
147 	ids += 4;
148 
149 	for (; ids < (int) (nzin + ndigs - 4); ids += 4) {	/* Additional digits to
150 								 * be found. Main loop. */
151 		ibf--;
152 		pbf->bsignificand[ibf] = 1000 * ds[ids - nzin] + 100 * ds[ids + 1 - nzin] + 10 * ds[ids + 2 - nzin] + ds[ids + 3 - nzin] - 1111 * '0';
153 	}
154 
155 	if (ibf > 0) {
156 #ifdef DEBUG
157 		assert(ibf == 1);
158 #endif
159 		pbf->bsignificand[0] = 1000 * FDIGIT(ids) + 100 * FDIGIT(ids + 1) + 10 * FDIGIT(ids + 2) + FDIGIT(ids + 3);
160 	} else {
161 #ifdef DEBUG
162 		assert(ibf == 0);
163 #endif
164 	}
165 
166 #ifdef DEBUG
167 	printf(" _fractionstring_to_big_decimal: ");
168 	_display_big_float(pbf, 10);
169 #endif
170 }
171 
172 void
_mul_10000short(_big_float * pbf,long unsigned carry)173 _mul_10000short(_big_float *pbf, long unsigned carry)
174 {
175 	int             j;
176 	long unsigned   p;
177 
178 	for (j = 0; j < pbf->blength; j++) {
179 		p = _prod_10000_b65536(pbf->bsignificand[j], carry);
180 		pbf->bsignificand[j] = (_BIG_FLOAT_DIGIT) (p & 0xffff);
181 		carry = p >> 16;
182 	}
183 	while (carry != 0) {
184 		p = _carry_out_b10000(carry);
185 		pbf->bsignificand[j++] = (_BIG_FLOAT_DIGIT) (p & 0xffff);
186 		carry = p >> 16;
187 	}
188 	pbf->blength = j;
189 }
190 
191 void
_big_decimal_to_big_binary(_big_float * pd,_big_float * pb)192 _big_decimal_to_big_binary(_big_float *pd, _big_float *pb)
193 {
194 	/* Convert _big_float from decimal form to binary form. */
195 
196 	int             id, idbound;
197 	_BIG_FLOAT_DIGIT sticky, carry;
198 	_BIG_FLOAT_DIGIT multiplier;
199 
200 #ifdef DEBUG
201 	assert(pd->bexponent >= -3);
202 	assert(pd->bexponent <= 3);
203 #endif
204 	pb->bexponent = 0;
205 	pb->blength = 1;
206 	id = pd->blength - 1;
207 	if ((id == 0) && (pd->bexponent < 0)) {
208 		pb->bsignificand[0] = 0;
209 	} else {
210 		pb->bsignificand[0] = pd->bsignificand[id--];
211 		idbound = (pd->bexponent < 0) ? 1 : 0;	/* How far to carry next
212 							 * for loop depends on
213 							 * whether last digit
214 							 * requires special
215 							 * treatment. */
216 		for (; id >= idbound; id--) {
217 			_mul_10000short(pb, (long unsigned) pd->bsignificand[id]);
218 		}
219 	}
220 	if (pd->bexponent < 0) {/* Have to save some integer bits, discard
221 				 * and stick some fraction bits at the end. */
222 #ifdef DEBUG
223 		assert(id == 0);
224 #endif
225 		sticky = 0;
226 		carry = pd->bsignificand[0];
227 		multiplier = 10000;
228 		switch (pd->bexponent) {
229 		case -1:
230 			sticky = carry % 10;
231 			carry /= 10;
232 			multiplier = 1000;
233 			break;
234 		case -2:
235 			sticky = carry % 100;
236 			carry /= 100;
237 			multiplier = 100;
238 			break;
239 		case -3:
240 			sticky = carry % 1000;
241 			carry /= 1000;
242 			multiplier = 10;
243 			break;
244 		}
245 		_multiply_base_two(pb, multiplier, (long unsigned) carry);
246 		if (sticky != 0)
247 			pb->bsignificand[0] |= 1;	/* Save lost bits. */
248 	} else if (pd->bexponent > 0) {	/* Have to append some zeros. */
249 		switch (pd->bexponent) {
250 		case 1:
251 			multiplier = 10;
252 			break;
253 		case 2:
254 			multiplier = 100;
255 			break;
256 		case 3:
257 			multiplier = 1000;
258 			break;
259 		}
260 		carry = 0;
261 		_multiply_base_two(pb, multiplier, (long unsigned) carry);
262 	}
263 #ifdef DEBUG
264 	printf(" _big_decimal_to_big_binary ");
265 	_display_big_float(pb, 2);
266 #endif
267 }
268 
269 void
_big_binary_to_unpacked(_big_float * pb,unpacked * pu)270 _big_binary_to_unpacked(_big_float *pb, unpacked *pu)
271 {
272 	/* Convert a binary big_float to a binary_unpacked.	 */
273 
274 	int             ib, iu;
275 
276 #ifdef DEBUG
277 	assert(pb->bsignificand[pb->blength - 1] != 0);	/* Assert pb is
278 							 * normalized. */
279 #endif
280 
281 	iu = 0;
282 	for (ib = pb->blength - 1; ((ib - 1) >= 0) && (iu < UNPACKED_SIZE); ib -= 2) {
283 		pu->significand[iu++] = pb->bsignificand[ib] << 16 | pb->bsignificand[ib - 1];
284 	}
285 	if (iu < UNPACKED_SIZE) {	/* The big float fits in the unpacked
286 					 * with no rounding. 	 */
287 		if (ib == 0)
288 			pu->significand[iu++] = pb->bsignificand[ib] << 16;
289 		for (; iu < UNPACKED_SIZE; iu++)
290 			pu->significand[iu] = 0;
291 	} else {		/* The big float is too big; chop, stick, and
292 				 * normalize. */
293 		while (pb->bsignificand[ib] == 0)
294 			ib--;
295 		if (ib >= 0)
296 			pu->significand[UNPACKED_SIZE - 1] |= 1;	/* Stick lsb if nonzero
297 									 * found. */
298 	}
299 
300 	pu->exponent = 16 * pb->blength + pb->bexponent - 1;
301 	_fp_normalize(pu);
302 
303 #ifdef DEBUG
304 	printf(" _big_binary_to_unpacked \n");
305 	_display_unpacked(pu);
306 #endif
307 }
308