1da2e3ebchin/***********************************************************************
2da2e3ebchin*                                                                      *
3da2e3ebchin*               This software is part of the ast package               *
43e14f97Roger A. Faulkner*          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5da2e3ebchin*                      and is licensed under the                       *
6da2e3ebchin*                  Common Public License, Version 1.0                  *
77c2fbfbApril Chin*                    by AT&T Intellectual Property                     *
8da2e3ebchin*                                                                      *
9da2e3ebchin*                A copy of the License is available at                 *
10da2e3ebchin*            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebchin*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebchin*                                                                      *
13da2e3ebchin*              Information and Software Systems Research               *
14da2e3ebchin*                            AT&T Research                             *
15da2e3ebchin*                           Florham Park NJ                            *
16da2e3ebchin*                                                                      *
17da2e3ebchin*                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebchin*                  David Korn <dgk@research.att.com>                   *
19da2e3ebchin*                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebchin*                                                                      *
21da2e3ebchin***********************************************************************/
227c2fbfbApril Chin#if __STDC__
237c2fbfbApril Chin#include	"FEATURE/isoc99"
247c2fbfbApril Chin#endif
25da2e3ebchin#include	"sfhdr.h"
26da2e3ebchin
27da2e3ebchin/*	Convert a floating point value to ASCII.
28da2e3ebchin**
29da2e3ebchin**	Written by Kiem-Phong Vo and Glenn Fowler (SFFMT_AFORMAT)
30da2e3ebchin*/
31da2e3ebchin
32da2e3ebchinstatic char		*lc_inf = "inf", *uc_inf = "INF";
33da2e3ebchinstatic char		*lc_nan = "nan", *uc_nan = "NAN";
34da2e3ebchinstatic char		*Zero = "0";
35da2e3ebchin#define SF_INF		((_Sfi = 3), strncpy(buf, (format & SFFMT_UPPER) ? uc_inf : lc_inf, size))
36da2e3ebchin#define SF_NAN		((_Sfi = 3), strncpy(buf, (format & SFFMT_UPPER) ? uc_nan : lc_nan, size))
37da2e3ebchin#define SF_ZERO		((_Sfi = 1), strncpy(buf, Zero, size))
38da2e3ebchin#define SF_INTPART	(SF_IDIGITS/2)
39da2e3ebchin
40da2e3ebchin#if ! _lib_isnan
41da2e3ebchin#if _lib_fpclassify
42da2e3ebchin#define isnan(n)	(fpclassify(n)==FP_NAN)
43da2e3ebchin#define isnanl(n)	(fpclassify(n)==FP_NAN)
44da2e3ebchin#else
45da2e3ebchin#define isnan(n)	(memcmp((void*)&n,(void*)&_Sfdnan,sizeof(n))==0)
46da2e3ebchin#define isnanl(n)	(memcmp((void*)&n,(void*)&_Sflnan,sizeof(n))==0)
47da2e3ebchin#endif
48da2e3ebchin#else
49da2e3ebchin#if ! _lib_isnanl
50da2e3ebchin#define isnanl(n)	isnan(n)
51da2e3ebchin#endif
52da2e3ebchin#endif
53da2e3ebchin
547c2fbfbApril Chin#if ! _lib_signbit && defined(signbit)
557c2fbfbApril Chin#undef	_lib_signbit
567c2fbfbApril Chin#define _lib_signbit	1
577c2fbfbApril Chin#endif
587c2fbfbApril Chin
597c2fbfbApril Chin#if ! _lib_signbit
607c2fbfbApril Chin#if ! _ast_fltmax_double
617c2fbfbApril Chinstatic int neg0ld(Sfdouble_t f)
627c2fbfbApril Chin{
637c2fbfbApril Chin	Sfdouble_t	z = -0.0;
647c2fbfbApril Chin	return !memcmp(&f, &z, sizeof(f));
657c2fbfbApril Chin}
667c2fbfbApril Chin#endif
677c2fbfbApril Chinstatic int neg0d(double f)
687c2fbfbApril Chin{
697c2fbfbApril Chin	double		z = -0.0;
707c2fbfbApril Chin	return !memcmp(&f, &z, sizeof(f));
717c2fbfbApril Chin}
727c2fbfbApril Chin#endif
737c2fbfbApril Chin
747c2fbfbApril Chin#if ULONG_DIG && ULONG_DIG < (DBL_DIG-1)
757c2fbfbApril Chin#define CVT_LDBL_INT	long
767c2fbfbApril Chin#define CVT_LDBL_MAXINT	LONG_MAX
777c2fbfbApril Chin#else
787c2fbfbApril Chin#if UINT_DIG && UINT_DIG < (DBL_DIG-1)
797c2fbfbApril Chin#define CVT_LDBL_INT	int
807c2fbfbApril Chin#define CVT_LDBL_MAXINT	INT_MAX
817c2fbfbApril Chin#else
827c2fbfbApril Chin#define CVT_LDBL_INT	long
837c2fbfbApril Chin#define CVT_LDBL_MAXINT	SF_MAXLONG
847c2fbfbApril Chin#endif
857c2fbfbApril Chin#endif
867c2fbfbApril Chin
877c2fbfbApril Chin#if ULONG_DIG && ULONG_DIG < (DBL_DIG-1)
887c2fbfbApril Chin#define CVT_DBL_INT	long
897c2fbfbApril Chin#define CVT_DBL_MAXINT	LONG_MAX
907c2fbfbApril Chin#else
917c2fbfbApril Chin#if UINT_DIG && UINT_DIG < (DBL_DIG-1)
927c2fbfbApril Chin#define CVT_DBL_INT	int
937c2fbfbApril Chin#define CVT_DBL_MAXINT	INT_MAX
947c2fbfbApril Chin#else
957c2fbfbApril Chin#define CVT_DBL_INT	long
967c2fbfbApril Chin#define CVT_DBL_MAXINT	SF_MAXLONG
977c2fbfbApril Chin#endif
987c2fbfbApril Chin#endif
997c2fbfbApril Chin
100da2e3ebchin#if __STD_C
1017c2fbfbApril Chinchar* _sfcvt(Void_t* vp, char* buf, size_t size, int n_digit,
102da2e3ebchin		int* decpt, int* sign, int* len, int format)
103da2e3ebchin#else
1047c2fbfbApril Chinchar* _sfcvt(vp,buf,size,n_digit,decpt,sign,len,format)
1057c2fbfbApril ChinVoid_t*		vp;		/* pointer to value to convert	*/
106da2e3ebchinchar*		buf;		/* conversion goes here		*/
107da2e3ebchinsize_t		size;		/* size of buf			*/
108da2e3ebchinint		n_digit;	/* number of digits wanted	*/
109da2e3ebchinint*		decpt;		/* to return decimal point	*/
110da2e3ebchinint*		sign;		/* to return sign		*/
111da2e3ebchinint*		len;		/* return string length		*/
112da2e3ebchinint		format;		/* conversion format		*/
113da2e3ebchin#endif
114da2e3ebchin{
115da2e3ebchin	reg char		*sp;
116da2e3ebchin	reg long		n, v;
11734f9b3eRoland Mainz	reg char		*ep, *b, *endsp, *t;
11834f9b3eRoland Mainz	int			x;
119da2e3ebchin	_ast_flt_unsigned_max_t	m;
120da2e3ebchin
121da2e3ebchin	static char		lx[] = "0123456789abcdef";
122da2e3ebchin	static char		ux[] = "0123456789ABCDEF";
123da2e3ebchin
124da2e3ebchin	*sign = *decpt = 0;
125da2e3ebchin
126da2e3ebchin#if !_ast_fltmax_double
127da2e3ebchin	if(format&SFFMT_LDOUBLE)
1287c2fbfbApril Chin	{	Sfdouble_t	f = *(Sfdouble_t*)vp;
1297c2fbfbApril Chin
1307c2fbfbApril Chin		if(isnanl(f))
1317c2fbfbApril Chin		{
132da2e3ebchin#if _lib_signbit
1337c2fbfbApril Chin			if (signbit(f))
134da2e3ebchin#else
1357c2fbfbApril Chin			if (f < 0)
136da2e3ebchin#endif
1377c2fbfbApril Chin				*sign = 1;
1387c2fbfbApril Chin			return SF_NAN;
1397c2fbfbApril Chin		}
1407c2fbfbApril Chin#if _lib_isinf
1417c2fbfbApril Chin		if (n = isinf(f))
1427c2fbfbApril Chin		{
1437c2fbfbApril Chin#if _lib_signbit
1447c2fbfbApril Chin			if (signbit(f))
1457c2fbfbApril Chin#else
1467c2fbfbApril Chin			if (n < 0 || f < 0)
147da2e3ebchin#endif
1487c2fbfbApril Chin				*sign = 1;
1497c2fbfbApril Chin			return SF_INF;
1507c2fbfbApril Chin		}
151da2e3ebchin#endif
1527c2fbfbApril Chin# if _c99_in_the_wild
1537c2fbfbApril Chin#  if _lib_signbit
1547c2fbfbApril Chin		if (signbit(f))
1557c2fbfbApril Chin#  else
1567c2fbfbApril Chin#   if _lib_copysignl
1577c2fbfbApril Chin		if (copysignl(1.0, f) < 0.0)
1587c2fbfbApril Chin#   else
1597c2fbfbApril Chin#    if _lib_copysign
1607c2fbfbApril Chin		if (copysign(1.0, (double)f) < 0.0)
1617c2fbfbApril Chin#    else
1627c2fbfbApril Chin		if (f < 0.0)
1637c2fbfbApril Chin#    endif
1647c2fbfbApril Chin#   endif
1657c2fbfbApril Chin#  endif
166da2e3ebchin		{	f = -f;
167da2e3ebchin			*sign = 1;
168da2e3ebchin		}
1697c2fbfbApril Chin#  if _lib_fpclassify
170da2e3ebchin		switch (fpclassify(f))
171da2e3ebchin		{
172da2e3ebchin		case FP_INFINITE:
173da2e3ebchin			return SF_INF;
174da2e3ebchin		case FP_NAN:
175da2e3ebchin			return SF_NAN;
176da2e3ebchin		case FP_ZERO:
177da2e3ebchin			return SF_ZERO;
178da2e3ebchin		}
1797c2fbfbApril Chin#  endif
1807c2fbfbApril Chin# else
1817c2fbfbApril Chin#  if _lib_signbit
1827c2fbfbApril Chin		if (signbit(f))
1837c2fbfbApril Chin#  else
1847c2fbfbApril Chin		if (f < 0.0 || f == 0.0 && neg0ld(f))
1857c2fbfbApril Chin#  endif
186da2e3ebchin		{	f = -f;
187da2e3ebchin			*sign = 1;
188da2e3ebchin		}
1897c2fbfbApril Chin# endif
190da2e3ebchin		if(f < LDBL_MIN)
191da2e3ebchin			return SF_ZERO;
192da2e3ebchin		if(f > LDBL_MAX)
193da2e3ebchin			return SF_INF;
194da2e3ebchin
195da2e3ebchin		if(format & SFFMT_AFORMAT)
196da2e3ebchin		{	Sfdouble_t	g;
197da2e3ebchin			b = sp = buf;
198da2e3ebchin			ep = (format & SFFMT_UPPER) ? ux : lx;
199da2e3ebchin			if(n_digit <= 0 || n_digit >= (size - 9))
200da2e3ebchin				n_digit = size - 9;
201da2e3ebchin			endsp = sp + n_digit + 1;
202da2e3ebchin
203da2e3ebchin			g = frexpl(f, &x);
204da2e3ebchin			*decpt = x;
205da2e3ebchin			f = ldexpl(g, 8 * sizeof(m) - 3);
206da2e3ebchin
207da2e3ebchin			for (;;)
208da2e3ebchin			{	m = f;
209da2e3ebchin				x = 8 * sizeof(m);
210da2e3ebchin				while ((x -= 4) >= 0)
211da2e3ebchin				{	*sp++ = ep[(m >> x) & 0xf];
212da2e3ebchin					if (sp >= endsp)
21334f9b3eRoland Mainz						goto around;
214da2e3ebchin				}
215da2e3ebchin				f -= m;
216da2e3ebchin				f = ldexpl(f, 8 * sizeof(m));
217da2e3ebchin			}
218da2e3ebchin		}
219da2e3ebchin
220da2e3ebchin		n = 0;
2217c2fbfbApril Chin		if(f >= (Sfdouble_t)CVT_LDBL_MAXINT)
222da2e3ebchin		{	/* scale to a small enough number to fit an int */
223da2e3ebchin			v = SF_MAXEXP10-1;
224da2e3ebchin			do
225da2e3ebchin			{	if(f < _Sfpos10[v])
226da2e3ebchin					v -= 1;
227da2e3ebchin				else
228da2e3ebchin				{
229da2e3ebchin					f *= _Sfneg10[v];
230da2e3ebchin					if((n += (1<<v)) >= SF_IDIGITS)
231da2e3ebchin						return SF_INF;
232da2e3ebchin				}
2337c2fbfbApril Chin			} while(f >= (Sfdouble_t)CVT_LDBL_MAXINT);
2347c2fbfbApril Chin		}
2357c2fbfbApril Chin		else if(f > 0.0 && f < 0.1)
2367c2fbfbApril Chin		{	/* scale to avoid excessive multiply by 10 below */
2377c2fbfbApril Chin			v = SF_MAXEXP10-1;
2387c2fbfbApril Chin			do
2397c2fbfbApril Chin			{	if(f <= _Sfneg10[v])
2407c2fbfbApril Chin				{	f *= _Sfpos10[v];
2417c2fbfbApril Chin					if((n += (1<<v)) >= SF_IDIGITS)
2427c2fbfbApril Chin						return SF_INF;
2437c2fbfbApril Chin				}
2447c2fbfbApril Chin				else if (--v < 0)
2457c2fbfbApril Chin					break;
2467c2fbfbApril Chin			} while(f < 0.1);
2477c2fbfbApril Chin			n = -n;
248da2e3ebchin		}
249da2e3ebchin		*decpt = (int)n;
250da2e3ebchin
251da2e3ebchin		b = sp = buf + SF_INTPART;
2527c2fbfbApril Chin		if((v = (CVT_LDBL_INT)f) != 0)
253da2e3ebchin		{	/* translate the integer part */
254da2e3ebchin			f -= (Sfdouble_t)v;
255da2e3ebchin
2567c2fbfbApril Chin			sfucvt(v,sp,n,ep,CVT_LDBL_INT,unsigned CVT_LDBL_INT);
257da2e3ebchin
258da2e3ebchin			n = b-sp;
259da2e3ebchin			if((*decpt += (int)n) >= SF_IDIGITS)
260da2e3ebchin				return SF_INF;
261da2e3ebchin			b = sp;
262da2e3ebchin			sp = buf + SF_INTPART;
263da2e3ebchin		}
264da2e3ebchin		else	n = 0;
265da2e3ebchin
266da2e3ebchin		/* remaining number of digits to compute; add 1 for later rounding */
267da2e3ebchin		n = (((format&SFFMT_EFORMAT) || *decpt <= 0) ? 1 : *decpt+1) - n;
268da2e3ebchin		if(n_digit > 0)
269da2e3ebchin		{	if(n_digit > LDBL_DIG)
270da2e3ebchin				n_digit = LDBL_DIG;
271da2e3ebchin			n += n_digit;
272da2e3ebchin		}
273da2e3ebchin
274da2e3ebchin		if((ep = (sp+n)) > (endsp = buf+(size-2)))
275da2e3ebchin			ep = endsp;
276da2e3ebchin		if(sp > ep)
277da2e3ebchin			sp = ep;
278da2e3ebchin		else
279da2e3ebchin		{
280da2e3ebchin			if((format&SFFMT_EFORMAT) && *decpt == 0 && f > 0.)
281da2e3ebchin			{	Sfdouble_t	d;
282da2e3ebchin				while((long)(d = f*10.) == 0)
283da2e3ebchin				{	f = d;
284da2e3ebchin					*decpt -= 1;
285da2e3ebchin				}
286da2e3ebchin			}
287da2e3ebchin
288da2e3ebchin			while(sp < ep)
289da2e3ebchin			{	/* generate fractional digits */
290da2e3ebchin				if(f <= 0.)
291da2e3ebchin				{	/* fill with 0's */
292da2e3ebchin					do { *sp++ = '0'; } while(sp < ep);
293da2e3ebchin					goto done;
294da2e3ebchin				}
295da2e3ebchin				else if((n = (long)(f *= 10.)) < 10)
296da2e3ebchin				{	*sp++ = '0' + n;
297da2e3ebchin					f -= n;
298da2e3ebchin				}
299da2e3ebchin				else /* n == 10 */
300da2e3ebchin				{	do { *sp++ = '9'; } while(sp < ep);
301da2e3ebchin				}
302da2e3ebchin			}
303da2e3ebchin		}
304da2e3ebchin	} else
305da2e3ebchin#endif
3067c2fbfbApril Chin	{	double	f = *(double*)vp;
307da2e3ebchin
3087c2fbfbApril Chin		if(isnan(f))
3097c2fbfbApril Chin		{
3107c2fbfbApril Chin#if _lib_signbit
3117c2fbfbApril Chin			if (signbit(f))
3127c2fbfbApril Chin#else
3137c2fbfbApril Chin			if (f < 0)
3147c2fbfbApril Chin#endif
3157c2fbfbApril Chin				*sign = 1;
3167c2fbfbApril Chin			return SF_NAN;
3177c2fbfbApril Chin		}
318da2e3ebchin#if _lib_isinf
319da2e3ebchin		if (n = isinf(f))
3207c2fbfbApril Chin		{
3217c2fbfbApril Chin#if _lib_signbit
3227c2fbfbApril Chin			if (signbit(f))
3237c2fbfbApril Chin#else
3247c2fbfbApril Chin			if (n < 0 || f < 0)
3257c2fbfbApril Chin#endif
326da2e3ebchin				*sign = 1;
327da2e3ebchin			return SF_INF;
328da2e3ebchin		}
329da2e3ebchin#endif
330da2e3ebchin#if _c99_in_the_wild
3317c2fbfbApril Chin# if _lib_signbit
332da2e3ebchin		if (signbit(f))
3337c2fbfbApril Chin# else
3347c2fbfbApril Chin#  if _lib_copysign
335da2e3ebchin		if (copysign(1.0, f) < 0.0)
3367c2fbfbApril Chin#  else
337da2e3ebchin		if (f < 0.0)
3387c2fbfbApril Chin#  endif
3397c2fbfbApril Chin# endif
340da2e3ebchin		{	f = -f;
341da2e3ebchin			*sign = 1;
342da2e3ebchin		}
3437c2fbfbApril Chin# if _lib_fpclassify
344da2e3ebchin		switch (fpclassify(f))
345da2e3ebchin		{
346da2e3ebchin		case FP_INFINITE:
347da2e3ebchin			return SF_INF;
348da2e3ebchin		case FP_NAN:
349da2e3ebchin			return SF_NAN;
350da2e3ebchin		case FP_ZERO:
351da2e3ebchin			return SF_ZERO;
352da2e3ebchin		}
3537c2fbfbApril Chin# endif
354da2e3ebchin#else
3557c2fbfbApril Chin# if _lib_signbit
3567c2fbfbApril Chin		if (signbit(f))
3577c2fbfbApril Chin# else
3587c2fbfbApril Chin		if (f < 0.0 || f == 0.0 && neg0d(f))
3597c2fbfbApril Chin# endif
360da2e3ebchin		{	f = -f;
361da2e3ebchin			*sign = 1;
362da2e3ebchin		}
363da2e3ebchin#endif
364da2e3ebchin		if(f < DBL_MIN)
365da2e3ebchin			return SF_ZERO;
366da2e3ebchin		if(f > DBL_MAX)
367da2e3ebchin			return SF_INF;
368da2e3ebchin
369da2e3ebchin		if(format & SFFMT_AFORMAT)
37034f9b3eRoland Mainz		{	double		g;
371da2e3ebchin			b = sp = buf;
372da2e3ebchin			ep = (format & SFFMT_UPPER) ? ux : lx;
373da2e3ebchin			if(n_digit <= 0 || n_digit >= (size - 9))
374da2e3ebchin				n_digit = size - 9;
37534f9b3eRoland Mainz			endsp = sp + n_digit + 1;
376da2e3ebchin
377da2e3ebchin			g = frexp(f, &x);
378da2e3ebchin			*decpt = x;
379da2e3ebchin			f = ldexp(g, 8 * sizeof(m) - 3);
380da2e3ebchin
381da2e3ebchin			for (;;)
382da2e3ebchin			{	m = f;
383da2e3ebchin				x = 8 * sizeof(m);
384da2e3ebchin				while ((x -= 4) >= 0)
385da2e3ebchin				{	*sp++ = ep[(m >> x) & 0xf];
386da2e3ebchin					if (sp >= endsp)
38734f9b3eRoland Mainz						goto around;
388da2e3ebchin				}
389da2e3ebchin				f -= m;
390da2e3ebchin				f = ldexp(f, 8 * sizeof(m));
391da2e3ebchin			}
392da2e3ebchin		}
393da2e3ebchin		n = 0;
3947c2fbfbApril Chin		if(f >= (double)CVT_DBL_MAXINT)
395da2e3ebchin		{	/* scale to a small enough number to fit an int */
396da2e3ebchin			v = SF_MAXEXP10-1;
397da2e3ebchin			do
398da2e3ebchin			{	if(f < _Sfpos10[v])
399da2e3ebchin					v -= 1;
400da2e3ebchin				else
401da2e3ebchin				{	f *= _Sfneg10[v];
402da2e3ebchin					if((n += (1<<v)) >= SF_IDIGITS)
403da2e3ebchin						return SF_INF;
404da2e3ebchin				}
4057c2fbfbApril Chin			} while(f >= (double)CVT_DBL_MAXINT);
4067c2fbfbApril Chin		}
4077c2fbfbApril Chin		else if(f > 0.0 && f < 1e-8)
4087c2fbfbApril Chin		{	/* scale to avoid excessive multiply by 10 below */
4097c2fbfbApril Chin			v = SF_MAXEXP10-1;
410