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