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
33void
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
55void
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
118void
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
172void
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
191void
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
269void
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