10 #define _MAX_CHARS 512
12 static char *lcset
= "0123456789abcdef";
15 double pvalue
, nvalue
;
31 nextdigit (double *value
)
35 *value
= modf (*value
* 10, &tmp
) ;
36 return lcset
[(int)tmp
];
41 print_nan (char *buffer
,
49 strcpy(buffer
, "nan");
55 strcpy(buffer
, "infinity");
68 /* A convert info struct */
71 char *buffer
; /* Destination of conversion */
72 double value
; /* scratch Value to convert */
73 double original_value
; /* saved Value to convert */
74 int value_neg
; /* OUT: 1 if value initialiy neg */
75 int abs_exp
; /* abs Decimal exponent of value */
76 int abs_exp_sign
; /* + or - */
77 int exp
; /* exp not sgned */
78 int type
; /* fFeEgG used in printing before exp */
80 int print_trailing_zeros
; /* Print 00's after a . */
82 int null_idx
; /* Index of the null at the end */
84 /* These ones are read only */
85 int decimal_places
; /* the number of digits to print after
87 int max_digits
; /* total number of digits to print */
88 int buffer_size
; /* Size of output buffer */
90 /* Two sorts of dot ness.
91 0 never ever print a dot
92 1 print a dot if followed by a digit
93 2 always print a dot, even if no digit following
95 enum { dot_never
, dot_sometimes
, dot_always
} dot
; /* Print a decimal point, always */
96 int dot_idx
; /* where the dot went, or would have gone */
101 renormalize (cvt_info_type
*in
)
104 /* Make sure all numbers are less than 1 */
106 while (in
->value
>= 1.0)
108 in
->value
= in
->value
* 0.1;
112 /* Now we have only numbers between 0 and .9999.., and have adjusted
113 exp to account for the shift */
117 in
->abs_exp_sign
= '+';
118 in
->abs_exp
= in
->exp
;
122 in
->abs_exp_sign
= '-';
123 in
->abs_exp
= -in
->exp
;
128 /* This routine looks at original_value, and makes it between 0 and 1,
129 modifying exp as it goes
133 normalize (double value
,
154 /* Work out texponent & normalise value */
156 /* If value > 1, then shrink it */
159 for (j
= 0; j
< 6; j
++)
161 while (value
>= powers
[j
].pvalue
)
163 value
/= powers
[j
].pvalue
;
164 texp
+= powers
[j
].exp
;
168 else if (value
!= 0.0)
170 for (j
= 0; j
< 6; j
++)
172 while (value
<= powers
[j
].nvalue
)
174 value
*= powers
[j
].pvalue
;
175 texp
-= powers
[j
].exp
;
189 in
->original_value
= value
;
194 round (cvt_info_type
*in
,
199 double rounder
= 5.0;
206 /* If the next digit to output would have been a '5' run back and */
207 /* see if we can create a more rounded number. If we can then do it.
208 If not (like when the number was 9.9 and the last char was
209 another 9), then we'll have to modify the number and try again */
214 for (p
= now
;!ok
&& p
>= start
; p
--)
223 rounder
= rounder
* 0.1;
239 else if (*p
!= '.') {
249 /* Getting here means that we couldn't round the number in place
250 textually - there have been all nines.
251 We'll have to add to it and try the conversion again
253 .99999[9] can't be rounded in place, so add
254 .000005 to it giving:
255 1.000004 we notice that the result is > 1 so add to exp and
260 in
->original_value
= in
->value
= in
->original_value
+ rounder
;
261 normalize(in
->original_value
, in
);
270 _cvte (register cvt_info_type
*in
)
275 int after_decimal
=0;
277 in
->buffer
[buffer_idx
++] = nextdigit(&(in
->value
));
279 in
->dot_idx
= buffer_idx
;
287 if (in
->decimal_places
288 && digit
< in
->max_digits
)
290 in
->buffer
[buffer_idx
++] = '.';
294 in
->buffer
[buffer_idx
++] = '.';
298 while (buffer_idx
< in
->buffer_size
299 && after_decimal
< in
->decimal_places
300 && digit
< in
->max_digits
)
302 in
->buffer
[buffer_idx
] = nextdigit(&(in
->value
));
311 in
->buffer
+buffer_idx
,
312 nextdigit(&(in
->value
))))
318 in
->buffer
[buffer_idx
++] = in
->type
;
319 in
->buffer
[buffer_idx
++] = in
->abs_exp_sign
;
321 if (in
->abs_exp
>= 100)
323 in
->buffer
[buffer_idx
++] = lcset
[in
->abs_exp
/ 100];
326 in
->buffer
[buffer_idx
++] = lcset
[in
->abs_exp
/ 10];
327 in
->buffer
[buffer_idx
++] = lcset
[in
->abs_exp
% 10];
330 in
->buffer
[buffer_idx
++] = 0;
336 /* Produce NNNN.FFFF */
338 _cvtf (cvt_info_type
*in
)
341 int buffer_idx
= 0; /* Current char being output */
342 int after_decimal
= 0;
346 in
->dot_idx
= in
->exp
+ 1;
348 /* Two sorts of number, NNN.FFF and 0.0000...FFFF */
351 /* Print all the digits up to the decimal point */
353 while (buffer_idx
<= in
->exp
354 && digit
< in
->max_digits
355 && buffer_idx
< in
->buffer_size
)
357 in
->buffer
[buffer_idx
] = nextdigit(&(in
->value
));
363 /* And the decimal point if we should */
364 if (buffer_idx
< in
->buffer_size
)
372 /* Only print a dot if following chars */
373 if (in
->decimal_places
374 && digit
< in
->max_digits
)
376 in
->buffer
[buffer_idx
++] = '.';
381 in
->buffer
[buffer_idx
++] = '.';
386 /* And the digits following the point if necessary */
388 /* Only print the leading zeros if a dot was possible */
389 if (in
->dot
|| in
->exp
>0)
391 while (buffer_idx
< in
->buffer_size
392 && (in
->abs_exp_sign
== '-' && digit
< in
->abs_exp
- 1)
393 && (after_decimal
< in
->decimal_places
)
394 && (digit
< in
->max_digits
))
396 in
->buffer
[buffer_idx
] = '0';
403 while (buffer_idx
< in
->buffer_size
404 && after_decimal
< in
->decimal_places
405 && digit
< in
->max_digits
)
407 in
->buffer
[buffer_idx
] = nextdigit(&(in
->value
));
414 in
->null_idx
= buffer_idx
;
415 in
->buffer
[buffer_idx
] = 0;
416 if (round(in
, in
->buffer
, in
->buffer
+buffer_idx
,
417 nextdigit(&(in
->value
))))
442 in
.buffer_size
= 512;
444 if (!finite(invalue
))
446 return print_nan(buffer
, invalue
, precision
);
450 normalize(invalue
, &in
);
453 in
.dot
= dot
? dot_always
: dot_sometimes
;
460 /* When formatting a g, the precision refers to the number of
461 char positions *total*, this leads to various off by ones */
463 /* A precision of 0 means 1 */
467 /* A g turns into an e if there are more digits than the
468 precision, or it's smaller than e-4 */
469 if (in
.exp
>= precision
|| in
.exp
< -4)
471 in
.type
= (type
== 'g' ? 'e' : 'E');
472 in
.decimal_places
= _MAX_CHARS
;
473 in
.max_digits
= precision
;
474 in
.print_trailing_zeros
= 1;
479 /* G means total number of chars to print */
480 in
.decimal_places
= _MAX_CHARS
;
481 in
.max_digits
= precision
;
482 in
.type
= (type
== 'g' ? 'f' : 'F');
483 in
.print_trailing_zeros
= 0;
487 /* trim trailing zeros */
488 int j
= in
.null_idx
-1;
489 while (j
> 0 && in
.buffer
[j
] == '0')
494 /* Stamp on a . if not followed by zeros */
495 if (j
> 0 && buffer
[j
] == '.')
504 in
.decimal_places
= precision
;
505 in
.max_digits
= _MAX_CHARS
;
506 in
.print_trailing_zeros
= 1;
511 in
.print_trailing_zeros
= 1;
512 in
.decimal_places
= precision
;
513 in
.max_digits
= _MAX_CHARS
;
528 fcvtbuf (double invalue
,
535 in
.buffer
= fcvt_buf
;
536 in
.buffer_size
= 512;
538 if (!finite(invalue
))
540 return print_nan(fcvt_buf
, invalue
, ndigit
);
543 normalize(invalue
, &in
);
545 in
.dot
= dot_never
; /* Don't print a decimal point */
546 in
.max_digits
= _MAX_CHARS
;
547 in
.buffer_size
= _MAX_CHARS
; /* Take as many as needed */
548 in
.decimal_places
= ndigit
;
551 *sign
= in
.value_neg
;
557 ecvtbuf (double invalue
,
564 in
.buffer
= fcvt_buf
;
566 if (!finite(invalue
))
568 return print_nan(fcvt_buf
, invalue
, ndigit
);
571 normalize(invalue
, &in
);
574 in
.dot
= dot_never
; /* Don't print a decimal point */
575 /* We can work out how many digits go after the decimal point */
577 in
.buffer_size
=_MAX_CHARS
;
578 in
.decimal_places
= _MAX_CHARS
;
579 in
.max_digits
= ndigit
; /* Take as many as told */
582 *sign
= in
.value_neg
;
593 return _dcvt(buf
, d
, ndigit
, 0, 'g', 1);