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