#include "lint.h"
#include <stdlib.h>
#include "base_conversion.h"
static unsigned int
__quorem10000(unsigned int x, unsigned short *pr)
{
*pr = x % 10000;
return (x / 10000);
}
static void
__big_binary_to_big_decimal(_big_float *pb, int nsig, _big_float **ppd,
int *sticky)
{
_big_float *pd;
int i, j, len, s;
unsigned int carry;
pd = *ppd;
if (pb->bexponent + ((pb->blength - 1) << 4) >= 0) {
carry = pb->bsignificand[pb->blength - 1];
pd->bsignificand[1] = __quorem10000(carry,
&pd->bsignificand[0]);
len = (pd->bsignificand[1])? 2 : 1;
for (i = pb->blength - 2; i >= 0 &&
pb->bexponent + (i << 4) >= 0; i--) {
carry = pb->bsignificand[i];
for (j = 0; j < len; j++) {
carry += (unsigned int)pd->bsignificand[j]
<< 16;
carry = __quorem10000(carry,
&pd->bsignificand[j]);
}
while (carry != 0) {
carry = __quorem10000(carry,
&pd->bsignificand[j]);
j++;
}
len = j;
}
} else {
i = pb->blength - 1;
len = 0;
}
if (i >= 0 && pb->bexponent + (i << 4) > -16) {
s = pb->bexponent + (i << 4) + 16;
carry = pb->bsignificand[i] >> (16 - s);
for (j = 0; j < len; j++) {
carry += (unsigned int)pd->bsignificand[j] << s;
carry = __quorem10000(carry, &pd->bsignificand[j]);
}
while (carry != 0) {
carry = __quorem10000(carry, &pd->bsignificand[j]);
j++;
}
len = j;
s = pb->bsignificand[i] & ((1 << (16 - s)) - 1);
i--;
} else {
s = 0;
}
pd->blength = len;
pd->bexponent = 0;
while (i >= 0)
s |= pb->bsignificand[i--];
*sticky = s;
if (pb->bexponent > 0) {
__big_float_times_power(pd, 2, pb->bexponent, nsig, ppd);
}
}
static void
__big_decimal_to_string(_big_float *pf, int sticky, decimal_mode *pm,
decimal_record *pd, fp_exception_field_type *ps)
{
unsigned short d;
int e, er, efirst, elast, i, is, j;
char s[4], round;
i = pf->blength - 1;
if (i < 0) {
e = pf->bexponent = -DECIMAL_STRING_LENGTH - 2;
} else {
e = pf->bexponent + (i << 2);
d = pf->bsignificand[i];
if (d >= 1000)
e += 3;
else if (d >= 100)
e += 2;
else if (d >= 10)
e++;
}
if (pm->df == fixed_form) {
er = -pm->ndigits;
if (er < 0) {
efirst = (e >= 0)? e : -1;
elast = er;
} else {
efirst = (e >= er)? e : ((er > 0)? er - 1 : 0);
elast = 0;
}
if (efirst - elast >= DECIMAL_STRING_LENGTH - 1) {
efirst = e;
elast = e - DECIMAL_STRING_LENGTH + 2;
if (er < elast)
er = elast;
*ps |= 1 << fp_overflow;
}
} else {
efirst = e;
elast = er = e - pm->ndigits + 1;
}
is = 0;
for (e = efirst; e >= pf->bexponent + (pf->blength << 2) &&
e >= er - 1; e--)
pd->ds[is++] = '0';
i = pf->blength - 1;
j = 3 - ((e - pf->bexponent) & 3);
if (j > 0 && e >= er - 1) {
__four_digits_quick(pf->bsignificand[i], s);
while (j <= 3 && e >= er - 1) {
pd->ds[is++] = s[j++];
e--;
}
while (j <= 3)
sticky |= (s[j++] - '0');
i--;
}
while ((i | (e - er - 2)) >= 0) {
__four_digits_quick(pf->bsignificand[i], pd->ds + is);
is += 4;
e -= 4;
i--;
}
if (i >= 0) {
if (e >= er - 1) {
__four_digits_quick(pf->bsignificand[i], s);
for (j = 0; e >= er - 1; j++) {
pd->ds[is++] = s[j];
e--;
}
while (j <= 3)
sticky |= (s[j++] - '0');
i--;
}
} else {
while (e-- >= er - 1)
pd->ds[is++] = '0';
}
round = pd->ds[--is];
while (i >= 0)
sticky |= pf->bsignificand[i--];
for (e = er - 1; e >= elast; e--)
pd->ds[is++] = '0';
pd->exponent = elast;
pd->ndigits = is;
pd->ds[is] = '\0';
if (round == '0' && sticky == 0)
return;
*ps |= 1 << fp_inexact;
switch (pm->rd) {
case fp_nearest:
if (round < '5' || (round == '5' && sticky == 0 &&
(is <= 0 || (pd->ds[is - 1] & 1) == 0)))
return;
break;
case fp_positive:
if (pd->sign)
return;
break;
case fp_negative:
if (!pd->sign)
return;
break;
default:
return;
}
for (i = efirst - er; i >= 0 && pd->ds[i] == '9'; i--)
pd->ds[i] = '0';
if (i >= 0) {
(pd->ds[i])++;
} else {
pd->ds[0] = '1';
if (pm->df == floating_form) {
pd->exponent++;
} else if (is == DECIMAL_STRING_LENGTH - 1) {
pd->exponent++;
*ps |= 1 << fp_overflow;
} else {
if (is > 0)
pd->ds[is] = '0';
is++;
pd->ndigits = is;
pd->ds[is] = '\0';
}
}
}
static void
__bigfloat_to_decimal(_big_float *bf, decimal_mode *pm, decimal_record *pd,
fp_exception_field_type *ps)
{
_big_float *pbf, *pbd, d;
int sticky, powten, sigbits, sigdigits, i;
if (pm->ndigits >= DECIMAL_STRING_LENGTH || pm->ndigits <=
((pm->df == floating_form)? 0 : -DECIMAL_STRING_LENGTH)) {
*ps = 1 << fp_overflow;
return;
}
pbf = bf;
powten = 0;
if (pm->df == fixed_form) {
if (pm->ndigits >= 0 && bf->bexponent < 0) {
powten = pm->ndigits + 1;
if (powten > -bf->bexponent)
powten = -bf->bexponent;
sigbits = bf->bexponent + (bf->blength << 4) +
(((powten * 217706) + 65535) >> 16);
if (sigbits < 1)
sigbits = 1;
__big_float_times_power(bf, 10, powten, sigbits, &pbf);
}
sigdigits = DECIMAL_STRING_LENGTH + 1;
} else {
if (bf->bexponent < 0) {
i = bf->bexponent + ((bf->blength - 1) << 4);
if (i <= 0 || ((i * 19728) >> 16) < pm->ndigits + 1) {
powten = pm->ndigits + 1;
if (i < 0)
powten += ((-i * 19729) + 65535) >> 16;
else if (i > 0)
powten -= (i * 19728) >> 16;
if (powten > -bf->bexponent)
powten = -bf->bexponent;
sigbits = i + 16 +
(((powten * 217706) + 65535) >> 16);
__big_float_times_power(bf, 10, powten,
sigbits, &pbf);
}
}
sigdigits = pm->ndigits + 2;
}
d.bsize = _BIG_FLOAT_SIZE;
pbd = &d;
__big_binary_to_big_decimal(pbf, sigdigits, &pbd, &sticky);
pbd->bexponent -= powten;
__big_decimal_to_string(pbd, sticky, pm, pd, ps);
if (pbf != bf)
(void) free((void *)pbf);
if (pbd != &d)
(void) free((void *)pbd);
}
static void
__shorten(_big_float *p)
{
int length = p->blength;
int zeros, i;
for (zeros = 0; zeros < length && p->bsignificand[zeros] == 0; zeros++)
;
if (zeros) {
length -= zeros;
p->bexponent += zeros << 4;
for (i = 0; i < length; i++)
p->bsignificand[i] = p->bsignificand[i + zeros];
p->blength = length;
}
}
static void
__double_to_bigfloat(double *px, _big_float *pf)
{
double_equivalence *x;
x = (double_equivalence *)px;
pf->bsize = _BIG_FLOAT_SIZE;
pf->bexponent = x->f.msw.exponent - DOUBLE_BIAS - 52;
pf->blength = 4;
pf->bsignificand[0] = x->f.significand2 & 0xffff;
pf->bsignificand[1] = x->f.significand2 >> 16;
pf->bsignificand[2] = x->f.msw.significand & 0xffff;
pf->bsignificand[3] = x->f.msw.significand >> 16;
if (x->f.msw.exponent == 0) {
pf->bexponent++;
while (pf->bsignificand[pf->blength - 1] == 0)
pf->blength--;
} else {
pf->bsignificand[3] += 0x10;
}
__shorten(pf);
}
static void
__extended_to_bigfloat(extended *px, _big_float *pf)
{
extended_equivalence *x;
x = (extended_equivalence *)px;
pf->bsize = _BIG_FLOAT_SIZE;
pf->bexponent = x->f.msw.exponent - EXTENDED_BIAS - 63;
pf->blength = 4;
pf->bsignificand[0] = x->f.significand2 & 0xffff;
pf->bsignificand[1] = x->f.significand2 >> 16;
pf->bsignificand[2] = x->f.significand & 0xffff;
pf->bsignificand[3] = x->f.significand >> 16;
if (x->f.msw.exponent == 0) {
pf->bexponent++;
while (pf->bsignificand[pf->blength - 1] == 0)
pf->blength--;
}
__shorten(pf);
}
static void
__quadruple_to_bigfloat(quadruple *px, _big_float *pf)
{
quadruple_equivalence *x;
x = (quadruple_equivalence *)px;
pf->bsize = _BIG_FLOAT_SIZE;
pf->bexponent = x->f.msw.exponent - QUAD_BIAS - 112;
pf->bsignificand[0] = x->f.significand4 & 0xffff;
pf->bsignificand[1] = x->f.significand4 >> 16;
pf->bsignificand[2] = x->f.significand3 & 0xffff;
pf->bsignificand[3] = x->f.significand3 >> 16;
pf->bsignificand[4] = x->f.significand2 & 0xffff;
pf->bsignificand[5] = x->f.significand2 >> 16;
pf->bsignificand[6] = x->f.msw.significand;
if (x->f.msw.exponent == 0) {
pf->blength = 7;
pf->bexponent++;
while (pf->bsignificand[pf->blength - 1] == 0)
pf->blength--;
} else {
pf->blength = 8;
pf->bsignificand[7] = 1;
}
__shorten(pf);
}
void
single_to_decimal(single *px, decimal_mode *pm, decimal_record *pd,
fp_exception_field_type *ps)
{
single_equivalence *kluge;
_big_float bf;
fp_exception_field_type ef;
double x;
kluge = (single_equivalence *)px;
pd->sign = kluge->f.msw.sign;
if (kluge->f.msw.exponent == 0) {
if (kluge->f.msw.significand == 0) {
pd->fpclass = fp_zero;
*ps = 0;
return;
} else {
#if defined(__sparc) || defined(__amd64)
int i;
pd->fpclass = fp_subnormal;
i = *(int *)px;
x = (double)(i & ~0x80000000);
if (i < 0)
x = -x;
x *= 1.401298464324817070923730e-45;
ef = 0;
if (__fast_double_to_decimal(&x, pm, pd, &ef)) {
__double_to_bigfloat(&x, &bf);
__bigfloat_to_decimal(&bf, pm, pd, &ef);
}
if (ef != 0)
__base_conversion_set_exception(ef);
*ps = ef;
return;
#else
pd->fpclass = fp_subnormal;
#endif
}
} else if (kluge->f.msw.exponent == 0xff) {
if (kluge->f.msw.significand == 0)
pd->fpclass = fp_infinity;
else if (kluge->f.msw.significand >= 0x400000)
pd->fpclass = fp_quiet;
else
pd->fpclass = fp_signaling;
*ps = 0;
return;
} else {
pd->fpclass = fp_normal;
}
ef = 0;
x = *px;
if (__fast_double_to_decimal(&x, pm, pd, &ef)) {
__double_to_bigfloat(&x, &bf);
__bigfloat_to_decimal(&bf, pm, pd, &ef);
}
if (ef != 0)
__base_conversion_set_exception(ef);
*ps = ef;
}
void
double_to_decimal(double *px, decimal_mode *pm, decimal_record *pd,
fp_exception_field_type *ps)
{
double_equivalence *kluge;
_big_float bf;
fp_exception_field_type ef;
kluge = (double_equivalence *)px;
pd->sign = kluge->f.msw.sign;
if (kluge->f.msw.exponent == 0) {
if (kluge->f.msw.significand == 0 &&
kluge->f.significand2 == 0) {
pd->fpclass = fp_zero;
*ps = 0;
return;
} else {
pd->fpclass = fp_subnormal;
}
} else if (kluge->f.msw.exponent == 0x7ff) {
if (kluge->f.msw.significand == 0 &&
kluge->f.significand2 == 0)
pd->fpclass = fp_infinity;
else if (kluge->f.msw.significand >= 0x80000)
pd->fpclass = fp_quiet;
else
pd->fpclass = fp_signaling;
*ps = 0;
return;
} else {
pd->fpclass = fp_normal;
}
ef = 0;
if (__fast_double_to_decimal(px, pm, pd, &ef)) {
__double_to_bigfloat(px, &bf);
__bigfloat_to_decimal(&bf, pm, pd, &ef);
}
if (ef != 0)
__base_conversion_set_exception(ef);
*ps = ef;
}
void
extended_to_decimal(extended *px, decimal_mode *pm, decimal_record *pd,
fp_exception_field_type *ps)
{
extended_equivalence *kluge;
_big_float bf;
fp_exception_field_type ef;
kluge = (extended_equivalence *)px;
pd->sign = kluge->f.msw.sign;
if (kluge->f.msw.exponent == 0) {
if ((kluge->f.significand | kluge->f.significand2) == 0) {
pd->fpclass = fp_zero;
*ps = 0;
return;
} else {
pd->fpclass = fp_subnormal;
}
} else if ((kluge->f.significand & 0x80000000) == 0) {
pd->fpclass = fp_signaling;
*ps = 0;
return;
} else if (kluge->f.msw.exponent == 0x7fff) {
if (((kluge->f.significand & 0x7fffffff) |
kluge->f.significand2) == 0)
pd->fpclass = fp_infinity;
else if ((kluge->f.significand & 0x7fffffff) >= 0x40000000)
pd->fpclass = fp_quiet;
else
pd->fpclass = fp_signaling;
*ps = 0;
return;
} else {
pd->fpclass = fp_normal;
}
ef = 0;
__extended_to_bigfloat(px, &bf);
__bigfloat_to_decimal(&bf, pm, pd, &ef);
if (ef != 0)
__base_conversion_set_exception(ef);
*ps = ef;
}
void
quadruple_to_decimal(quadruple *px, decimal_mode *pm, decimal_record *pd,
fp_exception_field_type *ps)
{
quadruple_equivalence *kluge;
_big_float bf;
fp_exception_field_type ef;
kluge = (quadruple_equivalence *)px;
pd->sign = kluge->f.msw.sign;
if (kluge->f.msw.exponent == 0) {
if (kluge->f.msw.significand == 0 &&
(kluge->f.significand2 | kluge->f.significand3 |
kluge->f.significand4) == 0) {
pd->fpclass = fp_zero;
*ps = 0;
return;
} else {
pd->fpclass = fp_subnormal;
}
} else if (kluge->f.msw.exponent == 0x7fff) {
if (kluge->f.msw.significand == 0 &&
(kluge->f.significand2 | kluge->f.significand3 |
kluge->f.significand4) == 0)
pd->fpclass = fp_infinity;
else if (kluge->f.msw.significand >= 0x8000)
pd->fpclass = fp_quiet;
else
pd->fpclass = fp_signaling;
*ps = 0;
return;
} else {
pd->fpclass = fp_normal;
}
ef = 0;
__quadruple_to_bigfloat(px, &bf);
__bigfloat_to_decimal(&bf, pm, pd, &ef);
if (ef != 0)
__base_conversion_set_exception(ef);
*ps = ef;
}