/*
* 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
* 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 (c) 1988-1995, by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/* Conversion between binary and decimal floating point. */
#include "base_conversion.h"
void
char ds[]; /* Input decimal integer string. */
unsigned ndigs; /* Input number of explicit digits in ds. */
unsigned nzeros; /* Input number of implicit trailing zeros. */
unsigned nsig; /* Input number of significant bits required. */
/*
* Converts a decimal integer string ds with ndigs explicit leading digits
* and nzeros implicit trailing zeros to a _big_float **pb, which only
* requires nsig significand bits.
*/
/* Inexactness is indicated by pb->bsignificand[0] |= 1. */
/*
* If the input is too big for a big_float, pb->bexponent is set to 0x7fff.
*/
{
unsigned nzout;
d.bsize = _BIG_FLOAT_SIZE;
_big_decimal_to_big_binary(&d, pb);
if (nzout != 0) {
switch ((unsigned int)pbout) {
case ((unsigned int)BIG_FLOAT_TIMES_TOOBIG):
#ifdef DEBUG
#endif
break;
case ((unsigned int)BIG_FLOAT_TIMES_NOMEM):
{
break;
}
default:
#ifdef DEBUG
printf(" decimal_to_binary_integer: product ");
#endif
* a large product; the
* target can't be more than
* a quad! */
int i, allweneed;
for (i = 0; i < allweneed; i++)
for (i = 0; (pbout->bsignificand[i] == 0); i++);
#ifdef DEBUG
printf(" decimal_to_binary_integer: removed %d excess digits from product \n", pbout->blength - allweneed);
#endif
}
break;
}
}
}
void
char ds[]; /* Decimal integer string input. */
unsigned ndigs; /* Number of explicit digits to read. */
unsigned nzeros; /* Number of implicit leading zeros before
* digits. */
unsigned nsig; /* Number of significant bits needed. */
/*
* Converts an explicit decimal string *ds[0]..*ds[ndigs-1] preceded by
* nzeros implicit leading zeros after the point into a big_float at *pb. If
* the input does not fit exactly in a big_float, the least significant bit
* of pbout->significand is stuck on. If the input is too big for the base
* conversion tables, pb->bexponent is set to 0x7fff.
*/
{
int i, excess;
d.bsize = _BIG_FLOAT_SIZE;
#ifdef DEBUG
printf(" decimal_to_binary_fraction sigbits %d twopower %d twosig %d \n",
#endif
switch ((unsigned int)pdout) {
case ((unsigned int)BIG_FLOAT_TIMES_TOOBIG):
#ifdef DEBUG
#endif
goto ret;
case ((unsigned int)BIG_FLOAT_TIMES_NOMEM):
{
break;
}
default:
#ifdef DEBUG
if (&d != pdout)
printf(" product ");
#endif
break;
}
/* Have computed appropriate decimal part; now toss fraction. */
#ifdef DEBUG
#endif
if (i < excess)
* discarded fraction. */
}
if (pdout != &d)
ret:
return;
}
void
unsigned significant_bits;
/*
* Converts *pd to *px so that *px can be correctly rounded. significant_bits
* tells how many bits will be significant in the final result to avoid
* superfluous computation. Inexactness is communicated by sticking on the
* lsb of px->significand[UNPACKED_SIZE-1]. Integer buffer overflow is
* indicated with a huge positive exponent.
*/
{
goto ret;
if (length == 0) { /* A zero significand slipped by. */
goto ret;
}
/* Length contains the number of explicit digits in string. */
ifrac = 0;
nfrac = 0; /* No fraction digits. */
nlz = 0;
ndigs = 0;
ntz = 0;
ifrac = 0;
} else { /* Some integer digits, some fraction digits. */
ntz = 0;
nlz = 0;
ifrac++;
nfrac--;
nlz++;
} /* Remove leading zeros. */
}
if (ndigs != 0) { /* Convert integer digits. */
goto ret;
}
if (sigint < 0)
sigint = 0;
} else { /* No integer digits. */
bi.bsignificand[0] = 0;
sigint = 0;
}
* even if we only need a
* round or sticky. */
} else { /* Only need fraction bits for sticky. */
if (nfrac != 0)
}
goto ret;
}
goto punpack;
}
* digits needed. */
#ifdef DEBUG
/* assert either bf << 1 or bf < 1 */
/*
* Assert that integer and fraction parts don't overlap by
* more than one big digit.
*/
#endif
* so bf is just a sticky. */
goto punpack;
}
if (leftshift > 0) { /* shift bf to align with bi. */
* longer, adjust
* expdiff. */
}
expdiff--;
#ifdef DEBUG
* of the hole between bi and bf. */
#endif
/* nmove is the number of words to add to bi. */
if (nmove < 0)
nmove = 0;
#ifdef DEBUG
#endif
if (nmove == 0)
i = -1;
else
for (; (i >= 0) && (expdiff > 0); i--) { /* Fill hole with zeros. */
expdiff--;
bi.bsignificand[i] = 0;
}
if0 = i;
for (; i >= 0; i--)
/* Find first non-zero. */
if (i >= 0)
* stick it. */
goto punpack;
}
* digits. */
#ifdef DEBUG
printf(" merged bi and bf: ");
#endif
ret:
return;
}
/* PUBLIC FUNCTIONS */
/*
* decimal_to_floating routines convert the decimal record at *pd to the
* floating type item at *px, observing the modes specified in *pm and
* setting exceptions in *ps.
*
* pd->sign and pd->fpclass are always taken into account.
*
* pd->exponent, pd->ds and pd->ndigits are used when pd->fpclass is
* fp_normal or fp_subnormal. In these cases pd->ds is expected to
* contain one or more ascii digits followed by a null and pd->ndigits
* is assumed to be the length of the string pd->ds. Notice that for
* efficiency reasons, the assumption that pd->ndigits == strlen(pd->ds)
* is NEVER verified.
*
* px is set to a correctly rounded approximation to
* (sign)*(ds)*10**(exponent) If pd->more != 0 then additional nonzero digits
* are assumed to follow those in ds; fp_inexact is set accordingly.
*
* Thus if pd->exponent == -2 and pd->ds = "1234", *px will get 12.34 rounded to
* storage precision.
*
* px is correctly rounded according to the IEEE rounding modes in pm->rd. *ps
* is set to contain fp_inexact, fp_underflow, or fp_overflow if any of these
* arise.
*
* pm->df and pm->ndigits are never used.
*
*/
void
{
unpacked u;
*ps = 0; /* Initialize to no floating-point
* exceptions. */
case fp_zero:
break;
case fp_infinity:
break;
case fp_quiet:
break;
case fp_signaling:
break;
default:
u.exponent = 0x000fffff;
u.significand[0] = 0x80000000;
goto inrange;
* underflow. */
goto underflow;
} else { /* Deep underflow possible, depending on
* string length. */
int i;
u.exponent = -0x000fffff;
u.significand[0] = 0x80000000;
} else {/* In range. */
}
}
_pack_single(&u, &kluge.x);
}
}
void
double *px;
{
unpacked u;
*ps = 0; /* Initialize to no floating-point
* exceptions. */
case fp_zero:
kluge.f.significand2 = 0;
break;
case fp_infinity:
kluge.f.significand2 = 0;
break;
case fp_quiet:
break;
case fp_signaling:
break;
default:
u.exponent = 0x000fffff;
u.significand[0] = 0x80000000;
goto inrange;
* underflow. */
goto underflow;
} else { /* Deep underflow possible, depending on
* string length. */
int i;
u.exponent = -0x000fffff;
u.significand[0] = 0x80000000;
} else {/* In range. */
}
}
_pack_double(&u, &kluge.x);
}
}
void
{
unpacked u;
*ps = 0; /* Initialize to no floating-point
* exceptions. */
case fp_zero:
kluge.f.significand = 0;
kluge.f.significand2 = 0;
break;
case fp_infinity:
kluge.f.significand = 0;
kluge.f.significand2 = 0;
break;
case fp_quiet:
break;
case fp_signaling:
break;
default:
u.exponent = 0x000fffff;
u.significand[0] = 0x80000000;
goto inrange;
* underflow. */
goto underflow;
} else { /* Deep underflow possible, depending on
* string length. */
int i;
u.exponent = -0x000fffff;
u.significand[0] = 0x80000000;
} else {/* In range. */
}
}
_pack_extended(&u, px);
return;
}
}
void
{
unpacked u;
int i;
*ps = 0; /* Initialize to no floating-point
* exceptions. */
case fp_zero:
kluge.f.significand2 = 0;
kluge.f.significand3 = 0;
kluge.f.significand4 = 0;
break;
case fp_infinity:
kluge.f.significand2 = 0;
kluge.f.significand3 = 0;
kluge.f.significand4 = 0;
break;
case fp_quiet:
break;
case fp_signaling:
break;
default:
u.exponent = 0x000fffff;
u.significand[0] = 0x80000000;
goto inrange;
* underflow. */
goto underflow;
} else { /* Deep underflow possible, depending on
* string length. */
u.exponent = -0x000fffff;
u.significand[0] = 0x80000000;
} else {/* In range. */
}
}
_pack_quadruple(&u, px);
return;
}
#ifdef __STDC__
#else
for (i = 0; i < 4; i++)
#endif
}