annotate lib/ftoastr.c @ 112308:474d5026a5a2

Regenerate.
author Paul Eggert <eggert@cs.ucla.edu>
date Sat, 08 Jan 2011 22:57:07 -0800
parents f31011c088d9
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
112305
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
1 /* floating point to accurate string
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
2
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
3 Copyright (C) 2010-2011 Free Software Foundation, Inc.
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
4
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
5 This program is free software: you can redistribute it and/or modify
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
6 it under the terms of the GNU General Public License as published by
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
7 the Free Software Foundation; either version 3 of the License, or
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
8 (at your option) any later version.
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
9
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
10 This program is distributed in the hope that it will be useful,
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
13 GNU General Public License for more details.
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
14
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
15 You should have received a copy of the GNU General Public License
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
17
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
18 /* Written by Paul Eggert. */
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
19
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
20 /* This code can misbehave on some buggy or older platforms, when
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
21 operating on arguments on floating types other than 'double', or
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
22 when given unusual combinations of options. Gnulib's
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
23 snprintf-posix module works around many of these problems.
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
24
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
25 This code relies on sprintf, strtod, etc. operating accurately;
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
26 otherwise, the resulting strings could be inaccurate or too long. */
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
27
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
28 #include <config.h>
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
29
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
30 #include "ftoastr.h"
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
31
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
32 #include "intprops.h"
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
33 #include <float.h>
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
34 #include <stdio.h>
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
35 #include <stdlib.h>
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
36
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
37 #if LENGTH == 3
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
38 # define FLOAT long double
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
39 # define FLOAT_DIG LDBL_DIG
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
40 # define FLOAT_MIN LDBL_MIN
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
41 # define FLOAT_PREC_BOUND _GL_LDBL_PREC_BOUND
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
42 # define FTOASTR ldtoastr
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
43 # define STRTOF strtold
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
44 #elif LENGTH == 2
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
45 # define FLOAT double
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
46 # define FLOAT_DIG DBL_DIG
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
47 # define FLOAT_MIN DBL_MIN
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
48 # define FLOAT_PREC_BOUND _GL_DBL_PREC_BOUND
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
49 # define FTOASTR dtoastr
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
50 # define STRTOF strtod
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
51 #else
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
52 # define LENGTH 1
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
53 # define FLOAT float
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
54 # define FLOAT_DIG FLT_DIG
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
55 # define FLOAT_MIN FLT_MIN
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
56 # define FLOAT_PREC_BOUND _GL_FLT_PREC_BOUND
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
57 # define FTOASTR ftoastr
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
58 # define STRTOF strtof
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
59 #endif
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
60
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
61 /* On pre-C99 hosts, approximate strtof and strtold with strtod. This
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
62 may generate one or two extra digits, but that's better than not
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
63 working at all. Assume that strtof works if strtold does. */
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
64 #if LENGTH != 2 && ! HAVE_C99_STRTOLD
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
65 # undef STRTOF
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
66 # define STRTOF strtod
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
67 #endif
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
68
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
69 /* On hosts where it's not known that snprintf works, use sprintf to
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
70 implement the subset needed here. Typically BUFSIZE is big enough
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
71 and there's little or no performance hit. */
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
72 #if ! GNULIB_SNPRINTF
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
73 # undef snprintf
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
74 # define snprintf ftoastr_snprintf
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
75 static int
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
76 ftoastr_snprintf (char *buf, size_t bufsize, char const *format,
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
77 int width, int prec, FLOAT x)
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
78 {
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
79 char width_0_buffer[LENGTH == 1 ? FLT_BUFSIZE_BOUND
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
80 : LENGTH == 2 ? DBL_BUFSIZE_BOUND
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
81 : LDBL_BUFSIZE_BOUND];
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
82 int n = width;
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
83 if (bufsize < sizeof width_0_buffer)
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
84 {
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
85 n = sprintf (width_0_buffer, format, 0, prec, x);
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
86 if (n < 0)
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
87 return n;
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
88 if (n < width)
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
89 n = width;
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
90 }
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
91 if (n < bufsize)
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
92 n = sprintf (buf, format, width, prec, x);
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
93 return n;
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
94 }
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
95 #endif
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
96
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
97 int
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
98 FTOASTR (char *buf, size_t bufsize, int flags, int width, FLOAT x)
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
99 {
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
100 /* The following method is simple but slow.
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
101 For ideas about speeding things up, please see:
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
102
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
103 Florian Loitsch, Printing floating-point numbers quickly and accurately
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
104 with integers. ACM SIGPLAN notices 46, 6 (June 2010), 233-243
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
105 <http://dx.doi.org/10.1145/1809028.1806623>; also see the
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
106 2010-03-21 draft <http://florian.loitsch.com/tmp/article.pdf>. */
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
107
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
108 char format[sizeof "%-+ 0*.*Lg"];
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
109 FLOAT abs_x = x < 0 ? -x : x;
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
110 int prec;
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
111
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
112 char *p = format;
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
113 *p++ = '%';
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
114
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
115 /* Support flags that generate output parsable by strtof. */
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
116 *p = '-'; p += (flags & FTOASTR_LEFT_JUSTIFY ) != 0;
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
117 *p = '+'; p += (flags & FTOASTR_ALWAYS_SIGNED ) != 0;
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
118 *p = ' '; p += (flags & FTOASTR_SPACE_POSITIVE) != 0;
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
119 *p = '0'; p += (flags & FTOASTR_ZERO_PAD ) != 0;
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
120
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
121 *p++ = '*';
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
122 *p++ = '.';
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
123 *p++ = '*';
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
124 *p = 'L'; p += 2 < LENGTH;
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
125 *p++ = flags & FTOASTR_UPPER_E ? 'G' : 'g';
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
126 *p = '\0';
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
127
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
128 for (prec = abs_x < FLOAT_MIN ? 1 : FLOAT_DIG; ; prec++)
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
129 {
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
130 int n = snprintf (buf, bufsize, format, width, prec, x);
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
131 if (n < 0
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
132 || FLOAT_PREC_BOUND <= prec
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
133 || (n < bufsize && STRTOF (buf, NULL) == x))
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
134 return n;
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
135 }
f31011c088d9 Regenerate.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
136 }