1 /*
2  * Copyright (c) 1994 Cygnus Support.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * and/or other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * at Cygnus Support, Inc.  Cygnus Support, Inc. may not be used to
11  * endorse or promote products derived from this software without
12  * specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 
19 #include <limits.h>
20 #include <math.h>
21 #include <stdio.h>
22 #include <float.h>
23 #include <ieeefp.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #define _MAX_CHARS 512
27 
28 static char *lcset = "0123456789abcdef";
29 
30 static struct p {
31 	double pvalue, nvalue;
32 	int exp;
33 } powers[] =
34 {
35 { 1e32, 1e-32, 32},
36 { 1e16, 1e-16, 16},
37 { 1e8, 1e-8, 8},
38 { 1e4, 1e-4, 4},
39 { 1e2, 1e-2, 2},
40 { 1e1, 1e-1, 1 },
41 { 1e0, 1e-0, 0 }
42 };
43 
44 #define _MAX_PREC 16
45 
46 static char
nextdigit(double * value)47 nextdigit (double *value)
48 {
49   double tmp;
50 
51   *value = modf (*value * 10, &tmp) ;
52   return  lcset[(int)tmp];
53 }
54 
55 
56 static char *
print_nan(char * buffer,double value,int precision)57 print_nan (char *buffer,
58        double value,
59        int precision)
60 {
61   size_t  i;
62 
63   if (isnan(value))
64     {
65       strcpy(buffer, "nan");
66       i = 3;
67 
68     }
69   else
70     {
71       strcpy(buffer, "infinity");
72       i = 8;
73     }
74 
75   while (i < precision)
76     {
77       buffer[i++] = ' ';
78     }
79   buffer[i++] = 0;
80   return buffer;
81 
82 }
83 
84 /* A convert info struct */
85 typedef struct
86 {
87   char *buffer ;		/* Destination of conversion */
88   double value;			/* scratch Value to convert */
89   double original_value;	/* saved Value to convert */
90   int value_neg;		/* OUT: 1 if value initialiy neg */
91   int abs_exp;			/* abs Decimal exponent of value */
92   int abs_exp_sign;		/* + or - */
93   int exp;			/* exp not sgned */
94   int type;			/* fFeEgG used in printing before exp */
95 
96   int print_trailing_zeros;     /* Print 00's after a . */
97 
98   int null_idx;  /* Index of the null at the end */
99 
100 /* These ones are read only */
101   int decimal_places;		/* the number of digits to print after
102 				   the decimal */
103   int max_digits;		/* total number of digits to print */
104   int buffer_size;              /* Size of output buffer */
105 
106   /* Two sorts of dot ness.
107      0  never ever print a dot
108      1  print a dot if followed by a digit
109      2  always print a dot, even if no digit following
110      */
111   enum { dot_never, dot_sometimes, dot_always} dot; /* Print a decimal point, always */
112   int dot_idx;			/* where the dot went, or would have gone */
113 } cvt_info_type;
114 
115 
116 void
renormalize(cvt_info_type * in)117 renormalize (cvt_info_type *in)
118 {
119 
120   /* Make sure all numbers are less than 1 */
121 
122   while (in->value >= 1.0)
123   {
124     in->value = in->value * 0.1;
125     in->exp++;
126   }
127 
128   /* Now we have only numbers between 0 and .9999.., and have adjusted
129      exp to account for the shift */
130 
131   if (in->exp >= 0)
132   {
133     in->abs_exp_sign = '+';
134     in->abs_exp = in->exp;
135   }
136   else
137   {
138     in->abs_exp_sign  = '-';
139     in->abs_exp = -in->exp;
140   }
141 
142 }
143 
144 /* This routine looks at original_value, and makes it between 0 and 1,
145    modifying exp as it goes
146  */
147 
148 static void
normalize(double value,cvt_info_type * in)149 normalize (double value,
150        cvt_info_type *in)
151 {
152   int j;
153   int texp;
154   if (value != 0)
155   {
156      texp = -1;
157 
158 
159   if (value < 0.0)
160   {
161     in->value_neg =1 ;
162     value = - value;
163   }
164   else
165   {
166     in->value_neg = 0;
167   }
168 
169 
170   /* Work out texponent & normalise value */
171 
172   /* If value > 1, then shrink it */
173   if (value >= 1.0)
174   {
175     for (j = 0; j < 6; j++)
176     {
177       while (value >= powers[j].pvalue)
178       {
179 	value /= powers[j].pvalue;
180 	texp += powers[j].exp;
181       }
182     }
183   }
184   else if (value != 0.0)
185   {
186     for (j = 0; j < 6; j++)
187     {
188       while (value <= powers[j].nvalue)
189       {
190 	value *= powers[j].pvalue;
191 	texp -= powers[j].exp;
192       }
193     }
194   }
195    }
196 
197   else
198   {
199     texp = 0;
200   }
201 
202 
203   in->exp = texp;
204   in->value = value;
205   in->original_value = value;
206   renormalize(in);
207 
208 }
209 int
dcvt_round(cvt_info_type * in,char * start,char * now,char ch)210 dcvt_round (cvt_info_type *in,
211        char *start,
212        char *now,
213        char ch)
214 {
215   double rounder = 5.0;
216 
217   char *p;
218   int ok = 0;
219 
220   now --;
221 
222   /* If the next digit to output would have been a '5' run back and */
223   /* see if we can create a more rounded number. If we can then do it.
224      If not (like when the number was 9.9 and the last char was
225      another 9), then we'll have to modify the number and try again */
226   if (ch < '5')
227    return 0;
228 
229 
230   for (p = now;!ok && p >= start; p--)
231   {
232     switch (*p)
233     {
234     default:
235       abort();
236     case '.':
237       break;
238     case '9':
239       rounder = rounder * 0.1;
240       break;
241     case '8':
242     case '7':
243     case '6':
244     case '5':
245     case '4':
246     case '3':
247     case '2':
248     case '1':
249     case '0':
250       p = now;
251       while (1) {
252 	  if (*p == '9') {
253 	      *p = '0';
254 	    }
255 	  else if (*p != '.') {
256 	      (*p)++;
257 	      return 0;
258 	    }
259 	  p--;
260 	}
261     }
262 
263   }
264 
265   /* Getting here means that we couldn't round the number in place
266      textually - there have been all nines.
267      We'll have to add to it and try the conversion again
268      eg
269      .99999[9] can't be rounded in place, so add
270      .000005   to it giving:
271      1.000004   we notice that the result is > 1 so add to exp and
272      divide by 10
273      .100004
274      */
275 
276   in->original_value = in->value = in->original_value + rounder;
277   normalize(in->original_value , in);
278   return 1;
279 
280 
281 }
282 
283 
284 
285 void
_cvte(register cvt_info_type * in)286 _cvte (register  cvt_info_type *in)
287 {
288   int buffer_idx  =0;
289   int digit = 0;
290 
291   int after_decimal =0;
292 
293   in->buffer[buffer_idx++] = nextdigit(&(in->value));
294   digit++;
295   in->dot_idx = buffer_idx;
296 
297 
298   switch (in->dot)
299   {
300   case dot_never:
301     break;
302   case dot_sometimes:
303     if (in->decimal_places
304 	&& digit < in->max_digits)
305     {
306       in->buffer[buffer_idx++] = '.';
307     }
308     break;
309   case dot_always:
310     in->buffer[buffer_idx++] = '.';
311   }
312 
313 
314   while (buffer_idx < in->buffer_size
315 	 && after_decimal < in->decimal_places
316 	 && digit < in->max_digits)
317   {
318     in->buffer[buffer_idx] = nextdigit(&(in->value));
319     after_decimal++;
320     buffer_idx++;
321     digit++;
322 
323   }
324 
325   if (dcvt_round(in,
326 	    in->buffer,
327 	    in->buffer+buffer_idx,
328 	    nextdigit(&(in->value))))
329   {
330     _cvte(in);
331   }
332   else
333   {
334     in->buffer[buffer_idx++] = in->type;
335     in->buffer[buffer_idx++] = in->abs_exp_sign;
336 
337     if (in->abs_exp >= 100)
338     {
339       in->buffer[buffer_idx++] = lcset[in->abs_exp / 100];
340       in->abs_exp %= 100;
341     }
342     in->buffer[buffer_idx++] = lcset[in->abs_exp / 10];
343     in->buffer[buffer_idx++] = lcset[in->abs_exp % 10];
344   }
345 
346   in->buffer[buffer_idx++] = 0;
347 }
348 
349 
350 
351 
352 /* Produce NNNN.FFFF */
353 void
_cvtf(cvt_info_type * in)354 _cvtf (cvt_info_type *in)
355 {
356 
357   int buffer_idx = 0;		/* Current char being output */
358   int after_decimal = 0;
359   int digit =0;
360 
361 
362   in->dot_idx = in->exp + 1;
363 
364   /* Two sorts of number, NNN.FFF and 0.0000...FFFF */
365 
366 
367   /* Print all the digits up to the decimal point */
368 
369   while (buffer_idx <= in->exp
370 	 && digit < in->max_digits
371 	 && buffer_idx < in->buffer_size)
372   {
373     in->buffer[buffer_idx]  = nextdigit(&(in->value));
374     buffer_idx++;
375     digit ++;
376   }
377 
378 
379   /* And the decimal point if we should */
380   if (buffer_idx < in->buffer_size)
381   {
382 
383     switch (in->dot)
384     {
385     case dot_never:
386       break;
387     case dot_sometimes:
388       /* Only print a dot if following chars */
389       if (in->decimal_places
390 	  && digit < in->max_digits )
391       {
392        in->buffer[buffer_idx++] = '.';
393      }
394 
395       break;
396     case dot_always:
397       in->buffer[buffer_idx++] = '.';
398     }
399 
400     after_decimal = 0;
401 
402     /* And the digits following the point if necessary */
403 
404     /* Only print the leading zeros if a dot was possible */
405     if (in->dot || in->exp>0)
406     {
407      while (buffer_idx < in->buffer_size
408 	    && (in->abs_exp_sign == '-' && digit < in->abs_exp - 1)
409 	    && (after_decimal < in->decimal_places)
410 	    && (digit < in->max_digits))
411      {
412        in->buffer[buffer_idx] = '0';
413        buffer_idx++;
414        digit++;
415        after_decimal++;
416      }
417    }
418 
419     while (buffer_idx < in->buffer_size
420 	   && after_decimal < in->decimal_places
421 	   && digit < in->max_digits)
422     {
423       in->buffer[buffer_idx]  = nextdigit(&(in->value));
424       buffer_idx++;
425       digit++;
426       after_decimal++;
427     }
428   }
429 
430   in->null_idx = buffer_idx;
431   in->buffer[buffer_idx] = 0;
432   if (dcvt_round(in, in->buffer, in->buffer+buffer_idx,
433 	    nextdigit(&(in->value))))
434   {
435       _cvtf(in);
436   }
437 
438 
439 
440 
441 }
442 
443 
444 
445 char *
_dcvt(char * buffer,double invalue,int precision,int width,char type,int dot)446 _dcvt (char *buffer,
447        double invalue,
448        int precision,
449        int width,
450        char type,
451        int dot)
452 {
453   cvt_info_type in;
454 
455 
456 
457   in.buffer = buffer;
458   in.buffer_size = 512;
459 
460   if (!finite(invalue))
461   {
462     return print_nan(buffer, invalue, precision);
463   }
464 
465 
466   normalize(invalue, &in);
467 
468   in.type = type;
469   in.dot = dot? dot_always: dot_sometimes;
470 
471   switch (type)
472   {
473 
474   case 'g':
475   case 'G':
476     /* When formatting a g, the precision refers to the number of
477        char positions *total*, this leads to various off by ones */
478   {
479     /* A precision of 0 means 1 */
480     if (precision == 0)
481      precision = 1;
482 
483     /* A g turns into an e if there are more digits than the
484        precision, or it's smaller than e-4 */
485     if (in.exp >= precision || in.exp < -4)
486     {
487       in.type = (type == 'g' ? 'e' : 'E');
488       in.decimal_places = _MAX_CHARS;
489       in.max_digits = precision;
490       in.print_trailing_zeros = 1;
491       _cvte(&in);
492     }
493     else
494     {
495       /* G means total number of chars to print */
496       in.decimal_places = _MAX_CHARS;
497       in.max_digits = precision;
498       in.type = (type == 'g' ? 'f' : 'F');
499       in.print_trailing_zeros = 0;
500       _cvtf(&in);
501 
502    if (!dot) {
503        /* trim trailing zeros */
504        int j = in.null_idx -1;
505        while (j > 0 && in.buffer[j] == '0')
506        {
507 	 in.buffer[j] = 0;
508 	 j--;
509        }
510        /* Stamp on a . if not followed by zeros */
511        if (j > 0 && buffer[j] == '.')
512 	in.buffer[j] = 0;
513      }
514     }
515 
516 
517     break;
518   case 'f':
519   case 'F':
520     in.decimal_places= precision;
521     in.max_digits = _MAX_CHARS;
522       in.print_trailing_zeros = 1;
523     _cvtf(&in);
524     break;
525   case 'e':
526   case 'E':
527       in.print_trailing_zeros = 1;
528     in.decimal_places = precision;
529     in.max_digits = _MAX_CHARS;
530     _cvte(&in);
531     break;
532   }
533 
534   }
535 
536 
537   return buffer;
538 }
539 
540 
541 
542 
543 char *
fcvtbuf(double invalue,int ndigit,int * decpt,int * sign,char * fcvt_buf)544 fcvtbuf (double invalue,
545        int ndigit,
546        int *decpt,
547        int *sign,
548        char *fcvt_buf)
549 {
550   cvt_info_type in;
551   in.buffer = fcvt_buf;
552   in.buffer_size = 512;
553 
554   if (!finite(invalue))
555     {
556       return print_nan(fcvt_buf, invalue, ndigit);
557     }
558 
559   normalize(invalue, &in);
560 
561   in.dot = dot_never;			/* Don't print a decimal point */
562   in.max_digits = _MAX_CHARS;
563   in.buffer_size = _MAX_CHARS;		/* Take as many as needed */
564   in.decimal_places = ndigit;
565   _cvtf(&in);
566   *decpt = in.dot_idx;
567   *sign = in.value_neg;
568   return in.buffer;
569 }
570 
571 
572 char *
ecvtbuf(double invalue,int ndigit,int * decpt,int * sign,char * fcvt_buf)573 ecvtbuf (double invalue,
574        int ndigit,
575        int *decpt,
576        int *sign,
577        char *fcvt_buf)
578 {
579   cvt_info_type in;
580   in.buffer = fcvt_buf;
581 
582   if (!finite(invalue))
583     {
584       return print_nan(fcvt_buf, invalue, ndigit);
585     }
586 
587   normalize(invalue, &in);
588 
589 
590   in.dot = dot_never;			/* Don't print a decimal point */
591 /* We can work out how many digits go after the decimal point */
592 
593   in.buffer_size =_MAX_CHARS;
594   in.decimal_places = _MAX_CHARS;
595   in.max_digits = ndigit;		/* Take as many as told */
596   _cvtf(&in);
597   *decpt = in.dot_idx;
598   *sign = in.value_neg;
599   return in.buffer;
600 }
601 
602 
603 
604 char *
gcvt(double d,int ndigit,char * buf)605 gcvt (double d,
606    int ndigit,
607    char *buf)
608 {
609   return _dcvt(buf, d, ndigit, 0, 'g', 1);
610 }
611