/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1985-2010 AT&T Intellectual Property *
* and is licensed under the *
* Common Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* David Korn <dgk@research.att.com> *
* Phong Vo <kpv@research.att.com> *
* *
***********************************************************************/
#if __STDC__
#endif
#include "sfhdr.h"
/* Convert a floating point value to ASCII.
**
** Written by Kiem-Phong Vo and Glenn Fowler (SFFMT_AFORMAT)
*/
#if ! _lib_isnan
#if _lib_fpclassify
#else
#endif
#else
#if ! _lib_isnanl
#endif
#endif
#if ! _lib_signbit && defined(signbit)
#endif
#if ! _lib_signbit
#if ! _ast_fltmax_double
{
Sfdouble_t z = -0.0;
return !memcmp(&f, &z, sizeof(f));
}
#endif
static int neg0d(double f)
{
double z = -0.0;
return !memcmp(&f, &z, sizeof(f));
}
#endif
#define CVT_LDBL_INT long
#else
#define CVT_LDBL_INT int
#else
#define CVT_LDBL_INT long
#endif
#endif
#define CVT_DBL_INT long
#else
#define CVT_DBL_INT int
#else
#define CVT_DBL_INT long
#endif
#endif
#if __STD_C
#else
char* buf; /* conversion goes here */
int n_digit; /* number of digits wanted */
int* decpt; /* to return decimal point */
int* sign; /* to return sign */
int* len; /* return string length */
int format; /* conversion format */
#endif
{
reg long n, v;
int x;
#if !_ast_fltmax_double
if(format&SFFMT_LDOUBLE)
if(isnanl(f))
{
#if _lib_signbit
if (signbit(f))
#else
if (f < 0)
#endif
*sign = 1;
return SF_NAN;
}
#if _lib_isinf
if (n = isinf(f))
{
#if _lib_signbit
if (signbit(f))
#else
if (n < 0 || f < 0)
#endif
*sign = 1;
return SF_INF;
}
#endif
# if _c99_in_the_wild
# if _lib_signbit
if (signbit(f))
# else
# if _lib_copysignl
# else
# if _lib_copysign
# else
if (f < 0.0)
# endif
# endif
# endif
{ f = -f;
*sign = 1;
}
# if _lib_fpclassify
switch (fpclassify(f))
{
case FP_INFINITE:
return SF_INF;
case FP_NAN:
return SF_NAN;
case FP_ZERO:
return SF_ZERO;
}
# endif
# else
# if _lib_signbit
if (signbit(f))
# else
# endif
{ f = -f;
*sign = 1;
}
# endif
if(f < LDBL_MIN)
return SF_ZERO;
if(f > LDBL_MAX)
return SF_INF;
if(format & SFFMT_AFORMAT)
{ Sfdouble_t g;
g = frexpl(f, &x);
*decpt = x;
for (;;)
{ m = f;
x = 8 * sizeof(m);
while ((x -= 4) >= 0)
goto around;
}
f -= m;
f = ldexpl(f, 8 * sizeof(m));
}
}
n = 0;
if(f >= (Sfdouble_t)CVT_LDBL_MAXINT)
{ /* scale to a small enough number to fit an int */
v = SF_MAXEXP10-1;
do
{ if(f < _Sfpos10[v])
v -= 1;
else
{
f *= _Sfneg10[v];
if((n += (1<<v)) >= SF_IDIGITS)
return SF_INF;
}
} while(f >= (Sfdouble_t)CVT_LDBL_MAXINT);
}
else if(f > 0.0 && f < 0.1)
{ /* scale to avoid excessive multiply by 10 below */
v = SF_MAXEXP10-1;
do
{ if(f <= _Sfneg10[v])
{ f *= _Sfpos10[v];
if((n += (1<<v)) >= SF_IDIGITS)
return SF_INF;
}
else if (--v < 0)
break;
} while(f < 0.1);
n = -n;
}
*decpt = (int)n;
if((v = (CVT_LDBL_INT)f) != 0)
{ /* translate the integer part */
f -= (Sfdouble_t)v;
n = b-sp;
if((*decpt += (int)n) >= SF_IDIGITS)
return SF_INF;
b = sp;
}
else n = 0;
/* remaining number of digits to compute; add 1 for later rounding */
if(n_digit > 0)
n += n_digit;
}
else
{
{ Sfdouble_t d;
while((long)(d = f*10.) == 0)
{ f = d;
*decpt -= 1;
}
}
{ /* generate fractional digits */
if(f <= 0.)
{ /* fill with 0's */
goto done;
}
else if((n = (long)(f *= 10.)) < 10)
{ *sp++ = '0' + n;
f -= n;
}
else /* n == 10 */
}
}
}
} else
#endif
{ double f = *(double*)vp;
if(isnan(f))
{
#if _lib_signbit
if (signbit(f))
#else
if (f < 0)
#endif
*sign = 1;
return SF_NAN;
}
#if _lib_isinf
if (n = isinf(f))
{
#if _lib_signbit
if (signbit(f))
#else
if (n < 0 || f < 0)
#endif
*sign = 1;
return SF_INF;
}
#endif
#if _c99_in_the_wild
# if _lib_signbit
if (signbit(f))
# else
# if _lib_copysign
# else
if (f < 0.0)
# endif
# endif
{ f = -f;
*sign = 1;
}
# if _lib_fpclassify
switch (fpclassify(f))
{
case FP_INFINITE:
return SF_INF;
case FP_NAN:
return SF_NAN;
case FP_ZERO:
return SF_ZERO;
}
# endif
#else
# if _lib_signbit
if (signbit(f))
# else
# endif
{ f = -f;
*sign = 1;
}
#endif
if(f < DBL_MIN)
return SF_ZERO;
if(f > DBL_MAX)
return SF_INF;
if(format & SFFMT_AFORMAT)
{ double g;
g = frexp(f, &x);
*decpt = x;
for (;;)
{ m = f;
x = 8 * sizeof(m);
while ((x -= 4) >= 0)
goto around;
}
f -= m;
f = ldexp(f, 8 * sizeof(m));
}
}
n = 0;
if(f >= (double)CVT_DBL_MAXINT)
{ /* scale to a small enough number to fit an int */
v = SF_MAXEXP10-1;
do
{ if(f < _Sfpos10[v])
v -= 1;
else
{ f *= _Sfneg10[v];
if((n += (1<<v)) >= SF_IDIGITS)
return SF_INF;
}
} while(f >= (double)CVT_DBL_MAXINT);
}
else if(f > 0.0 && f < 1e-8)
{ /* scale to avoid excessive multiply by 10 below */
v = SF_MAXEXP10-1;
do
{ if(f <= _Sfneg10[v])
{ f *= _Sfpos10[v];
if((n += (1<<v)) >= SF_IDIGITS)
return SF_INF;
}
else if(--v < 0)
break;
} while(f < 0.1);
n = -n;
}
*decpt = (int)n;
if((v = (CVT_DBL_INT)f) != 0)
{ /* translate the integer part */
f -= (double)v;
n = b-sp;
if((*decpt += (int)n) >= SF_IDIGITS)
return SF_INF;
b = sp;
}
else n = 0;
/* remaining number of digits to compute; add 1 for later rounding */
if(n_digit > 0)
n += n_digit;
}
else
{
{ reg double d;
while((long)(d = f*10.) == 0)
{ f = d;
*decpt -= 1;
}
}
{ /* generate fractional digits */
if(f <= 0.)
{ /* fill with 0's */
goto done;
}
else if((n = (long)(f *= 10.)) < 10)
{ *sp++ = (char)('0' + n);
f -= n;
}
else /* n == 10 */
break;
}
}
}
}
if(ep <= b)
ep = b+1;
{ /* round the last digit */
*--sp += 5;
while(*sp > '9')
{ *sp = '0';
if(sp > b)
*--sp += 1;
else
{ /* next power of 10 */
*sp = '1';
*decpt += 1;
if(!(format&SFFMT_EFORMAT))
{ /* add one more 0 for %f precision */
ep += 1;
}
}
}
}
done:
*--ep = '\0';
if(len)
return b;
if (((m >> x) & 0xf) >= 8)
{ t = sp - 1;
for (;;)
{ if (--t <= b)
{ (*decpt)++;
break;
}
switch (*t)
{
case 'f':
case 'F':
*t = '0';
continue;
case '9':
*t = ep[10];
break;
default:
(*t)++;
break;
}
break;
}
}
goto done;
}