Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libm / test / dcvt.c
blob56d5c2b6ba0644e7d9d3dd263650ce90ffb1b51e
3 #include <limits.h>
4 #include <math.h>
5 #include <stdio.h>
6 #include <float.h>
7 #include <ieeefp.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #define _MAX_CHARS 512
12 static char *lcset = "0123456789abcdef";
14 static struct p {
15 double pvalue, nvalue;
16 int exp;
17 } powers[] =
19 { 1e32, 1e-32, 32},
20 { 1e16, 1e-16, 16},
21 { 1e8, 1e-8, 8},
22 { 1e4, 1e-4, 4},
23 { 1e2, 1e-2, 2},
24 { 1e1, 1e-1, 1 },
25 { 1e0, 1e-0, 0 }
28 #define _MAX_PREC 16
30 static char
31 nextdigit (double *value)
33 double tmp;
35 *value = modf (*value * 10, &tmp) ;
36 return lcset[(int)tmp];
40 static char *
41 print_nan (char *buffer,
42 double value,
43 int precision)
45 size_t i;
47 if (isnan(value))
49 strcpy(buffer, "nan");
50 i = 3;
53 else
55 strcpy(buffer, "infinity");
56 i = 8;
59 while (i < precision)
61 buffer[i++] = ' ';
63 buffer[i++] = 0;
64 return buffer;
68 /* A convert info struct */
69 typedef 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
86 the decimal */
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 */
97 } cvt_info_type;
100 void
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;
109 in->exp++;
112 /* Now we have only numbers between 0 and .9999.., and have adjusted
113 exp to account for the shift */
115 if (in->exp >= 0)
117 in->abs_exp_sign = '+';
118 in->abs_exp = in->exp;
120 else
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
132 static void
133 normalize (double value,
134 cvt_info_type *in)
136 int j;
137 int texp;
138 if (value != 0)
140 texp = -1;
143 if (value < 0.0)
145 in->value_neg =1 ;
146 value = - value;
148 else
150 in->value_neg = 0;
154 /* Work out texponent & normalise value */
156 /* If value > 1, then shrink it */
157 if (value >= 1.0)
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;
181 else
183 texp = 0;
187 in->exp = texp;
188 in->value = value;
189 in->original_value = value;
190 renormalize(in);
194 round (cvt_info_type *in,
195 char *start,
196 char *now,
197 char ch)
199 double rounder = 5.0;
201 char *p;
202 int ok = 0;
204 now --;
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 */
210 if (ch < '5')
211 return 0;
214 for (p = now;!ok && p >= start; p--)
216 switch (*p)
218 default:
219 abort();
220 case '.':
221 break;
222 case '9':
223 rounder = rounder * 0.1;
224 break;
225 case '8':
226 case '7':
227 case '6':
228 case '5':
229 case '4':
230 case '3':
231 case '2':
232 case '1':
233 case '0':
234 p = now;
235 while (1) {
236 if (*p == '9') {
237 *p = '0';
239 else if (*p != '.') {
240 (*p)++;
241 return 0;
243 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
256 divide by 10
257 .100004
260 in->original_value = in->value = in->original_value + rounder;
261 normalize(in->original_value , in);
262 return 1;
269 void
270 _cvte (register cvt_info_type *in)
272 int buffer_idx =0;
273 int digit = 0;
275 int after_decimal =0;
277 in->buffer[buffer_idx++] = nextdigit(&(in->value));
278 digit++;
279 in->dot_idx = buffer_idx;
282 switch (in->dot)
284 case dot_never:
285 break;
286 case dot_sometimes:
287 if (in->decimal_places
288 && digit < in->max_digits)
290 in->buffer[buffer_idx++] = '.';
292 break;
293 case dot_always:
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));
303 after_decimal++;
304 buffer_idx++;
305 digit++;
309 if (round(in,
310 in->buffer,
311 in->buffer+buffer_idx,
312 nextdigit(&(in->value))))
314 _cvte(in);
316 else
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];
324 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 */
337 void
338 _cvtf (cvt_info_type *in)
341 int buffer_idx = 0; /* Current char being output */
342 int after_decimal = 0;
343 int digit =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));
358 buffer_idx++;
359 digit ++;
363 /* And the decimal point if we should */
364 if (buffer_idx < in->buffer_size)
367 switch (in->dot)
369 case dot_never:
370 break;
371 case dot_sometimes:
372 /* Only print a dot if following chars */
373 if (in->decimal_places
374 && digit < in->max_digits )
376 in->buffer[buffer_idx++] = '.';
379 break;
380 case dot_always:
381 in->buffer[buffer_idx++] = '.';
384 after_decimal = 0;
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';
397 buffer_idx++;
398 digit++;
399 after_decimal++;
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));
408 buffer_idx++;
409 digit++;
410 after_decimal++;
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))))
419 _cvtf(in);
429 char *
430 _dcvt (char *buffer,
431 double invalue,
432 int precision,
433 int width,
434 char type,
435 int dot)
437 cvt_info_type in;
441 in.buffer = buffer;
442 in.buffer_size = 512;
444 if (!finite(invalue))
446 return print_nan(buffer, invalue, precision);
450 normalize(invalue, &in);
452 in.type = type;
453 in.dot = dot? dot_always: dot_sometimes;
455 switch (type)
458 case 'g':
459 case 'G':
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 */
464 if (precision == 0)
465 precision = 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;
475 _cvte(&in);
477 else
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;
484 _cvtf(&in);
486 if (!dot) {
487 /* trim trailing zeros */
488 int j = in.null_idx -1;
489 while (j > 0 && in.buffer[j] == '0')
491 in.buffer[j] = 0;
492 j--;
494 /* Stamp on a . if not followed by zeros */
495 if (j > 0 && buffer[j] == '.')
496 in.buffer[j] = 0;
501 break;
502 case 'f':
503 case 'F':
504 in.decimal_places= precision;
505 in.max_digits = _MAX_CHARS;
506 in.print_trailing_zeros = 1;
507 _cvtf(&in);
508 break;
509 case 'e':
510 case 'E':
511 in.print_trailing_zeros = 1;
512 in.decimal_places = precision;
513 in.max_digits = _MAX_CHARS;
514 _cvte(&in);
515 break;
521 return buffer;
527 char *
528 fcvtbuf (double invalue,
529 int ndigit,
530 int *decpt,
531 int *sign,
532 char *fcvt_buf)
534 cvt_info_type in;
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;
549 _cvtf(&in);
550 *decpt = in.dot_idx;
551 *sign = in.value_neg;
552 return in.buffer;
556 char *
557 ecvtbuf (double invalue,
558 int ndigit,
559 int *decpt,
560 int *sign,
561 char *fcvt_buf)
563 cvt_info_type in;
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 */
580 _cvtf(&in);
581 *decpt = in.dot_idx;
582 *sign = in.value_neg;
583 return in.buffer;
588 char *
589 gcvt (double d,
590 int ndigit,
591 char *buf)
593 return _dcvt(buf, d, ndigit, 0, 'g', 1);