xref: /onnv-gate/usr/src/lib/libast/common/sfio/sfcvt.c (revision 4887:feebf9260c2e)
1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
18*4887Schin *                  David Korn <dgk@research.att.com>                   *
19*4887Schin *                   Phong Vo <kpv@research.att.com>                    *
20*4887Schin *                                                                      *
21*4887Schin ***********************************************************************/
22*4887Schin #include	"sfhdr.h"
23*4887Schin 
24*4887Schin /*	Convert a floating point value to ASCII.
25*4887Schin **
26*4887Schin **	Written by Kiem-Phong Vo and Glenn Fowler (SFFMT_AFORMAT)
27*4887Schin */
28*4887Schin 
29*4887Schin static char		*lc_inf = "inf", *uc_inf = "INF";
30*4887Schin static char		*lc_nan = "nan", *uc_nan = "NAN";
31*4887Schin static char		*Zero = "0";
32*4887Schin #define SF_INF		((_Sfi = 3), strncpy(buf, (format & SFFMT_UPPER) ? uc_inf : lc_inf, size))
33*4887Schin #define SF_NAN		((_Sfi = 3), strncpy(buf, (format & SFFMT_UPPER) ? uc_nan : lc_nan, size))
34*4887Schin #define SF_ZERO		((_Sfi = 1), strncpy(buf, Zero, size))
35*4887Schin #define SF_INTPART	(SF_IDIGITS/2)
36*4887Schin 
37*4887Schin #if ! _lib_isnan
38*4887Schin #if _lib_fpclassify
39*4887Schin #define isnan(n)	(fpclassify(n)==FP_NAN)
40*4887Schin #define isnanl(n)	(fpclassify(n)==FP_NAN)
41*4887Schin #else
42*4887Schin #define isnan(n)	(memcmp((void*)&n,(void*)&_Sfdnan,sizeof(n))==0)
43*4887Schin #define isnanl(n)	(memcmp((void*)&n,(void*)&_Sflnan,sizeof(n))==0)
44*4887Schin #endif
45*4887Schin #else
46*4887Schin #if ! _lib_isnanl
47*4887Schin #define isnanl(n)	isnan(n)
48*4887Schin #endif
49*4887Schin #endif
50*4887Schin 
51*4887Schin #if __STD_C
52*4887Schin char* _sfcvt(Sfdouble_t dv, char* buf, size_t size, int n_digit,
53*4887Schin 		int* decpt, int* sign, int* len, int format)
54*4887Schin #else
55*4887Schin char* _sfcvt(dv,buf,size,n_digit,decpt,sign,len,format)
56*4887Schin Sfdouble_t	dv;		/* value to convert		*/
57*4887Schin char*		buf;		/* conversion goes here		*/
58*4887Schin size_t		size;		/* size of buf			*/
59*4887Schin int		n_digit;	/* number of digits wanted	*/
60*4887Schin int*		decpt;		/* to return decimal point	*/
61*4887Schin int*		sign;		/* to return sign		*/
62*4887Schin int*		len;		/* return string length		*/
63*4887Schin int		format;		/* conversion format		*/
64*4887Schin #endif
65*4887Schin {
66*4887Schin 	reg char		*sp;
67*4887Schin 	reg long		n, v;
68*4887Schin 	reg char		*ep, *b, *endsp;
69*4887Schin 	_ast_flt_unsigned_max_t	m;
70*4887Schin 
71*4887Schin 	static char		lx[] = "0123456789abcdef";
72*4887Schin 	static char		ux[] = "0123456789ABCDEF";
73*4887Schin 
74*4887Schin 	*sign = *decpt = 0;
75*4887Schin 
76*4887Schin 	if(isnanl(dv))
77*4887Schin 		return SF_NAN;
78*4887Schin #if _lib_isinf
79*4887Schin 	if (n = isinf(dv))
80*4887Schin 	{	if (n < 0)
81*4887Schin 			*sign = 1;
82*4887Schin 		return SF_INF;
83*4887Schin 	}
84*4887Schin #endif
85*4887Schin #if !_ast_fltmax_double
86*4887Schin 	if(format&SFFMT_LDOUBLE)
87*4887Schin 	{	Sfdouble_t	f = dv;
88*4887Schin #if _c99_in_the_wild
89*4887Schin #if _lib_signbit
90*4887Schin 		if (signbit(f))
91*4887Schin #else
92*4887Schin #if _lib_copysignl
93*4887Schin 		if (copysignl(1.0, f) < 0.0)
94*4887Schin #else
95*4887Schin #if _lib_copysign
96*4887Schin 		if (copysign(1.0, (double)f) < 0.0)
97*4887Schin #else
98*4887Schin 		if (f < 0.0)
99*4887Schin #endif
100*4887Schin #endif
101*4887Schin #endif
102*4887Schin 		{	f = -f;
103*4887Schin 			*sign = 1;
104*4887Schin 		}
105*4887Schin #if _lib_fpclassify
106*4887Schin 		switch (fpclassify(f))
107*4887Schin 		{
108*4887Schin 		case FP_INFINITE:
109*4887Schin 			return SF_INF;
110*4887Schin 		case FP_NAN:
111*4887Schin 			return SF_NAN;
112*4887Schin 		case FP_ZERO:
113*4887Schin 			return SF_ZERO;
114*4887Schin 		}
115*4887Schin #endif
116*4887Schin #else
117*4887Schin 		if (f < 0.0)
118*4887Schin 		{	f = -f;
119*4887Schin 			*sign = 1;
120*4887Schin 		}
121*4887Schin #endif
122*4887Schin 		if(f < LDBL_MIN)
123*4887Schin 			return SF_ZERO;
124*4887Schin 		if(f > LDBL_MAX)
125*4887Schin 			return SF_INF;
126*4887Schin 
127*4887Schin 		if(format & SFFMT_AFORMAT)
128*4887Schin 		{	Sfdouble_t	g;
129*4887Schin 			int		x;
130*4887Schin 			b = sp = buf;
131*4887Schin 			ep = (format & SFFMT_UPPER) ? ux : lx;
132*4887Schin 			if(n_digit <= 0 || n_digit >= (size - 9))
133*4887Schin 				n_digit = size - 9;
134*4887Schin 			endsp = sp + n_digit + 1;
135*4887Schin 
136*4887Schin 			g = frexpl(f, &x);
137*4887Schin 			*decpt = x;
138*4887Schin 			f = ldexpl(g, 8 * sizeof(m) - 3);
139*4887Schin 
140*4887Schin 			for (;;)
141*4887Schin 			{	m = f;
142*4887Schin 				x = 8 * sizeof(m);
143*4887Schin 				while ((x -= 4) >= 0)
144*4887Schin 				{	*sp++ = ep[(m >> x) & 0xf];
145*4887Schin 					if (sp >= endsp)
146*4887Schin 					{	ep = sp + 1;
147*4887Schin 						goto done;
148*4887Schin 					}
149*4887Schin 				}
150*4887Schin 				f -= m;
151*4887Schin 				f = ldexpl(f, 8 * sizeof(m));
152*4887Schin 			}
153*4887Schin 		}
154*4887Schin 
155*4887Schin 		n = 0;
156*4887Schin 		if(f >= (Sfdouble_t)SF_MAXLONG)
157*4887Schin 		{	/* scale to a small enough number to fit an int */
158*4887Schin 			v = SF_MAXEXP10-1;
159*4887Schin 			do
160*4887Schin 			{	if(f < _Sfpos10[v])
161*4887Schin 					v -= 1;
162*4887Schin 				else
163*4887Schin 				{
164*4887Schin 					f *= _Sfneg10[v];
165*4887Schin 					if((n += (1<<v)) >= SF_IDIGITS)
166*4887Schin 						return SF_INF;
167*4887Schin 				}
168*4887Schin 			} while(f >= (Sfdouble_t)SF_MAXLONG);
169*4887Schin 		}
170*4887Schin 		*decpt = (int)n;
171*4887Schin 
172*4887Schin 		b = sp = buf + SF_INTPART;
173*4887Schin 		if((v = (long)f) != 0)
174*4887Schin 		{	/* translate the integer part */
175*4887Schin 			f -= (Sfdouble_t)v;
176*4887Schin 
177*4887Schin 			sfucvt(v,sp,n,ep,long,ulong);
178*4887Schin 
179*4887Schin 			n = b-sp;
180*4887Schin 			if((*decpt += (int)n) >= SF_IDIGITS)
181*4887Schin 				return SF_INF;
182*4887Schin 			b = sp;
183*4887Schin 			sp = buf + SF_INTPART;
184*4887Schin 		}
185*4887Schin 		else	n = 0;
186*4887Schin 
187*4887Schin 		/* remaining number of digits to compute; add 1 for later rounding */
188*4887Schin 		n = (((format&SFFMT_EFORMAT) || *decpt <= 0) ? 1 : *decpt+1) - n;
189*4887Schin 		if(n_digit > 0)
190*4887Schin 		{	if(n_digit > LDBL_DIG)
191*4887Schin 				n_digit = LDBL_DIG;
192*4887Schin 			n += n_digit;
193*4887Schin 		}
194*4887Schin 
195*4887Schin 		if((ep = (sp+n)) > (endsp = buf+(size-2)))
196*4887Schin 			ep = endsp;
197*4887Schin 		if(sp > ep)
198*4887Schin 			sp = ep;
199*4887Schin 		else
200*4887Schin 		{
201*4887Schin 			if((format&SFFMT_EFORMAT) && *decpt == 0 && f > 0.)
202*4887Schin 			{	Sfdouble_t	d;
203*4887Schin 				while((long)(d = f*10.) == 0)
204*4887Schin 				{	f = d;
205*4887Schin 					*decpt -= 1;
206*4887Schin 				}
207*4887Schin 			}
208*4887Schin 
209*4887Schin 			while(sp < ep)
210*4887Schin 			{	/* generate fractional digits */
211*4887Schin 				if(f <= 0.)
212*4887Schin 				{	/* fill with 0's */
213*4887Schin 					do { *sp++ = '0'; } while(sp < ep);
214*4887Schin 					goto done;
215*4887Schin 				}
216*4887Schin 				else if((n = (long)(f *= 10.)) < 10)
217*4887Schin 				{	*sp++ = '0' + n;
218*4887Schin 					f -= n;
219*4887Schin 				}
220*4887Schin 				else /* n == 10 */
221*4887Schin 				{	do { *sp++ = '9'; } while(sp < ep);
222*4887Schin 				}
223*4887Schin 			}
224*4887Schin 		}
225*4887Schin 	} else
226*4887Schin #endif
227*4887Schin 	{	double	f = (double)dv;
228*4887Schin 
229*4887Schin #if _lib_isinf
230*4887Schin 		if (n = isinf(f))
231*4887Schin 		{	if (n < 0)
232*4887Schin 				*sign = 1;
233*4887Schin 			return SF_INF;
234*4887Schin 		}
235*4887Schin #endif
236*4887Schin #if _c99_in_the_wild
237*4887Schin #if _lib_signbit
238*4887Schin 		if (signbit(f))
239*4887Schin #else
240*4887Schin #if _lib_copysign
241*4887Schin 		if (copysign(1.0, f) < 0.0)
242*4887Schin #else
243*4887Schin 		if (f < 0.0)
244*4887Schin #endif
245*4887Schin #endif
246*4887Schin 		{	f = -f;
247*4887Schin 			*sign = 1;
248*4887Schin 		}
249*4887Schin #if _lib_fpclassify
250*4887Schin 		switch (fpclassify(f))
251*4887Schin 		{
252*4887Schin 		case FP_INFINITE:
253*4887Schin 			return SF_INF;
254*4887Schin 		case FP_NAN:
255*4887Schin 			return SF_NAN;
256*4887Schin 		case FP_ZERO:
257*4887Schin 			return SF_ZERO;
258*4887Schin 		}
259*4887Schin #endif
260*4887Schin #else
261*4887Schin 		if (f < 0.0)
262*4887Schin 		{	f = -f;
263*4887Schin 			*sign = 1;
264*4887Schin 		}
265*4887Schin #endif
266*4887Schin 		if(f < DBL_MIN)
267*4887Schin 			return SF_ZERO;
268*4887Schin 		if(f > DBL_MAX)
269*4887Schin 			return SF_INF;
270*4887Schin 
271*4887Schin 		if(format & SFFMT_AFORMAT)
272*4887Schin 		{	double	g;
273*4887Schin 			int	x;
274*4887Schin 			b = sp = buf;
275*4887Schin 			ep = (format & SFFMT_UPPER) ? ux : lx;
276*4887Schin 			if(n_digit <= 0 || n_digit >= (size - 9))
277*4887Schin 				n_digit = size - 9;
278*4887Schin 			endsp = sp + n_digit;
279*4887Schin 
280*4887Schin 			g = frexp(f, &x);
281*4887Schin 			*decpt = x;
282*4887Schin 			f = ldexp(g, 8 * sizeof(m) - 3);
283*4887Schin 
284*4887Schin 			for (;;)
285*4887Schin 			{	m = f;
286*4887Schin 				x = 8 * sizeof(m);
287*4887Schin 				while ((x -= 4) >= 0)
288*4887Schin 				{	*sp++ = ep[(m >> x) & 0xf];
289*4887Schin 					if (sp >= endsp)
290*4887Schin 					{	ep = sp + 1;
291*4887Schin 						goto done;
292*4887Schin 					}
293*4887Schin 				}
294*4887Schin 				f -= m;
295*4887Schin 				f = ldexp(f, 8 * sizeof(m));
296*4887Schin 			}
297*4887Schin 		}
298*4887Schin 		n = 0;
299*4887Schin 		if(f >= (double)SF_MAXLONG)
300*4887Schin 		{	/* scale to a small enough number to fit an int */
301*4887Schin 			v = SF_MAXEXP10-1;
302*4887Schin 			do
303*4887Schin 			{	if(f < _Sfpos10[v])
304*4887Schin 					v -= 1;
305*4887Schin 				else
306*4887Schin 				{	f *= _Sfneg10[v];
307*4887Schin 					if((n += (1<<v)) >= SF_IDIGITS)
308*4887Schin 						return SF_INF;
309*4887Schin 				}
310*4887Schin 			} while(f >= (double)SF_MAXLONG);
311*4887Schin 		}
312*4887Schin 		*decpt = (int)n;
313*4887Schin 
314*4887Schin 		b = sp = buf + SF_INTPART;
315*4887Schin 		if((v = (long)f) != 0)
316*4887Schin 		{	/* translate the integer part */
317*4887Schin 			f -= (double)v;
318*4887Schin 
319*4887Schin 			sfucvt(v,sp,n,ep,long,ulong);
320*4887Schin 
321*4887Schin 			n = b-sp;
322*4887Schin 			if((*decpt += (int)n) >= SF_IDIGITS)
323*4887Schin 				return SF_INF;
324*4887Schin 			b = sp;
325*4887Schin 			sp = buf + SF_INTPART;
326*4887Schin 		}
327*4887Schin 		else	n = 0;
328*4887Schin 
329*4887Schin 		/* remaining number of digits to compute; add 1 for later rounding */
330*4887Schin 		n = (((format&SFFMT_EFORMAT) || *decpt <= 0) ? 1 : *decpt+1) - n;
331*4887Schin 		if(n_digit > 0)
332*4887Schin 		{	if(n_digit > DBL_DIG)
333*4887Schin 				n_digit = DBL_DIG;
334*4887Schin 			n += n_digit;
335*4887Schin 		}
336*4887Schin 
337*4887Schin 		if((ep = (sp+n)) > (endsp = buf+(size-2)))
338*4887Schin 			ep = endsp;
339*4887Schin 		if(sp > ep)
340*4887Schin 			sp = ep;
341*4887Schin 		else
342*4887Schin 		{
343*4887Schin 			if((format&SFFMT_EFORMAT) && *decpt == 0 && f > 0.)
344*4887Schin 			{	reg double	d;
345*4887Schin 				while((long)(d = f*10.) == 0)
346*4887Schin 				{	f = d;
347*4887Schin 					*decpt -= 1;
348*4887Schin 				}
349*4887Schin 			}
350*4887Schin 
351*4887Schin 			while(sp < ep)
352*4887Schin 			{	/* generate fractional digits */
353*4887Schin 				if(f <= 0.)
354*4887Schin 				{	/* fill with 0's */
355*4887Schin 					do { *sp++ = '0'; } while(sp < ep);
356*4887Schin 					goto done;
357*4887Schin 				}
358*4887Schin 				else if((n = (long)(f *= 10.)) < 10)
359*4887Schin 				{	*sp++ = (char)('0' + n);
360*4887Schin 					f -= n;
361*4887Schin 				}
362*4887Schin 				else /* n == 10 */
363*4887Schin 				{	do { *sp++ = '9'; } while(sp < ep);
364*4887Schin 				}
365*4887Schin 			}
366*4887Schin 		}
367*4887Schin 	}
368*4887Schin 
369*4887Schin 	if(ep <= b)
370*4887Schin 		ep = b+1;
371*4887Schin 	else if(ep < endsp)
372*4887Schin 	{	/* round the last digit */
373*4887Schin 		*--sp += 5;
374*4887Schin 		while(*sp > '9')
375*4887Schin 		{	*sp = '0';
376*4887Schin 			if(sp > b)
377*4887Schin 				*--sp += 1;
378*4887Schin 			else
379*4887Schin 			{	/* next power of 10 */
380*4887Schin 				*sp = '1';
381*4887Schin 				*decpt += 1;
382*4887Schin 				if(!(format&SFFMT_EFORMAT))
383*4887Schin 				{	/* add one more 0 for %f precision */
384*4887Schin 					ep[-1] = '0';
385*4887Schin 					ep += 1;
386*4887Schin 				}
387*4887Schin 			}
388*4887Schin 		}
389*4887Schin 	}
390*4887Schin 
391*4887Schin done:
392*4887Schin 	*--ep = '\0';
393*4887Schin 	if(len)
394*4887Schin 		*len = ep-b;
395*4887Schin 	return b;
396*4887Schin }
397