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