1*0a6a1f1dSLionel Sambuc /* $NetBSD: t_strtod.c,v 1.33 2014/12/27 18:03:41 martin Exp $ */
211be35a1SLionel Sambuc
311be35a1SLionel Sambuc /*-
411be35a1SLionel Sambuc * Copyright (c) 2011 The NetBSD Foundation, Inc.
511be35a1SLionel Sambuc * All rights reserved.
611be35a1SLionel Sambuc *
711be35a1SLionel Sambuc * This code is derived from software contributed to The NetBSD Foundation
811be35a1SLionel Sambuc * by Jukka Ruohonen.
911be35a1SLionel Sambuc *
1011be35a1SLionel Sambuc * Redistribution and use in source and binary forms, with or without
1111be35a1SLionel Sambuc * modification, are permitted provided that the following conditions
1211be35a1SLionel Sambuc * are met:
1311be35a1SLionel Sambuc * 1. Redistributions of source code must retain the above copyright
1411be35a1SLionel Sambuc * notice, this list of conditions and the following disclaimer.
1511be35a1SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
1611be35a1SLionel Sambuc * notice, this list of conditions and the following disclaimer in the
1711be35a1SLionel Sambuc * documentation and/or other materials provided with the distribution.
1811be35a1SLionel Sambuc *
1911be35a1SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2011be35a1SLionel Sambuc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2111be35a1SLionel Sambuc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2211be35a1SLionel Sambuc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2311be35a1SLionel Sambuc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2411be35a1SLionel Sambuc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2511be35a1SLionel Sambuc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2611be35a1SLionel Sambuc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2711be35a1SLionel Sambuc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2811be35a1SLionel Sambuc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2911be35a1SLionel Sambuc * POSSIBILITY OF SUCH DAMAGE.
3011be35a1SLionel Sambuc */
3111be35a1SLionel Sambuc
3211be35a1SLionel Sambuc /* Public domain, Otto Moerbeek <otto@drijf.net>, 2006. */
3311be35a1SLionel Sambuc
3411be35a1SLionel Sambuc #include <sys/cdefs.h>
35*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: t_strtod.c,v 1.33 2014/12/27 18:03:41 martin Exp $");
3611be35a1SLionel Sambuc
3711be35a1SLionel Sambuc #include <errno.h>
3811be35a1SLionel Sambuc #include <math.h>
3911be35a1SLionel Sambuc #include <stdio.h>
4011be35a1SLionel Sambuc #include <stdlib.h>
4111be35a1SLionel Sambuc #include <string.h>
4211be35a1SLionel Sambuc
4311be35a1SLionel Sambuc #include <atf-c.h>
4411be35a1SLionel Sambuc
45*0a6a1f1dSLionel Sambuc #ifdef HAVE_FENV
4611be35a1SLionel Sambuc #include <fenv.h>
4711be35a1SLionel Sambuc #endif
4811be35a1SLionel Sambuc
4911be35a1SLionel Sambuc #if !defined(__vax__)
5011be35a1SLionel Sambuc static const char * const inf_strings[] =
5111be35a1SLionel Sambuc { "Inf", "INF", "-Inf", "-INF", "Infinity", "+Infinity",
5211be35a1SLionel Sambuc "INFINITY", "-INFINITY", "InFiNiTy", "+InFiNiTy" };
5311be35a1SLionel Sambuc const char *nan_string = "NaN(x)y";
5411be35a1SLionel Sambuc #endif
5511be35a1SLionel Sambuc
5611be35a1SLionel Sambuc ATF_TC(strtod_basic);
ATF_TC_HEAD(strtod_basic,tc)5711be35a1SLionel Sambuc ATF_TC_HEAD(strtod_basic, tc)
5811be35a1SLionel Sambuc {
5911be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "A basic test of strtod(3)");
6011be35a1SLionel Sambuc }
6111be35a1SLionel Sambuc
ATF_TC_BODY(strtod_basic,tc)6211be35a1SLionel Sambuc ATF_TC_BODY(strtod_basic, tc)
6311be35a1SLionel Sambuc {
6411be35a1SLionel Sambuc static const size_t n = 1024 * 1000;
6511be35a1SLionel Sambuc
6611be35a1SLionel Sambuc for (size_t i = 1; i < n; i = i + 1024) {
6711be35a1SLionel Sambuc char buf[512];
6811be35a1SLionel Sambuc (void)snprintf(buf, sizeof(buf), "%zu.%zu", i, i + 1);
6911be35a1SLionel Sambuc
7011be35a1SLionel Sambuc errno = 0;
7111be35a1SLionel Sambuc double d = strtod(buf, NULL);
7211be35a1SLionel Sambuc
7311be35a1SLionel Sambuc ATF_REQUIRE(d > 0.0);
7411be35a1SLionel Sambuc ATF_REQUIRE(errno == 0);
7511be35a1SLionel Sambuc }
7611be35a1SLionel Sambuc }
7711be35a1SLionel Sambuc
7811be35a1SLionel Sambuc ATF_TC(strtod_hex);
ATF_TC_HEAD(strtod_hex,tc)7911be35a1SLionel Sambuc ATF_TC_HEAD(strtod_hex, tc)
8011be35a1SLionel Sambuc {
8111be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "A strtod(3) with hexadecimals");
8211be35a1SLionel Sambuc }
8311be35a1SLionel Sambuc
8411be35a1SLionel Sambuc #ifdef __vax__
8511be35a1SLionel Sambuc #define SMALL_NUM 1.0e-38
8611be35a1SLionel Sambuc #else
8711be35a1SLionel Sambuc #define SMALL_NUM 1.0e-40
8811be35a1SLionel Sambuc #endif
8911be35a1SLionel Sambuc
ATF_TC_BODY(strtod_hex,tc)9011be35a1SLionel Sambuc ATF_TC_BODY(strtod_hex, tc)
9111be35a1SLionel Sambuc {
9211be35a1SLionel Sambuc const char *str;
9311be35a1SLionel Sambuc char *end;
9411be35a1SLionel Sambuc volatile double d;
9511be35a1SLionel Sambuc
9611be35a1SLionel Sambuc str = "-0x0";
9711be35a1SLionel Sambuc d = strtod(str, &end); /* -0.0 */
9811be35a1SLionel Sambuc
9911be35a1SLionel Sambuc ATF_REQUIRE(end == str + 4);
10011be35a1SLionel Sambuc ATF_REQUIRE(signbit(d) != 0);
10111be35a1SLionel Sambuc ATF_REQUIRE(fabs(d) < SMALL_NUM);
10211be35a1SLionel Sambuc
10311be35a1SLionel Sambuc str = "-0x";
10411be35a1SLionel Sambuc d = strtod(str, &end); /* -0.0 */
10511be35a1SLionel Sambuc
10611be35a1SLionel Sambuc ATF_REQUIRE(end == str + 2);
10711be35a1SLionel Sambuc ATF_REQUIRE(signbit(d) != 0);
10811be35a1SLionel Sambuc ATF_REQUIRE(fabs(d) < SMALL_NUM);
10911be35a1SLionel Sambuc }
11011be35a1SLionel Sambuc
11111be35a1SLionel Sambuc ATF_TC(strtod_inf);
ATF_TC_HEAD(strtod_inf,tc)11211be35a1SLionel Sambuc ATF_TC_HEAD(strtod_inf, tc)
11311be35a1SLionel Sambuc {
11411be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "A strtod(3) with INF (PR lib/33262)");
11511be35a1SLionel Sambuc }
11611be35a1SLionel Sambuc
ATF_TC_BODY(strtod_inf,tc)11711be35a1SLionel Sambuc ATF_TC_BODY(strtod_inf, tc)
11811be35a1SLionel Sambuc {
11911be35a1SLionel Sambuc #ifndef __vax__
12011be35a1SLionel Sambuc for (size_t i = 0; i < __arraycount(inf_strings); i++) {
12111be35a1SLionel Sambuc volatile double d = strtod(inf_strings[i], NULL);
12211be35a1SLionel Sambuc ATF_REQUIRE(isinf(d) != 0);
12311be35a1SLionel Sambuc }
12411be35a1SLionel Sambuc #else
12511be35a1SLionel Sambuc atf_tc_skip("vax not supported");
12611be35a1SLionel Sambuc #endif
12711be35a1SLionel Sambuc }
12811be35a1SLionel Sambuc
12911be35a1SLionel Sambuc ATF_TC(strtof_inf);
ATF_TC_HEAD(strtof_inf,tc)13011be35a1SLionel Sambuc ATF_TC_HEAD(strtof_inf, tc)
13111be35a1SLionel Sambuc {
13211be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "A strtof(3) with INF (PR lib/33262)");
13311be35a1SLionel Sambuc }
13411be35a1SLionel Sambuc
ATF_TC_BODY(strtof_inf,tc)13511be35a1SLionel Sambuc ATF_TC_BODY(strtof_inf, tc)
13611be35a1SLionel Sambuc {
13711be35a1SLionel Sambuc #ifndef __vax__
13811be35a1SLionel Sambuc for (size_t i = 0; i < __arraycount(inf_strings); i++) {
13911be35a1SLionel Sambuc volatile float f = strtof(inf_strings[i], NULL);
14011be35a1SLionel Sambuc ATF_REQUIRE(isinf(f) != 0);
14111be35a1SLionel Sambuc }
14211be35a1SLionel Sambuc #else
14311be35a1SLionel Sambuc atf_tc_skip("vax not supported");
14411be35a1SLionel Sambuc #endif
14511be35a1SLionel Sambuc }
14611be35a1SLionel Sambuc
14711be35a1SLionel Sambuc ATF_TC(strtold_inf);
ATF_TC_HEAD(strtold_inf,tc)14811be35a1SLionel Sambuc ATF_TC_HEAD(strtold_inf, tc)
14911be35a1SLionel Sambuc {
15011be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "A strtold(3) with INF (PR lib/33262)");
15111be35a1SLionel Sambuc }
15211be35a1SLionel Sambuc
ATF_TC_BODY(strtold_inf,tc)15311be35a1SLionel Sambuc ATF_TC_BODY(strtold_inf, tc)
15411be35a1SLionel Sambuc {
15511be35a1SLionel Sambuc #ifndef __vax__
15611be35a1SLionel Sambuc # ifdef __HAVE_LONG_DOUBLE
15711be35a1SLionel Sambuc
15811be35a1SLionel Sambuc for (size_t i = 0; i < __arraycount(inf_strings); i++) {
15911be35a1SLionel Sambuc volatile long double ld = strtold(inf_strings[i], NULL);
16011be35a1SLionel Sambuc ATF_REQUIRE(isinf(ld) != 0);
16111be35a1SLionel Sambuc }
16211be35a1SLionel Sambuc # else
16311be35a1SLionel Sambuc atf_tc_skip("Requires long double support");
16411be35a1SLionel Sambuc # endif
16511be35a1SLionel Sambuc #else
16611be35a1SLionel Sambuc atf_tc_skip("vax not supported");
16711be35a1SLionel Sambuc #endif
16811be35a1SLionel Sambuc }
16911be35a1SLionel Sambuc
17011be35a1SLionel Sambuc ATF_TC(strtod_nan);
ATF_TC_HEAD(strtod_nan,tc)17111be35a1SLionel Sambuc ATF_TC_HEAD(strtod_nan, tc)
17211be35a1SLionel Sambuc {
17311be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "A strtod(3) with NaN");
17411be35a1SLionel Sambuc }
17511be35a1SLionel Sambuc
ATF_TC_BODY(strtod_nan,tc)17611be35a1SLionel Sambuc ATF_TC_BODY(strtod_nan, tc)
17711be35a1SLionel Sambuc {
17811be35a1SLionel Sambuc #ifndef __vax__
17911be35a1SLionel Sambuc char *end;
18011be35a1SLionel Sambuc
18111be35a1SLionel Sambuc volatile double d = strtod(nan_string, &end);
18211be35a1SLionel Sambuc ATF_REQUIRE(isnan(d) != 0);
18311be35a1SLionel Sambuc ATF_REQUIRE(strcmp(end, "y") == 0);
18411be35a1SLionel Sambuc #else
18511be35a1SLionel Sambuc atf_tc_skip("vax not supported");
18611be35a1SLionel Sambuc #endif
18711be35a1SLionel Sambuc }
18811be35a1SLionel Sambuc
18911be35a1SLionel Sambuc ATF_TC(strtof_nan);
ATF_TC_HEAD(strtof_nan,tc)19011be35a1SLionel Sambuc ATF_TC_HEAD(strtof_nan, tc)
19111be35a1SLionel Sambuc {
19211be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "A strtof(3) with NaN");
19311be35a1SLionel Sambuc }
19411be35a1SLionel Sambuc
ATF_TC_BODY(strtof_nan,tc)19511be35a1SLionel Sambuc ATF_TC_BODY(strtof_nan, tc)
19611be35a1SLionel Sambuc {
19711be35a1SLionel Sambuc #ifndef __vax__
19811be35a1SLionel Sambuc char *end;
19911be35a1SLionel Sambuc
20011be35a1SLionel Sambuc volatile float f = strtof(nan_string, &end);
20111be35a1SLionel Sambuc ATF_REQUIRE(isnanf(f) != 0);
20211be35a1SLionel Sambuc ATF_REQUIRE(strcmp(end, "y") == 0);
20311be35a1SLionel Sambuc #else
20411be35a1SLionel Sambuc atf_tc_skip("vax not supported");
20511be35a1SLionel Sambuc #endif
20611be35a1SLionel Sambuc }
20711be35a1SLionel Sambuc
20811be35a1SLionel Sambuc ATF_TC(strtold_nan);
ATF_TC_HEAD(strtold_nan,tc)20911be35a1SLionel Sambuc ATF_TC_HEAD(strtold_nan, tc)
21011be35a1SLionel Sambuc {
21111be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "A strtold(3) with NaN (PR lib/45020)");
21211be35a1SLionel Sambuc }
21311be35a1SLionel Sambuc
ATF_TC_BODY(strtold_nan,tc)21411be35a1SLionel Sambuc ATF_TC_BODY(strtold_nan, tc)
21511be35a1SLionel Sambuc {
21611be35a1SLionel Sambuc #ifndef __vax__
21711be35a1SLionel Sambuc # ifdef __HAVE_LONG_DOUBLE
21811be35a1SLionel Sambuc
21911be35a1SLionel Sambuc char *end;
22011be35a1SLionel Sambuc
22111be35a1SLionel Sambuc volatile long double ld = strtold(nan_string, &end);
22211be35a1SLionel Sambuc ATF_REQUIRE(isnan(ld) != 0);
22311be35a1SLionel Sambuc ATF_REQUIRE(__isnanl(ld) != 0);
22411be35a1SLionel Sambuc ATF_REQUIRE(strcmp(end, "y") == 0);
22511be35a1SLionel Sambuc # else
22611be35a1SLionel Sambuc atf_tc_skip("Requires long double support");
22711be35a1SLionel Sambuc # endif
22811be35a1SLionel Sambuc #else
22911be35a1SLionel Sambuc atf_tc_skip("vax not supported");
23011be35a1SLionel Sambuc #endif
23111be35a1SLionel Sambuc }
23211be35a1SLionel Sambuc
23311be35a1SLionel Sambuc ATF_TC(strtod_round);
ATF_TC_HEAD(strtod_round,tc)23411be35a1SLionel Sambuc ATF_TC_HEAD(strtod_round, tc)
23511be35a1SLionel Sambuc {
23611be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "Test rouding in strtod(3)");
23711be35a1SLionel Sambuc }
23811be35a1SLionel Sambuc
ATF_TC_BODY(strtod_round,tc)23911be35a1SLionel Sambuc ATF_TC_BODY(strtod_round, tc)
24011be35a1SLionel Sambuc {
241*0a6a1f1dSLionel Sambuc #ifdef HAVE_FENV
24211be35a1SLionel Sambuc
24311be35a1SLionel Sambuc /*
24411be35a1SLionel Sambuc * Test that strtod(3) honors the current rounding mode.
24511be35a1SLionel Sambuc * The used value is somewhere near 1 + DBL_EPSILON + FLT_EPSILON.
24611be35a1SLionel Sambuc */
24711be35a1SLionel Sambuc const char *val =
24811be35a1SLionel Sambuc "1.00000011920928977282585492503130808472633361816406";
24911be35a1SLionel Sambuc
25011be35a1SLionel Sambuc (void)fesetround(FE_UPWARD);
25111be35a1SLionel Sambuc
25211be35a1SLionel Sambuc volatile double d1 = strtod(val, NULL);
25311be35a1SLionel Sambuc
25411be35a1SLionel Sambuc (void)fesetround(FE_DOWNWARD);
25511be35a1SLionel Sambuc
25611be35a1SLionel Sambuc volatile double d2 = strtod(val, NULL);
25711be35a1SLionel Sambuc
25811be35a1SLionel Sambuc if (fabs(d1 - d2) > 0.0)
25911be35a1SLionel Sambuc return;
26011be35a1SLionel Sambuc else {
26111be35a1SLionel Sambuc atf_tc_expect_fail("PR misc/44767");
26211be35a1SLionel Sambuc atf_tc_fail("strtod(3) did not honor fesetround(3)");
26311be35a1SLionel Sambuc }
26411be35a1SLionel Sambuc #else
265*0a6a1f1dSLionel Sambuc atf_tc_skip("Requires <fenv.h> support");
26611be35a1SLionel Sambuc #endif
26711be35a1SLionel Sambuc }
26811be35a1SLionel Sambuc
26911be35a1SLionel Sambuc ATF_TC(strtod_underflow);
ATF_TC_HEAD(strtod_underflow,tc)27011be35a1SLionel Sambuc ATF_TC_HEAD(strtod_underflow, tc)
27111be35a1SLionel Sambuc {
27211be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "Test underflow in strtod(3)");
27311be35a1SLionel Sambuc }
27411be35a1SLionel Sambuc
ATF_TC_BODY(strtod_underflow,tc)27511be35a1SLionel Sambuc ATF_TC_BODY(strtod_underflow, tc)
27611be35a1SLionel Sambuc {
27711be35a1SLionel Sambuc
27811be35a1SLionel Sambuc const char *tmp =
27911be35a1SLionel Sambuc "0.0000000000000000000000000000000000000000000000000000"
28011be35a1SLionel Sambuc "000000000000000000000000000000000000000000000000000000"
28111be35a1SLionel Sambuc "000000000000000000000000000000000000000000000000000000"
28211be35a1SLionel Sambuc "000000000000000000000000000000000000000000000000000000"
28311be35a1SLionel Sambuc "000000000000000000000000000000000000000000000000000000"
28411be35a1SLionel Sambuc "000000000000000000000000000000000000000000000000000000"
28511be35a1SLionel Sambuc "000000000000000000000000000000000000000000000000000000"
28611be35a1SLionel Sambuc "000000000000000002";
28711be35a1SLionel Sambuc
28811be35a1SLionel Sambuc errno = 0;
28911be35a1SLionel Sambuc volatile double d = strtod(tmp, NULL);
29011be35a1SLionel Sambuc
29111be35a1SLionel Sambuc if (d != 0 || errno != ERANGE)
29211be35a1SLionel Sambuc atf_tc_fail("strtod(3) did not detect underflow");
29311be35a1SLionel Sambuc }
29411be35a1SLionel Sambuc
29511be35a1SLionel Sambuc /*
29611be35a1SLionel Sambuc * Bug found by Geza Herman.
29711be35a1SLionel Sambuc * See
29811be35a1SLionel Sambuc * http://www.exploringbinary.com/a-bug-in-the-bigcomp-function-of-david-gays-strtod/
29911be35a1SLionel Sambuc */
30011be35a1SLionel Sambuc ATF_TC(strtod_gherman_bug);
ATF_TC_HEAD(strtod_gherman_bug,tc)30111be35a1SLionel Sambuc ATF_TC_HEAD(strtod_gherman_bug, tc)
30211be35a1SLionel Sambuc {
30311be35a1SLionel Sambuc atf_tc_set_md_var(tc, "descr", "Test a bug found by Geza Herman");
30411be35a1SLionel Sambuc }
30511be35a1SLionel Sambuc
ATF_TC_BODY(strtod_gherman_bug,tc)30611be35a1SLionel Sambuc ATF_TC_BODY(strtod_gherman_bug, tc)
30711be35a1SLionel Sambuc {
30811be35a1SLionel Sambuc
30911be35a1SLionel Sambuc const char *str =
31011be35a1SLionel Sambuc "1.8254370818746402660437411213933955878019332885742187";
31111be35a1SLionel Sambuc
31211be35a1SLionel Sambuc errno = 0;
31311be35a1SLionel Sambuc volatile double d = strtod(str, NULL);
31411be35a1SLionel Sambuc
31511be35a1SLionel Sambuc ATF_CHECK(d == 0x1.d34fd8378ea83p+0);
31611be35a1SLionel Sambuc }
31711be35a1SLionel Sambuc
ATF_TP_ADD_TCS(tp)31811be35a1SLionel Sambuc ATF_TP_ADD_TCS(tp)
31911be35a1SLionel Sambuc {
32011be35a1SLionel Sambuc
32111be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, strtod_basic);
32211be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, strtod_hex);
32311be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, strtod_inf);
32411be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, strtof_inf);
32511be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, strtold_inf);
32611be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, strtod_nan);
32711be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, strtof_nan);
32811be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, strtold_nan);
32911be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, strtod_round);
33011be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, strtod_underflow);
33111be35a1SLionel Sambuc ATF_TP_ADD_TC(tp, strtod_gherman_bug);
33211be35a1SLionel Sambuc
33311be35a1SLionel Sambuc return atf_no_error();
33411be35a1SLionel Sambuc }
335