1 | /* Basic tests for strtod. |
2 | Copyright (C) 1991-2024 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <ctype.h> |
20 | #include <locale.h> |
21 | #include <stddef.h> |
22 | #include <stdio.h> |
23 | #include <stdlib.h> |
24 | #include <errno.h> |
25 | #include <string.h> |
26 | #include <math.h> |
27 | |
28 | struct ltest |
29 | { |
30 | const char *str; /* Convert this. */ |
31 | double expect; /* To get this. */ |
32 | char left; /* With this left over. */ |
33 | int err; /* And this in errno. */ |
34 | }; |
35 | static const struct ltest tests[] = |
36 | { |
37 | { "12.345" , 12.345, '\0', 0 }, |
38 | { "12.345e19" , 12.345e19, '\0', 0 }, |
39 | { "-.1e+9" , -.1e+9, '\0', 0 }, |
40 | { ".125" , .125, '\0', 0 }, |
41 | { "1e20" , 1e20, '\0', 0 }, |
42 | { "0e-19" , 0, '\0', 0 }, |
43 | { "4\00012" , 4.0, '\0', 0 }, |
44 | { "5.9e-76" , 5.9e-76, '\0', 0 }, |
45 | { "0x1.4p+3" , 10.0, '\0', 0 }, |
46 | { "0xAp0" , 10.0, '\0', 0 }, |
47 | { "0x0Ap0" , 10.0, '\0', 0 }, |
48 | { "0x0A" , 10.0, '\0', 0 }, |
49 | { "0xA0" , 160.0, '\0', 0 }, |
50 | { "0x0.A0p8" , 160.0, '\0', 0 }, |
51 | { "0x0.50p9" , 160.0, '\0', 0 }, |
52 | { "0x0.28p10" , 160.0, '\0', 0 }, |
53 | { "0x0.14p11" , 160.0, '\0', 0 }, |
54 | { "0x0.0A0p12" , 160.0, '\0', 0 }, |
55 | { "0x0.050p13" , 160.0, '\0', 0 }, |
56 | { "0x0.028p14" , 160.0, '\0', 0 }, |
57 | { "0x0.014p15" , 160.0, '\0', 0 }, |
58 | { "0x00.00A0p16" , 160.0, '\0', 0 }, |
59 | { "0x00.0050p17" , 160.0, '\0', 0 }, |
60 | { "0x00.0028p18" , 160.0, '\0', 0 }, |
61 | { "0x00.0014p19" , 160.0, '\0', 0 }, |
62 | { "0x1p-1023" , |
63 | 1.11253692925360069154511635866620203210960799023116591527666e-308, |
64 | '\0', 0 }, |
65 | { "0x0.8p-1022" , |
66 | 1.11253692925360069154511635866620203210960799023116591527666e-308, |
67 | '\0', 0 }, |
68 | { "Inf" , HUGE_VAL, '\0', 0 }, |
69 | { "-Inf" , -HUGE_VAL, '\0', 0 }, |
70 | { "+InFiNiTy" , HUGE_VAL, '\0', 0 }, |
71 | { "0x80000Ap-23" , 0x80000Ap-23, '\0', 0 }, |
72 | { "1e-324" , 0, '\0', ERANGE }, |
73 | { "0x100000000000008p0" , 0x1p56, '\0', 0 }, |
74 | { "0x100000000000008.p0" , 0x1p56, '\0', 0 }, |
75 | { "0x100000000000008.00p0" , 0x1p56, '\0', 0 }, |
76 | { "0x10000000000000800p0" , 0x1p64, '\0', 0 }, |
77 | { "0x10000000000000801p0" , 0x1.0000000000001p64, '\0', 0 }, |
78 | { NULL, 0, '\0', 0 } |
79 | }; |
80 | |
81 | static void expand (char *dst, int c); |
82 | static int long_dbl (void); |
83 | |
84 | static int |
85 | do_test (void) |
86 | { |
87 | char buf[100]; |
88 | const struct ltest *lt; |
89 | char *ep; |
90 | int status = 0; |
91 | int save_errno; |
92 | |
93 | for (lt = tests; lt->str != NULL; ++lt) |
94 | { |
95 | double d; |
96 | |
97 | errno = 0; |
98 | d = strtod(lt->str, &ep); |
99 | save_errno = errno; |
100 | printf (format: "strtod (\"%s\") test %u" , |
101 | lt->str, (unsigned int) (lt - tests)); |
102 | if (d == lt->expect && *ep == lt->left && save_errno == lt->err) |
103 | puts (s: "\tOK" ); |
104 | else |
105 | { |
106 | puts (s: "\tBAD" ); |
107 | if (d != lt->expect) |
108 | printf (format: " returns %.60g, expected %.60g\n" , d, lt->expect); |
109 | if (lt->left != *ep) |
110 | { |
111 | char exp1[5], exp2[5]; |
112 | expand (dst: exp1, c: *ep); |
113 | expand (dst: exp2, c: lt->left); |
114 | printf (format: " leaves '%s', expected '%s'\n" , exp1, exp2); |
115 | } |
116 | if (save_errno != lt->err) |
117 | printf (format: " errno %d (%s) instead of %d (%s)\n" , |
118 | save_errno, strerror (errnum: save_errno), |
119 | lt->err, strerror (errnum: lt->err)); |
120 | status = 1; |
121 | } |
122 | } |
123 | |
124 | sprintf (buf, "%f" , strtod ("-0.0" , NULL)); |
125 | if (strcmp (buf, "-0.000000" ) != 0) |
126 | { |
127 | printf (format: " strtod (\"-0.0\", NULL) returns \"%s\"\n" , buf); |
128 | status = 1; |
129 | } |
130 | |
131 | const char input[] = "3752432815e-39" ; |
132 | |
133 | float f1 = strtold (input, NULL); |
134 | float f2; |
135 | float f3 = strtof (input, NULL); |
136 | sscanf (input, "%g" , &f2); |
137 | |
138 | if (f1 != f2) |
139 | { |
140 | printf (format: "f1 = %a != f2 = %a\n" , f1, f2); |
141 | status = 1; |
142 | } |
143 | if (f1 != f3) |
144 | { |
145 | printf (format: "f1 = %a != f3 = %a\n" , f1, f3); |
146 | status = 1; |
147 | } |
148 | if (f2 != f3) |
149 | { |
150 | printf (format: "f2 = %a != f3 = %a\n" , f2, f3); |
151 | status = 1; |
152 | } |
153 | |
154 | const char input2[] = "+1.000000000116415321826934814453125" ; |
155 | if (strtold (input2, NULL) != +1.000000000116415321826934814453125L) |
156 | { |
157 | printf (format: "input2: %La != %La\n" , strtold (input2, NULL), |
158 | +1.000000000116415321826934814453125L); |
159 | status = 1; |
160 | } |
161 | |
162 | static struct { const char *str; long double l; } ltests[] = |
163 | { |
164 | { "42.0000000000000000001" , 42.0000000000000000001L }, |
165 | { "42.00000000000000000001" , 42.00000000000000000001L }, |
166 | { "42.000000000000000000001" , 42.000000000000000000001L } |
167 | }; |
168 | int n; |
169 | for (n = 0; n < sizeof (ltests) / sizeof (ltests[0]); ++n) |
170 | if (strtold (ltests[n].str, NULL) != ltests[n].l) |
171 | { |
172 | printf (format: "ltests[%d]: %La != %La\n" , n, |
173 | strtold (ltests[n].str, NULL), ltests[n].l); |
174 | status = 1; |
175 | } |
176 | |
177 | status |= long_dbl (); |
178 | |
179 | return status ? EXIT_FAILURE : EXIT_SUCCESS; |
180 | } |
181 | |
182 | static void |
183 | expand (char *dst, int c) |
184 | { |
185 | if (isprint (c)) |
186 | { |
187 | dst[0] = c; |
188 | dst[1] = '\0'; |
189 | } |
190 | else |
191 | (void) sprintf (dst, "%#.3o" , (unsigned int) c); |
192 | } |
193 | |
194 | static int |
195 | long_dbl (void) |
196 | { |
197 | /* Regenerate this string using |
198 | |
199 | echo '(2^53-1)*2^(1024-53)' | bc | sed 's/\([^\]*\)\\*$/ "\1"/' |
200 | |
201 | */ |
202 | static const char longestdbl[] = |
203 | "17976931348623157081452742373170435679807056752584499659891747680315" |
204 | "72607800285387605895586327668781715404589535143824642343213268894641" |
205 | "82768467546703537516986049910576551282076245490090389328944075868508" |
206 | "45513394230458323690322294816580855933212334827479782620414472316873" |
207 | "8177180919299881250404026184124858368" ; |
208 | double d = strtod (longestdbl, NULL); |
209 | |
210 | printf (format: "strtod (\"%s\", NULL) = %g\n" , longestdbl, d); |
211 | |
212 | if (d != 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000) |
213 | return 1; |
214 | |
215 | return 0; |
216 | } |
217 | |
218 | #include <support/test-driver.c> |
219 | |