/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 1988 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "base_conversion.h"
#ifdef DEBUG
void
_display_big_float(_big_float *pbf, unsigned base)
{
int i;
for (i = 0; i < pbf->blength; i++) {
switch (base) {
case 2:
printf(" + %d * 2** %d", pbf->bsignificand[i], (16 * i + pbf->bexponent));
break;
case 10:
printf(" + %d * 10** %d", pbf->bsignificand[i], (4 * i + pbf->bexponent));
break;
}
if ((i % 4) == 3)
printf("\n");
}
printf("\n");
}
#endif
void
_integerstring_to_big_decimal(char ds[], unsigned ndigs, unsigned nzin,
unsigned *pnzout, _big_float *pd)
{
/*
* Convert ndigs decimal digits from ds, and up to 3 trailing zeros,
* into a decimal big_float in *pd. nzin tells how many implicit
* trailing zeros may be used, while *pnzout tells how many were
* actually absorbed. Up to 3 are used if available so that
* (ndigs+*pnzout) % 4 = 0.
*/
int extras, taken, id, ids;
#ifdef DEBUG
printf(" _integerstring_to_big_decimal: ndigs %d nzin %d ds %s \n", ndigs, nzin, ds);
#endif
/* Compute how many trailing zeros we're going to put in *pd. */
extras = ndigs % 4;
if ((extras > 0) && (nzin != 0)) {
taken = 4 - extras;
if (taken > nzin)
taken = nzin;
} else
taken = 0;
*pnzout = nzin - taken;
#define IDIGIT(i) ((i < 0) ? 0 : ((i < ndigs) ? (ds[i] - '0') : 0))
pd->bexponent = 0;
pd->blength = (ndigs + taken + 3) / 4;
ids = (ndigs + taken) - 4 * pd->blength;
id = pd->blength - 1;
#ifdef DEBUG
printf(" _integerstring_to_big_decimal exponent %d ids %d id %d \n", pd->bexponent, ids, id);
#endif
pd->bsignificand[id] = 1000 * IDIGIT(ids) + 100 * IDIGIT(ids + 1) + 10 * IDIGIT(ids + 2) + IDIGIT(ids + 3);
ids += 4;
for (; ids < (int) (ndigs + taken - 4); ids += 4) { /* Additional digits to
* be found. Main loop. */
id--;
pd->bsignificand[id] = 1000 * ds[ids] + 100 * ds[ids + 1] + 10 * ds[ids + 2] + ds[ids + 3] - 1111 * '0';
}
#ifdef DEBUG
assert((id == 1) || (id == 0));
#endif
if (id != 0)
pd->bsignificand[0] = 1000 * IDIGIT(ids) + 100 * IDIGIT(ids + 1) + 10 * IDIGIT(ids + 2) + IDIGIT(ids + 3);
#ifdef DEBUG
printf(" _integerstring_to_big_decimal: ");
_display_big_float(pd, 10);
#endif
}
void
_fractionstring_to_big_decimal(char ds[], unsigned ndigs, unsigned nzin,
_big_float *pbf)
{
/*
* Converts a decimal string containing an implicit point, nzin
* leading implicit zeros, and ndigs explicit digits, into a big
* float.
*/
int ids, ibf;
#ifdef DEBUG
printf(" _fractionstring_to_big_decimal ndigs %d nzin %d s %s \n", ndigs, nzin, ds);
#endif
pbf->bexponent = -(int) (nzin + ndigs);
pbf->blength = (ndigs + 3) / 4;
ids = nzin + ndigs - 4 * pbf->blength;
ibf = pbf->blength - 1;
#ifdef DEBUG
printf(" _fractionstring_to_big_decimal exponent %d ids %d ibf %d \n", pbf->bexponent, ids, ibf);
#endif
#define FDIGIT(i) ((i < nzin) ? 0 : ((i < (nzin+ndigs)) ? (ds[i-nzin] - '0') : 0))
pbf->bsignificand[ibf] = 1000 * FDIGIT(ids) + 100 * FDIGIT(ids + 1) + 10 * FDIGIT(ids + 2) + FDIGIT(ids + 3);
ids += 4;
for (; ids < (int) (nzin + ndigs - 4); ids += 4) { /* Additional digits to
* be found. Main loop. */
ibf--;
pbf->bsignificand[ibf] = 1000 * ds[ids - nzin] + 100 * ds[ids + 1 - nzin] + 10 * ds[ids + 2 - nzin] + ds[ids + 3 - nzin] - 1111 * '0';
}
if (ibf > 0) {
#ifdef DEBUG
assert(ibf == 1);
#endif
pbf->bsignificand[0] = 1000 * FDIGIT(ids) + 100 * FDIGIT(ids + 1) + 10 * FDIGIT(ids + 2) + FDIGIT(ids + 3);
} else {
#ifdef DEBUG
assert(ibf == 0);
#endif
}
#ifdef DEBUG
printf(" _fractionstring_to_big_decimal: ");
_display_big_float(pbf, 10);
#endif
}
void
_mul_10000short(_big_float *pbf, long unsigned carry)
{
int j;
long unsigned p;
for (j = 0; j < pbf->blength; j++) {
p = _prod_10000_b65536(pbf->bsignificand[j], carry);
pbf->bsignificand[j] = (_BIG_FLOAT_DIGIT) (p & 0xffff);
carry = p >> 16;
}
while (carry != 0) {
p = _carry_out_b10000(carry);
pbf->bsignificand[j++] = (_BIG_FLOAT_DIGIT) (p & 0xffff);
carry = p >> 16;
}
pbf->blength = j;
}
void
_big_decimal_to_big_binary(_big_float *pd, _big_float *pb)
{
/* Convert _big_float from decimal form to binary form. */
int id, idbound;
_BIG_FLOAT_DIGIT sticky, carry;
_BIG_FLOAT_DIGIT multiplier;
#ifdef DEBUG
assert(pd->bexponent >= -3);
assert(pd->bexponent <= 3);
#endif
pb->bexponent = 0;
pb->blength = 1;
id = pd->blength - 1;
if ((id == 0) && (pd->bexponent < 0)) {
pb->bsignificand[0] = 0;
} else {
pb->bsignificand[0] = pd->bsignificand[id--];
idbound = (pd->bexponent < 0) ? 1 : 0; /* How far to carry next
* for loop depends on
* whether last digit
* requires special
* treatment. */
for (; id >= idbound; id--) {
_mul_10000short(pb, (long unsigned) pd->bsignificand[id]);
}
}
if (pd->bexponent < 0) {/* Have to save some integer bits, discard
* and stick some fraction bits at the end. */
#ifdef DEBUG
assert(id == 0);
#endif
sticky = 0;
carry = pd->bsignificand[0];
multiplier = 10000;
switch (pd->bexponent) {
case -1:
sticky = carry % 10;
carry /= 10;
multiplier = 1000;
break;
case -2:
sticky = carry % 100;
carry /= 100;
multiplier = 100;
break;
case -3:
sticky = carry % 1000;
carry /= 1000;
multiplier = 10;
break;
}
_multiply_base_two(pb, multiplier, (long unsigned) carry);
if (sticky != 0)
pb->bsignificand[0] |= 1; /* Save lost bits. */
} else if (pd->bexponent > 0) { /* Have to append some zeros. */
switch (pd->bexponent) {
case 1:
multiplier = 10;
break;
case 2:
multiplier = 100;
break;
case 3:
multiplier = 1000;
break;
}
carry = 0;
_multiply_base_two(pb, multiplier, (long unsigned) carry);
}
#ifdef DEBUG
printf(" _big_decimal_to_big_binary ");
_display_big_float(pb, 2);
#endif
}
void
_big_binary_to_unpacked(_big_float *pb, unpacked *pu)
{
/* Convert a binary big_float to a binary_unpacked. */
int ib, iu;
#ifdef DEBUG
assert(pb->bsignificand[pb->blength - 1] != 0); /* Assert pb is
* normalized. */
#endif
iu = 0;
for (ib = pb->blength - 1; ((ib - 1) >= 0) && (iu < UNPACKED_SIZE); ib -= 2) {
pu->significand[iu++] = pb->bsignificand[ib] << 16 | pb->bsignificand[ib - 1];
}
if (iu < UNPACKED_SIZE) { /* The big float fits in the unpacked
* with no rounding. */
if (ib == 0)
pu->significand[iu++] = pb->bsignificand[ib] << 16;
for (; iu < UNPACKED_SIZE; iu++)
pu->significand[iu] = 0;
} else { /* The big float is too big; chop, stick, and
* normalize. */
while (pb->bsignificand[ib] == 0)
ib--;
if (ib >= 0)
pu->significand[UNPACKED_SIZE - 1] |= 1; /* Stick lsb if nonzero
* found. */
}
pu->exponent = 16 * pb->blength + pb->bexponent - 1;
_fp_normalize(pu);
#ifdef DEBUG
printf(" _big_binary_to_unpacked \n");
_display_unpacked(pu);
#endif
}