1 /* Compare numeric strings. This is an internal include file.
3 Copyright (C) 1988, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
4 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 /* Written by Mike Haertel. */
21 #ifndef STRNUMCMP_IN_H
22 # define STRNUMCMP_IN_H 1
24 # include "strnumcmp.h"
28 # define NEGATION_SIGN '-'
29 # define NUMERIC_ZERO '0'
31 /* ISDIGIT differs from isdigit, as follows:
32 - Its arg may be any int or unsigned int; it need not be an unsigned char
34 - It's typically faster.
35 POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
36 isdigit unless it's important to use the locale's definition
37 of `digit' even when the host does not conform to POSIX. */
38 # define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
41 /* Compare strings A and B containing decimal fractions < 1.
42 DECIMAL_POINT is the decimal point. Each string
43 should begin with a decimal point followed immediately by the digits
44 of the fraction. Strings not of this form are treated as zero. */
46 /* The goal here, is to take two numbers a and b... compare these
47 in parallel. Instead of converting each, and then comparing the
48 outcome. Most likely stopping the comparison before the conversion
49 is complete. The algorithm used, in the old "sort" utility:
51 Algorithm: fraccompare
52 Action : compare two decimal fractions
53 accepts : char *a, char *b
54 returns : -1 if a<b, 0 if a=b, 1 if a>b.
57 if *a == decimal_point AND *b == decimal_point
58 find first character different in a and b.
59 if both are digits, return the difference *a - *b.
62 if digit return 1, else 0
65 if digit return -1, else 0
66 if *a is a decimal_point
67 skip past decimal_point and zeros
68 if digit return 1, else 0
69 if *b is a decimal_point
70 skip past decimal_point and zeros
71 if digit return -1, else 0
75 fraccompare (char const *a
, char const *b
, char decimal_point
)
77 if (*a
== decimal_point
&& *b
== decimal_point
)
82 if (ISDIGIT (*a
) && ISDIGIT (*b
))
85 goto a_trailing_nonzero
;
87 goto b_trailing_nonzero
;
90 else if (*a
++ == decimal_point
)
93 while (*a
== NUMERIC_ZERO
)
97 else if (*b
++ == decimal_point
)
100 while (*b
== NUMERIC_ZERO
)
102 return - ISDIGIT (*b
);
107 /* Compare strings A and B as numbers without explicitly converting
108 them to machine numbers, to avoid overflow problems and perhaps
109 improve performance. DECIMAL_POINT is the decimal point and
110 THOUSANDS_SEP the thousands separator. A DECIMAL_POINT of -1
111 causes comparisons to act as if there is no decimal point
112 character, and likewise for THOUSANDS_SEP. */
115 numcompare (char const *a
, char const *b
,
116 int decimal_point
, int thousands_sep
)
118 unsigned char tmpa
= *a
;
119 unsigned char tmpb
= *b
;
124 if (tmpa
== NEGATION_SIGN
)
128 while (tmpa
== NUMERIC_ZERO
|| tmpa
== thousands_sep
);
129 if (tmpb
!= NEGATION_SIGN
)
131 if (tmpa
== decimal_point
)
134 while (tmpa
== NUMERIC_ZERO
);
137 while (tmpb
== NUMERIC_ZERO
|| tmpb
== thousands_sep
)
139 if (tmpb
== decimal_point
)
142 while (tmpb
== NUMERIC_ZERO
);
143 return - ISDIGIT (tmpb
);
147 while (tmpb
== NUMERIC_ZERO
|| tmpb
== thousands_sep
);
149 while (tmpa
== tmpb
&& ISDIGIT (tmpa
))
153 while (tmpa
== thousands_sep
);
156 while (tmpb
== thousands_sep
);
159 if ((tmpa
== decimal_point
&& !ISDIGIT (tmpb
))
160 || (tmpb
== decimal_point
&& !ISDIGIT (tmpa
)))
161 return fraccompare (b
, a
, decimal_point
);
165 for (log_a
= 0; ISDIGIT (tmpa
); ++log_a
)
168 while (tmpa
== thousands_sep
);
170 for (log_b
= 0; ISDIGIT (tmpb
); ++log_b
)
173 while (tmpb
== thousands_sep
);
176 return log_a
< log_b
? 1 : -1;
183 else if (tmpb
== NEGATION_SIGN
)
187 while (tmpb
== NUMERIC_ZERO
|| tmpb
== thousands_sep
);
188 if (tmpb
== decimal_point
)
191 while (tmpb
== NUMERIC_ZERO
);
194 while (tmpa
== NUMERIC_ZERO
|| tmpa
== thousands_sep
)
196 if (tmpa
== decimal_point
)
199 while (tmpa
== NUMERIC_ZERO
);
200 return ISDIGIT (tmpa
);
204 while (tmpa
== NUMERIC_ZERO
|| tmpa
== thousands_sep
)
206 while (tmpb
== NUMERIC_ZERO
|| tmpb
== thousands_sep
)
209 while (tmpa
== tmpb
&& ISDIGIT (tmpa
))
213 while (tmpa
== thousands_sep
);
216 while (tmpb
== thousands_sep
);
219 if ((tmpa
== decimal_point
&& !ISDIGIT (tmpb
))
220 || (tmpb
== decimal_point
&& !ISDIGIT (tmpa
)))
221 return fraccompare (a
, b
, decimal_point
);
225 for (log_a
= 0; ISDIGIT (tmpa
); ++log_a
)
228 while (tmpa
== thousands_sep
);
230 for (log_b
= 0; ISDIGIT (tmpb
); ++log_b
)
233 while (tmpb
== thousands_sep
);
236 return log_a
< log_b
? -1 : 1;