xref: /netbsd-src/tests/lib/libc/stdlib/t_strtod.c (revision ca453df649ce9db45b64d73678ba06cbccf9aa11)
1 /*	$NetBSD: t_strtod.c,v 1.24 2011/07/08 05:10:05 jruoho Exp $ */
2 
3 /*-
4  * Copyright (c) 2011 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jukka Ruohonen.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /* Public domain, Otto Moerbeek <otto@drijf.net>, 2006. */
33 
34 #include <sys/cdefs.h>
35 __RCSID("$NetBSD: t_strtod.c,v 1.24 2011/07/08 05:10:05 jruoho Exp $");
36 
37 #include <sys/utsname.h>
38 
39 #include <errno.h>
40 #include <math.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 
45 #include <atf-c.h>
46 #include <atf-c/config.h>
47 
48 #if defined(__i386__) || defined(__amd64__) || defined(__sparc__)
49 #include <fenv.h>
50 #endif
51 
52 #if !defined(__vax__)
53 static const char * const inf_strings[] =
54     { "Inf", "INF", "-Inf", "-INF", "Infinity", "+Infinity",
55       "INFINITY", "-INFINITY", "InFiNiTy", "+InFiNiTy" };
56 const char *nan_string = "NaN(x)y";
57 #endif
58 
59 ATF_TC(strtod_basic);
60 ATF_TC_HEAD(strtod_basic, tc)
61 {
62 	atf_tc_set_md_var(tc, "descr", "A basic test of strtod(3)");
63 }
64 
65 ATF_TC_BODY(strtod_basic, tc)
66 {
67 	static const size_t n = 1024 * 1000;
68 
69 	for (size_t i = 1; i < n; i = i + 1024) {
70 		char buf[512];
71 		(void)snprintf(buf, sizeof(buf), "%zu.%zu", i, i + 1);
72 
73 		errno = 0;
74 		double d = strtod(buf, NULL);
75 
76 		ATF_REQUIRE(d > 0.0);
77 		ATF_REQUIRE(errno == 0);
78 	}
79 }
80 
81 ATF_TC(strtod_hex);
82 ATF_TC_HEAD(strtod_hex, tc)
83 {
84 	atf_tc_set_md_var(tc, "descr", "A strtod(3) with hexadecimals");
85 }
86 
87 #ifdef __vax__
88 #define SMALL_NUM       1.0e-38
89 #else
90 #define SMALL_NUM       1.0e-40
91 #endif
92 
93 ATF_TC_BODY(strtod_hex, tc)
94 {
95 	const char *str;
96 	char *end;
97 	double d;
98 
99 	str = "-0x0";
100 	d = strtod(str, &end);	/* -0.0 */
101 
102 	ATF_REQUIRE(end == str + 4);
103 	ATF_REQUIRE(signbit(d) != 0);
104 	ATF_REQUIRE(fabs(d) < SMALL_NUM);
105 
106 	str = "-0x";
107 	d = strtod(str, &end);	/* -0.0 */
108 
109 	ATF_REQUIRE(end == str + 2);
110 	ATF_REQUIRE(signbit(d) != 0);
111 	ATF_REQUIRE(fabs(d) < SMALL_NUM);
112 }
113 
114 ATF_TC(strtod_inf);
115 ATF_TC_HEAD(strtod_inf, tc)
116 {
117 	atf_tc_set_md_var(tc, "descr", "A strtod(3) with INF");
118 }
119 
120 ATF_TC_BODY(strtod_inf, tc)
121 {
122 #ifndef __vax__
123 	/*
124 	 * See the closed PR lib/33262.
125 	 */
126 	for (size_t i = 0; i < __arraycount(inf_strings); i++) {
127 		double d = strtod(inf_strings[i], NULL);
128 		ATF_REQUIRE(isinf(d) != 0);
129 	}
130 #else
131 	atf_tc_skip("vax not supported");
132 #endif
133 }
134 
135 ATF_TC(strtof_inf);
136 ATF_TC_HEAD(strtof_inf, tc)
137 {
138 	atf_tc_set_md_var(tc, "descr", "A strtof(3) with INF");
139 }
140 
141 ATF_TC_BODY(strtof_inf, tc)
142 {
143 #ifndef __vax__
144 	/*
145 	 * See the closed PR lib/33262.
146 	 */
147 	for (size_t i = 0; i < __arraycount(inf_strings); i++) {
148 		float f = strtof(inf_strings[i], NULL);
149 		ATF_REQUIRE(isinf(f) != 0);
150 	}
151 #else
152 	atf_tc_skip("vax not supported");
153 #endif
154 }
155 
156 ATF_TC(strtold_inf);
157 ATF_TC_HEAD(strtold_inf, tc)
158 {
159 	atf_tc_set_md_var(tc, "descr", "A strtold(3) with INF");
160 }
161 
162 ATF_TC_BODY(strtold_inf, tc)
163 {
164 #ifndef __vax__
165 #   ifdef __HAVE_LONG_DOUBLE
166 
167 	/*
168 	 * See the closed PR lib/33262.
169 	 *
170 	 * This may also fail under QEMU; cf. PR misc/44767.
171 	 */
172 	if (system("cpuctl identify 0 | grep -q QEMU") == 0)
173 		atf_tc_expect_fail("PR misc/44767");
174 
175 	for (size_t i = 0; i < __arraycount(inf_strings); i++) {
176 		long double ld = strtold(inf_strings[i], NULL);
177 		ATF_REQUIRE(isinf(ld) != 0);
178 	}
179 #   else
180 	atf_tc_skip("Requires long double support");
181 #   endif
182 #else
183 	atf_tc_skip("vax not supported");
184 #endif
185 }
186 
187 ATF_TC(strtod_nan);
188 ATF_TC_HEAD(strtod_nan, tc)
189 {
190 	atf_tc_set_md_var(tc, "descr", "A strtod(3) with NaN");
191 }
192 
193 ATF_TC_BODY(strtod_nan, tc)
194 {
195 #ifndef __vax__
196 	char *end;
197 
198 	double d = strtod(nan_string, &end);
199 	ATF_REQUIRE(isnan(d) != 0);
200 	ATF_REQUIRE(strcmp(end, "y") == 0);
201 #else
202 	atf_tc_skip("vax not supported");
203 #endif
204 }
205 
206 ATF_TC(strtof_nan);
207 ATF_TC_HEAD(strtof_nan, tc)
208 {
209 	atf_tc_set_md_var(tc, "descr", "A strtof(3) with NaN");
210 }
211 
212 ATF_TC_BODY(strtof_nan, tc)
213 {
214 #ifndef __vax__
215 	char *end;
216 
217 	float f = strtof(nan_string, &end);
218 	ATF_REQUIRE(isnanf(f) != 0);
219 	ATF_REQUIRE(strcmp(end, "y") == 0);
220 #else
221 	atf_tc_skip("vax not supported");
222 #endif
223 }
224 
225 ATF_TC(strtold_nan);
226 ATF_TC_HEAD(strtold_nan, tc)
227 {
228 	atf_tc_set_md_var(tc, "descr", "A strtold(3) with NaN");
229 }
230 
231 ATF_TC_BODY(strtold_nan, tc)
232 {
233 #ifndef __vax__
234 #   ifdef __HAVE_LONG_DOUBLE
235 
236 	char *end;
237 
238 	/*
239 	 * See PR lib/45020.
240 	 *
241 	 * This may also fail under QEMU; cf. PR misc/44767.
242 	 */
243 	if (system("cpuctl identify 0 | grep -q QEMU") == 0)
244 		atf_tc_expect_fail("PR misc/44767");
245 
246 	long double ld = strtold(nan_string, &end);
247 	ATF_REQUIRE(isnan(ld) != 0);
248 	ATF_REQUIRE(__isnanl(ld) != 0);
249 	ATF_REQUIRE(strcmp(end, "y") == 0);
250 #   else
251 	atf_tc_skip("Requires long double support");
252 #   endif
253 #else
254 	atf_tc_skip("vax not supported");
255 #endif
256 }
257 
258 ATF_TC(strtod_round);
259 ATF_TC_HEAD(strtod_round, tc)
260 {
261 	atf_tc_set_md_var(tc, "descr", "Test rouding in strtod(3)");
262 }
263 
264 ATF_TC_BODY(strtod_round, tc)
265 {
266 #if defined(__i386__) || defined(__amd64__) || defined(__sparc__)
267 
268 	struct utsname utsname;
269 
270 	/*
271 	 * Test that strtod(3) honors the current rounding mode.
272 	 * The used value is somewhere near 1 + DBL_EPSILON + FLT_EPSILON.
273 	 *
274 	 * May fail under QEMU; cf. PR misc/44767.
275 	 */
276 	ATF_REQUIRE(uname(&utsname) == 0);
277 
278 	if (strcmp(utsname.machine, "amd64") == 0 &&
279 	    system("cpuctl identify 0 | grep -q QEMU") == 0)
280 		atf_tc_expect_fail("PR misc/44767");
281 
282 	const char *val =
283 	    "1.00000011920928977282585492503130808472633361816406";
284 
285 	(void)fesetround(FE_UPWARD);
286 
287 	double d1 = strtod(val, NULL);
288 
289 	(void)fesetround(FE_DOWNWARD);
290 
291 	double d2 = strtod(val, NULL);
292 
293 	ATF_REQUIRE(fabs(d1 - d2) > 0.0);
294 #else
295 	atf_tc_skip("Requires one of i386, amd64 or sparc");
296 #endif
297 }
298 
299 ATF_TC(strtod_underflow);
300 ATF_TC_HEAD(strtod_underflow, tc)
301 {
302 	atf_tc_set_md_var(tc, "descr", "Test underflow in strtod(3)");
303 }
304 
305 ATF_TC_BODY(strtod_underflow, tc)
306 {
307 
308 	const char *tmp =
309 	    "0.0000000000000000000000000000000000000000000000000000"
310 	    "000000000000000000000000000000000000000000000000000000"
311 	    "000000000000000000000000000000000000000000000000000000"
312 	    "000000000000000000000000000000000000000000000000000000"
313 	    "000000000000000000000000000000000000000000000000000000"
314 	    "000000000000000000000000000000000000000000000000000000"
315 	    "000000000000000000000000000000000000000000000000000000"
316 	    "000000000000000002";
317 
318 	errno = 0;
319 	double d = strtod(tmp, NULL);
320 
321 	if (d != 0 || errno != ERANGE)
322 		atf_tc_fail("strtod(3) did not detect underflow");
323 }
324 
325 ATF_TP_ADD_TCS(tp)
326 {
327 
328 	ATF_TP_ADD_TC(tp, strtod_basic);
329 	ATF_TP_ADD_TC(tp, strtod_hex);
330 	ATF_TP_ADD_TC(tp, strtod_inf);
331 	ATF_TP_ADD_TC(tp, strtof_inf);
332 	ATF_TP_ADD_TC(tp, strtold_inf);
333 	ATF_TP_ADD_TC(tp, strtod_nan);
334 	ATF_TP_ADD_TC(tp, strtof_nan);
335 	ATF_TP_ADD_TC(tp, strtold_nan);
336 	ATF_TP_ADD_TC(tp, strtod_round);
337 	ATF_TP_ADD_TC(tp, strtod_underflow);
338 
339 	return atf_no_error();
340 }
341