#include "lint.h"
#include "base_conversion.h"
static const char *hexchar = "0123456789abcdef";
#if defined(__sparc)
void
__aconvert(double arg, int ndigits, int *exp, int *sign, char *buf)
{
union {
unsigned int i[2];
long long l;
double d;
} a, c;
int ha, i, s;
unsigned int d;
a.d = arg;
*sign = s = a.i[0] >> 31;
ha = a.i[0] & ~0x80000000;
if (ha >= 0x7ff00000) {
*exp = 0;
__infnanstring((ha == 0x7ff00000 && a.i[1] == 0)?
fp_infinity : fp_quiet, ndigits, buf);
return;
}
if (ha < 0x00100000) {
if ((ha | a.i[1]) == 0) {
*exp = 0;
for (i = 0; i < ndigits; i++)
buf[i] = '0';
buf[ndigits] = '\0';
return;
}
a.i[0] = ha;
a.d = (double)a.l;
if (s)
a.d = -a.d;
ha = a.i[0] & ~0x80000000;
*exp = (ha >> 20) - 0x3ff - 1074;
} else {
*exp = (ha >> 20) - 0x3ff;
}
if (ndigits < 14) {
c.i[0] = (0x43700000 | (s << 31)) - (ndigits << 22);
c.i[1] = 0;
a.i[0] = (a.i[0] & 0x800fffff) | 0x3ff00000;
a.d = (a.d + c.d) - c.d;
ha = a.i[0] & ~0x80000000;
if (ha >= 0x40000000)
(*exp)++;
}
buf[0] = '1';
d = ha << 12;
for (i = 1; i < ndigits && i < 6; i++) {
buf[i] = hexchar[d >> 28];
d <<= 4;
}
d = a.i[1];
for (; i < ndigits && i < 14; i++) {
buf[i] = hexchar[d >> 28];
d <<= 4;
}
for (; i < ndigits; i++)
buf[i] = '0';
buf[ndigits] = '\0';
}
void
__qaconvert(long double *arg, int ndigits, int *exp, int *sign, char *buf)
{
union {
unsigned int i[4];
long double q;
} a;
enum fp_direction_type rd;
int ha, i, s;
unsigned int b, r, d;
a.q = *arg;
*sign = a.i[0] >> 31;
ha = a.i[0] &= ~0x80000000;
if (ha >= 0x7fff0000) {
*exp = 0;
__infnanstring((ha == 0x7fff0000 && (a.i[1] | a.i[2] | a.i[3])
== 0)? fp_infinity : fp_quiet, ndigits, buf);
return;
}
if (ha < 0x00010000) {
if ((ha | a.i[1] | a.i[2] | a.i[3]) == 0) {
*exp = 0;
for (i = 0; i < ndigits; i++)
buf[i] = '0';
buf[ndigits] = '\0';
return;
}
i = 0;
while ((a.i[0] | (a.i[1] & 0xffff0000)) == 0) {
a.i[0] = a.i[1];
a.i[1] = a.i[2];
a.i[2] = a.i[3];
a.i[3] = 0;
i += 32;
}
while ((a.i[0] & 0x7fff0000) == 0) {
a.i[0] = (a.i[0] << 1) | (a.i[1] >> 31);
a.i[1] = (a.i[1] << 1) | (a.i[2] >> 31);
a.i[2] = (a.i[2] << 1) | (a.i[3] >> 31);
a.i[3] <<= 1;
i++;
}
*exp = -0x3ffe - i;
} else {
*exp = (ha >> 16) - 0x3fff;
}
if (ndigits < 29) {
a.i[0] = (a.i[0] & 0xffff) | 0x10000;
if (ndigits <= 5) {
i = 0;
s = (5 - ndigits) << 2;
b = 1 << s;
r = ((a.i[0] << 1) << (31 - s)) | (a.i[1] >> s);
if ((a.i[1] & (b - 1)) | a.i[2] | a.i[3])
r |= 1;
a.i[0] &= ~(b - 1);
a.i[1] = a.i[2] = a.i[3] = 0;
} else if (ndigits <= 13) {
i = 1;
s = (13 - ndigits) << 2;
b = 1 << s;
r = ((a.i[1] << 1) << (31 - s)) | (a.i[2] >> s);
if ((a.i[2] & (b - 1)) | a.i[3])
r |= 1;
a.i[1] &= ~(b - 1);
a.i[2] = a.i[3] = 0;
} else if (ndigits <= 21) {
i = 2;
s = (21 - ndigits) << 2;
b = 1 << s;
r = ((a.i[2] << 1) << (31 - s)) | (a.i[3] >> s);
if (a.i[3] & (b - 1))
r |= 1;
a.i[2] &= ~(b - 1);
a.i[3] = 0;
} else {
i = 3;
s = (29 - ndigits) << 2;
b = 1 << s;
r = (a.i[3] << 1) << (31 - s);
a.i[3] &= ~(b - 1);
}
if (r) {
__base_conversion_set_exception(
(fp_exception_field_type)(1 << fp_inexact));
rd = _QgetRD();
if (*sign && (rd == fp_positive || rd == fp_negative))
rd = fp_positive + fp_negative - rd;
if (rd == fp_positive || (rd == fp_nearest &&
(r > 0x80000000u || (r == 0x80000000u &&
(a.i[i] & b))))) {
a.i[i] += b;
while (a.i[i] == 0)
a.i[--i]++;
if (a.i[0] >= 0x20000)
(*exp)++;
}
}
}
buf[0] = '1';
d = a.i[0] << 16;
for (i = 1; i < ndigits && i < 5; i++) {
buf[i] = hexchar[d >> 28];
d <<= 4;
}
d = a.i[1];
for (; i < ndigits && i < 13; i++) {
buf[i] = hexchar[d >> 28];
d <<= 4;
}
d = a.i[2];
for (; i < ndigits && i < 21; i++) {
buf[i] = hexchar[d >> 28];
d <<= 4;
}
d = a.i[3];
for (; i < ndigits && i < 29; i++) {
buf[i] = hexchar[d >> 28];
d <<= 4;
}
for (; i < ndigits; i++)
buf[i] = '0';
buf[ndigits] = '\0';
}
#elif defined(__i386) || defined(__amd64)
void
__qaconvert(long double *arg, int ndigits, int *exp, int *sign, char *buf)
{
union {
unsigned int i[3];
long double x;
} a, c;
int ea, i, s;
unsigned int d;
a.x = *arg;
*sign = s = (a.i[2] >> 15) & 1;
ea = a.i[2] & 0x7fff;
if (ea == 0x7fff) {
*exp = 0;
__infnanstring((((a.i[1] << 1) | a.i[0]) == 0)?
fp_infinity : fp_quiet, ndigits, buf);
return;
}
if (ea == 0) {
if ((a.i[1] | a.i[0]) == 0) {
*exp = 0;
for (i = 0; i < ndigits; i++)
buf[i] = '0';
buf[ndigits] = '\0';
return;
}
a.x *= 18446744073709551616.0;
ea = a.i[2] & 0x7fff;
*exp = ea - 0x403f;
} else {
*exp = ea - 0x3fff;
}
if (ndigits < 17) {
c.i[2] = (0x4042 | (s << 15)) - (ndigits << 2);
c.i[1] = 0x80000000;
c.i[0] = 0;
a.i[2] = 0x3fff | (s << 15);
a.x = (a.x + c.x) - c.x;
ea = a.i[2] & 0x7fff;
if (ea >= 0x4000)
(*exp)++;
}
buf[0] = '1';
d = (a.i[1] << 1) | (a.i[0] >> 31);
for (i = 1; i < ndigits && i < 9; i++) {
buf[i] = hexchar[d >> 28];
d <<= 4;
}
d = a.i[0] << 1;
for (; i < ndigits && i < 17; i++) {
buf[i] = hexchar[d >> 28];
d <<= 4;
}
for (; i < ndigits; i++)
buf[i] = '0';
buf[ndigits] = '\0';
}
void
__aconvert(double arg, int ndigits, int *exp, int *sign, char *buf)
{
union {
int i[2];
double d;
} a;
long double ldarg;
int ha;
a.i[0] = *(int *)&arg;
a.i[1] = *(1+(int *)&arg);
ha = a.i[1] & ~0x80000000;
if (ha > 0x7ff00000 || (ha == 0x7ff00000 && a.i[0] != 0))
a.i[1] |= 0x80000;
ldarg = a.d;
__qaconvert(&ldarg, ndigits, exp, sign, buf);
}
#else
#error Unknown architecture
#endif