t_strtod.c revision 272343
1272343Sngie/*	$NetBSD: t_strtod.c,v 1.31 2012/09/26 07:24:38 jruoho Exp $ */
2272343Sngie
3272343Sngie/*-
4272343Sngie * Copyright (c) 2011 The NetBSD Foundation, Inc.
5272343Sngie * All rights reserved.
6272343Sngie *
7272343Sngie * This code is derived from software contributed to The NetBSD Foundation
8272343Sngie * by Jukka Ruohonen.
9272343Sngie *
10272343Sngie * Redistribution and use in source and binary forms, with or without
11272343Sngie * modification, are permitted provided that the following conditions
12272343Sngie * are met:
13272343Sngie * 1. Redistributions of source code must retain the above copyright
14272343Sngie *    notice, this list of conditions and the following disclaimer.
15272343Sngie * 2. Redistributions in binary form must reproduce the above copyright
16272343Sngie *    notice, this list of conditions and the following disclaimer in the
17272343Sngie *    documentation and/or other materials provided with the distribution.
18272343Sngie *
19272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22272343Sngie * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29272343Sngie * POSSIBILITY OF SUCH DAMAGE.
30272343Sngie */
31272343Sngie
32272343Sngie/* Public domain, Otto Moerbeek <otto@drijf.net>, 2006. */
33272343Sngie
34272343Sngie#include <sys/cdefs.h>
35272343Sngie__RCSID("$NetBSD: t_strtod.c,v 1.31 2012/09/26 07:24:38 jruoho Exp $");
36272343Sngie
37272343Sngie#include <errno.h>
38272343Sngie#include <math.h>
39272343Sngie#include <stdio.h>
40272343Sngie#include <stdlib.h>
41272343Sngie#include <string.h>
42272343Sngie
43272343Sngie#include <atf-c.h>
44272343Sngie#include <atf-c/config.h>
45272343Sngie
46272343Sngie#if defined(__i386__) || defined(__amd64__) || defined(__sparc__)
47272343Sngie#include <fenv.h>
48272343Sngie#endif
49272343Sngie
50272343Sngie#if !defined(__vax__)
51272343Sngiestatic const char * const inf_strings[] =
52272343Sngie    { "Inf", "INF", "-Inf", "-INF", "Infinity", "+Infinity",
53272343Sngie      "INFINITY", "-INFINITY", "InFiNiTy", "+InFiNiTy" };
54272343Sngieconst char *nan_string = "NaN(x)y";
55272343Sngie#endif
56272343Sngie
57272343SngieATF_TC(strtod_basic);
58272343SngieATF_TC_HEAD(strtod_basic, tc)
59272343Sngie{
60272343Sngie	atf_tc_set_md_var(tc, "descr", "A basic test of strtod(3)");
61272343Sngie}
62272343Sngie
63272343SngieATF_TC_BODY(strtod_basic, tc)
64272343Sngie{
65272343Sngie	static const size_t n = 1024 * 1000;
66272343Sngie
67272343Sngie	for (size_t i = 1; i < n; i = i + 1024) {
68272343Sngie		char buf[512];
69272343Sngie		(void)snprintf(buf, sizeof(buf), "%zu.%zu", i, i + 1);
70272343Sngie
71272343Sngie		errno = 0;
72272343Sngie		double d = strtod(buf, NULL);
73272343Sngie
74272343Sngie		ATF_REQUIRE(d > 0.0);
75272343Sngie		ATF_REQUIRE(errno == 0);
76272343Sngie	}
77272343Sngie}
78272343Sngie
79272343SngieATF_TC(strtod_hex);
80272343SngieATF_TC_HEAD(strtod_hex, tc)
81272343Sngie{
82272343Sngie	atf_tc_set_md_var(tc, "descr", "A strtod(3) with hexadecimals");
83272343Sngie}
84272343Sngie
85272343Sngie#ifdef __vax__
86272343Sngie#define SMALL_NUM       1.0e-38
87272343Sngie#else
88272343Sngie#define SMALL_NUM       1.0e-40
89272343Sngie#endif
90272343Sngie
91272343SngieATF_TC_BODY(strtod_hex, tc)
92272343Sngie{
93272343Sngie	const char *str;
94272343Sngie	char *end;
95272343Sngie	volatile double d;
96272343Sngie
97272343Sngie	str = "-0x0";
98272343Sngie	d = strtod(str, &end);	/* -0.0 */
99272343Sngie
100272343Sngie	ATF_REQUIRE(end == str + 4);
101272343Sngie	ATF_REQUIRE(signbit(d) != 0);
102272343Sngie	ATF_REQUIRE(fabs(d) < SMALL_NUM);
103272343Sngie
104272343Sngie	str = "-0x";
105272343Sngie	d = strtod(str, &end);	/* -0.0 */
106272343Sngie
107272343Sngie	ATF_REQUIRE(end == str + 2);
108272343Sngie	ATF_REQUIRE(signbit(d) != 0);
109272343Sngie	ATF_REQUIRE(fabs(d) < SMALL_NUM);
110272343Sngie}
111272343Sngie
112272343SngieATF_TC(strtod_inf);
113272343SngieATF_TC_HEAD(strtod_inf, tc)
114272343Sngie{
115272343Sngie	atf_tc_set_md_var(tc, "descr", "A strtod(3) with INF (PR lib/33262)");
116272343Sngie}
117272343Sngie
118272343SngieATF_TC_BODY(strtod_inf, tc)
119272343Sngie{
120272343Sngie#ifndef __vax__
121272343Sngie	for (size_t i = 0; i < __arraycount(inf_strings); i++) {
122272343Sngie		volatile double d = strtod(inf_strings[i], NULL);
123272343Sngie		ATF_REQUIRE(isinf(d) != 0);
124272343Sngie	}
125272343Sngie#else
126272343Sngie	atf_tc_skip("vax not supported");
127272343Sngie#endif
128272343Sngie}
129272343Sngie
130272343SngieATF_TC(strtof_inf);
131272343SngieATF_TC_HEAD(strtof_inf, tc)
132272343Sngie{
133272343Sngie	atf_tc_set_md_var(tc, "descr", "A strtof(3) with INF (PR lib/33262)");
134272343Sngie}
135272343Sngie
136272343SngieATF_TC_BODY(strtof_inf, tc)
137272343Sngie{
138272343Sngie#ifndef __vax__
139272343Sngie	for (size_t i = 0; i < __arraycount(inf_strings); i++) {
140272343Sngie		volatile float f = strtof(inf_strings[i], NULL);
141272343Sngie		ATF_REQUIRE(isinf(f) != 0);
142272343Sngie	}
143272343Sngie#else
144272343Sngie	atf_tc_skip("vax not supported");
145272343Sngie#endif
146272343Sngie}
147272343Sngie
148272343SngieATF_TC(strtold_inf);
149272343SngieATF_TC_HEAD(strtold_inf, tc)
150272343Sngie{
151272343Sngie	atf_tc_set_md_var(tc, "descr", "A strtold(3) with INF (PR lib/33262)");
152272343Sngie}
153272343Sngie
154272343SngieATF_TC_BODY(strtold_inf, tc)
155272343Sngie{
156272343Sngie#ifndef __vax__
157272343Sngie#   ifdef __HAVE_LONG_DOUBLE
158272343Sngie
159272343Sngie	for (size_t i = 0; i < __arraycount(inf_strings); i++) {
160272343Sngie		volatile long double ld = strtold(inf_strings[i], NULL);
161272343Sngie		ATF_REQUIRE(isinf(ld) != 0);
162272343Sngie	}
163272343Sngie#   else
164272343Sngie	atf_tc_skip("Requires long double support");
165272343Sngie#   endif
166272343Sngie#else
167272343Sngie	atf_tc_skip("vax not supported");
168272343Sngie#endif
169272343Sngie}
170272343Sngie
171272343SngieATF_TC(strtod_nan);
172272343SngieATF_TC_HEAD(strtod_nan, tc)
173272343Sngie{
174272343Sngie	atf_tc_set_md_var(tc, "descr", "A strtod(3) with NaN");
175272343Sngie}
176272343Sngie
177272343SngieATF_TC_BODY(strtod_nan, tc)
178272343Sngie{
179272343Sngie#ifndef __vax__
180272343Sngie	char *end;
181272343Sngie
182272343Sngie	volatile double d = strtod(nan_string, &end);
183272343Sngie	ATF_REQUIRE(isnan(d) != 0);
184272343Sngie	ATF_REQUIRE(strcmp(end, "y") == 0);
185272343Sngie#else
186272343Sngie	atf_tc_skip("vax not supported");
187272343Sngie#endif
188272343Sngie}
189272343Sngie
190272343SngieATF_TC(strtof_nan);
191272343SngieATF_TC_HEAD(strtof_nan, tc)
192272343Sngie{
193272343Sngie	atf_tc_set_md_var(tc, "descr", "A strtof(3) with NaN");
194272343Sngie}
195272343Sngie
196272343SngieATF_TC_BODY(strtof_nan, tc)
197272343Sngie{
198272343Sngie#ifndef __vax__
199272343Sngie	char *end;
200272343Sngie
201272343Sngie	volatile float f = strtof(nan_string, &end);
202272343Sngie	ATF_REQUIRE(isnanf(f) != 0);
203272343Sngie	ATF_REQUIRE(strcmp(end, "y") == 0);
204272343Sngie#else
205272343Sngie	atf_tc_skip("vax not supported");
206272343Sngie#endif
207272343Sngie}
208272343Sngie
209272343SngieATF_TC(strtold_nan);
210272343SngieATF_TC_HEAD(strtold_nan, tc)
211272343Sngie{
212272343Sngie	atf_tc_set_md_var(tc, "descr", "A strtold(3) with NaN (PR lib/45020)");
213272343Sngie}
214272343Sngie
215272343SngieATF_TC_BODY(strtold_nan, tc)
216272343Sngie{
217272343Sngie#ifndef __vax__
218272343Sngie#   ifdef __HAVE_LONG_DOUBLE
219272343Sngie
220272343Sngie	char *end;
221272343Sngie
222272343Sngie	volatile long double ld = strtold(nan_string, &end);
223272343Sngie	ATF_REQUIRE(isnan(ld) != 0);
224272343Sngie	ATF_REQUIRE(__isnanl(ld) != 0);
225272343Sngie	ATF_REQUIRE(strcmp(end, "y") == 0);
226272343Sngie#   else
227272343Sngie	atf_tc_skip("Requires long double support");
228272343Sngie#   endif
229272343Sngie#else
230272343Sngie	atf_tc_skip("vax not supported");
231272343Sngie#endif
232272343Sngie}
233272343Sngie
234272343SngieATF_TC(strtod_round);
235272343SngieATF_TC_HEAD(strtod_round, tc)
236272343Sngie{
237272343Sngie	atf_tc_set_md_var(tc, "descr", "Test rouding in strtod(3)");
238272343Sngie}
239272343Sngie
240272343SngieATF_TC_BODY(strtod_round, tc)
241272343Sngie{
242272343Sngie#if defined(__i386__) || defined(__amd64__) || defined(__sparc__)
243272343Sngie
244272343Sngie	/*
245272343Sngie	 * Test that strtod(3) honors the current rounding mode.
246272343Sngie	 * The used value is somewhere near 1 + DBL_EPSILON + FLT_EPSILON.
247272343Sngie	 */
248272343Sngie	const char *val =
249272343Sngie	    "1.00000011920928977282585492503130808472633361816406";
250272343Sngie
251272343Sngie	(void)fesetround(FE_UPWARD);
252272343Sngie
253272343Sngie	volatile double d1 = strtod(val, NULL);
254272343Sngie
255272343Sngie	(void)fesetround(FE_DOWNWARD);
256272343Sngie
257272343Sngie	volatile double d2 = strtod(val, NULL);
258272343Sngie
259272343Sngie	if (fabs(d1 - d2) > 0.0)
260272343Sngie		return;
261272343Sngie	else {
262272343Sngie		atf_tc_expect_fail("PR misc/44767");
263272343Sngie		atf_tc_fail("strtod(3) did not honor fesetround(3)");
264272343Sngie	}
265272343Sngie#else
266272343Sngie	atf_tc_skip("Requires one of i386, amd64 or sparc");
267272343Sngie#endif
268272343Sngie}
269272343Sngie
270272343SngieATF_TC(strtod_underflow);
271272343SngieATF_TC_HEAD(strtod_underflow, tc)
272272343Sngie{
273272343Sngie	atf_tc_set_md_var(tc, "descr", "Test underflow in strtod(3)");
274272343Sngie}
275272343Sngie
276272343SngieATF_TC_BODY(strtod_underflow, tc)
277272343Sngie{
278272343Sngie
279272343Sngie	const char *tmp =
280272343Sngie	    "0.0000000000000000000000000000000000000000000000000000"
281272343Sngie	    "000000000000000000000000000000000000000000000000000000"
282272343Sngie	    "000000000000000000000000000000000000000000000000000000"
283272343Sngie	    "000000000000000000000000000000000000000000000000000000"
284272343Sngie	    "000000000000000000000000000000000000000000000000000000"
285272343Sngie	    "000000000000000000000000000000000000000000000000000000"
286272343Sngie	    "000000000000000000000000000000000000000000000000000000"
287272343Sngie	    "000000000000000002";
288272343Sngie
289272343Sngie	errno = 0;
290272343Sngie	volatile double d = strtod(tmp, NULL);
291272343Sngie
292272343Sngie	if (d != 0 || errno != ERANGE)
293272343Sngie		atf_tc_fail("strtod(3) did not detect underflow");
294272343Sngie}
295272343Sngie
296272343Sngie/*
297272343Sngie * Bug found by Geza Herman.
298272343Sngie * See
299272343Sngie * http://www.exploringbinary.com/a-bug-in-the-bigcomp-function-of-david-gays-strtod/
300272343Sngie */
301272343SngieATF_TC(strtod_gherman_bug);
302272343SngieATF_TC_HEAD(strtod_gherman_bug, tc)
303272343Sngie{
304272343Sngie	atf_tc_set_md_var(tc, "descr", "Test a bug found by Geza Herman");
305272343Sngie}
306272343Sngie
307272343SngieATF_TC_BODY(strtod_gherman_bug, tc)
308272343Sngie{
309272343Sngie
310272343Sngie	const char *str =
311272343Sngie	    "1.8254370818746402660437411213933955878019332885742187";
312272343Sngie
313272343Sngie	errno = 0;
314272343Sngie	volatile double d = strtod(str, NULL);
315272343Sngie
316272343Sngie	ATF_CHECK(d == 0x1.d34fd8378ea83p+0);
317272343Sngie}
318272343Sngie
319272343SngieATF_TP_ADD_TCS(tp)
320272343Sngie{
321272343Sngie
322272343Sngie	ATF_TP_ADD_TC(tp, strtod_basic);
323272343Sngie	ATF_TP_ADD_TC(tp, strtod_hex);
324272343Sngie	ATF_TP_ADD_TC(tp, strtod_inf);
325272343Sngie	ATF_TP_ADD_TC(tp, strtof_inf);
326272343Sngie	ATF_TP_ADD_TC(tp, strtold_inf);
327272343Sngie	ATF_TP_ADD_TC(tp, strtod_nan);
328272343Sngie	ATF_TP_ADD_TC(tp, strtof_nan);
329272343Sngie	ATF_TP_ADD_TC(tp, strtold_nan);
330272343Sngie	ATF_TP_ADD_TC(tp, strtod_round);
331272343Sngie	ATF_TP_ADD_TC(tp, strtod_underflow);
332272343Sngie	ATF_TP_ADD_TC(tp, strtod_gherman_bug);
333272343Sngie
334272343Sngie	return atf_no_error();
335272343Sngie}
336