11ec3feb6SAlex Richardson /* $NetBSD: t_scalbn.c,v 1.16 2018/11/07 03:59:36 riastradh Exp $ */
257718be8SEnji Cooper 
357718be8SEnji Cooper /*-
457718be8SEnji Cooper  * Copyright (c) 2011 The NetBSD Foundation, Inc.
557718be8SEnji Cooper  * All rights reserved.
657718be8SEnji Cooper  *
757718be8SEnji Cooper  * This code is derived from software contributed to The NetBSD Foundation
857718be8SEnji Cooper  * by Jukka Ruohonen.
957718be8SEnji Cooper  *
1057718be8SEnji Cooper  * Redistribution and use in source and binary forms, with or without
1157718be8SEnji Cooper  * modification, are permitted provided that the following conditions
1257718be8SEnji Cooper  * are met:
1357718be8SEnji Cooper  * 1. Redistributions of source code must retain the above copyright
1457718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer.
1557718be8SEnji Cooper  * 2. Redistributions in binary form must reproduce the above copyright
1657718be8SEnji Cooper  *    notice, this list of conditions and the following disclaimer in the
1757718be8SEnji Cooper  *    documentation and/or other materials provided with the distribution.
1857718be8SEnji Cooper  *
1957718be8SEnji Cooper  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2057718be8SEnji Cooper  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2157718be8SEnji Cooper  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2257718be8SEnji Cooper  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2357718be8SEnji Cooper  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2457718be8SEnji Cooper  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2557718be8SEnji Cooper  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2657718be8SEnji Cooper  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2757718be8SEnji Cooper  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2857718be8SEnji Cooper  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2957718be8SEnji Cooper  * POSSIBILITY OF SUCH DAMAGE.
3057718be8SEnji Cooper  */
3157718be8SEnji Cooper #include <sys/cdefs.h>
321ec3feb6SAlex Richardson __RCSID("$NetBSD: t_scalbn.c,v 1.16 2018/11/07 03:59:36 riastradh Exp $");
3357718be8SEnji Cooper 
3457718be8SEnji Cooper #include <math.h>
3557718be8SEnji Cooper #include <limits.h>
3657718be8SEnji Cooper #include <float.h>
3757718be8SEnji Cooper #include <errno.h>
381ec3feb6SAlex Richardson #include <fenv.h>
3957718be8SEnji Cooper 
4057718be8SEnji Cooper #include <atf-c.h>
4157718be8SEnji Cooper 
4257718be8SEnji Cooper static const int exps[] = { 0, 1, -1, 100, -100 };
4357718be8SEnji Cooper 
4457718be8SEnji Cooper /* tests here do not require specific precision, so we just use double */
4557718be8SEnji Cooper struct testcase {
4657718be8SEnji Cooper 	int exp;
4757718be8SEnji Cooper 	double inval;
4857718be8SEnji Cooper 	double result;
4957718be8SEnji Cooper 	int error;
501ec3feb6SAlex Richardson 	int except;
5157718be8SEnji Cooper };
5287d65c74SAlex Richardson static struct testcase test_vals[] = {
531ec3feb6SAlex Richardson 	{ 0,		1.00085,	1.00085,	0, 0 },
541ec3feb6SAlex Richardson 	{ 0,		0.99755,	0.99755,	0, 0 },
551ec3feb6SAlex Richardson 	{ 0,		-1.00085,	-1.00085,	0, 0 },
561ec3feb6SAlex Richardson 	{ 0,		-0.99755,	-0.99755,	0, 0 },
571ec3feb6SAlex Richardson 	{ 1,		1.00085,	2.0* 1.00085,	0, 0 },
581ec3feb6SAlex Richardson 	{ 1,		0.99755,	2.0* 0.99755,	0, 0 },
591ec3feb6SAlex Richardson 	{ 1,		-1.00085,	2.0* -1.00085,	0, 0 },
601ec3feb6SAlex Richardson 	{ 1,		-0.99755,	2.0* -0.99755,	0, 0 },
6157718be8SEnji Cooper 
6257718be8SEnji Cooper 	/*
6357718be8SEnji Cooper 	 * We could add more corner test cases here, but we would have to
6457718be8SEnji Cooper 	 * add some ifdefs for the exact format and use a reliable
6557718be8SEnji Cooper 	 * generator program - bail for now and only do trivial stuff above.
6657718be8SEnji Cooper 	 */
6757718be8SEnji Cooper };
6857718be8SEnji Cooper 
6957718be8SEnji Cooper /*
7057718be8SEnji Cooper  * scalbn(3)
7157718be8SEnji Cooper  */
7257718be8SEnji Cooper ATF_TC(scalbn_val);
ATF_TC_HEAD(scalbn_val,tc)7357718be8SEnji Cooper ATF_TC_HEAD(scalbn_val, tc)
7457718be8SEnji Cooper {
7557718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbn() for a few values");
7657718be8SEnji Cooper }
7757718be8SEnji Cooper 
ATF_TC_BODY(scalbn_val,tc)7857718be8SEnji Cooper ATF_TC_BODY(scalbn_val, tc)
7957718be8SEnji Cooper {
8057718be8SEnji Cooper 	const struct testcase *tests = test_vals;
8157718be8SEnji Cooper 	const size_t tcnt = __arraycount(test_vals);
8257718be8SEnji Cooper 	size_t i;
8357718be8SEnji Cooper 	double rv;
8457718be8SEnji Cooper 
8557718be8SEnji Cooper 	for (i = 0; i < tcnt; i++) {
8679097302SEnji Cooper 		errno = 0;
871ec3feb6SAlex Richardson #ifndef __vax__
881ec3feb6SAlex Richardson 		feclearexcept(FE_ALL_EXCEPT);
891ec3feb6SAlex Richardson #endif
9057718be8SEnji Cooper 		rv = scalbn(tests[i].inval, tests[i].exp);
9157718be8SEnji Cooper 		ATF_CHECK_EQ_MSG(errno, tests[i].error,
9257718be8SEnji Cooper 		    "test %zu: errno %d instead of %d", i, errno,
9357718be8SEnji Cooper 		    tests[i].error);
941ec3feb6SAlex Richardson #ifndef __vax__
951ec3feb6SAlex Richardson 		ATF_CHECK_EQ_MSG(errno, tests[i].error,
961ec3feb6SAlex Richardson 		    "test %zu: fetestexcept %d instead of %d", i,
971ec3feb6SAlex Richardson 		    fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW),
981ec3feb6SAlex Richardson 		    tests[i].except);
991ec3feb6SAlex Richardson #endif
1001ec3feb6SAlex Richardson 		/* scalbn is always exact except for underflow or overflow.  */
1011ec3feb6SAlex Richardson 		ATF_CHECK_MSG(rv == tests[i].result,
1021ec3feb6SAlex Richardson 		    "test %zu: return value %.17g instead of %.17g"
1031ec3feb6SAlex Richardson 		    " (error %.17g)",
1041ec3feb6SAlex Richardson 		    i, rv, tests[i].result,
1051ec3feb6SAlex Richardson 		    fabs((tests[i].result - rv)/tests[i].result));
10657718be8SEnji Cooper 	}
10757718be8SEnji Cooper }
10857718be8SEnji Cooper 
10957718be8SEnji Cooper ATF_TC(scalbn_nan);
ATF_TC_HEAD(scalbn_nan,tc)11057718be8SEnji Cooper ATF_TC_HEAD(scalbn_nan, tc)
11157718be8SEnji Cooper {
11257718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbn(NaN, n) == NaN");
11357718be8SEnji Cooper }
11457718be8SEnji Cooper 
ATF_TC_BODY(scalbn_nan,tc)11557718be8SEnji Cooper ATF_TC_BODY(scalbn_nan, tc)
11657718be8SEnji Cooper {
11757718be8SEnji Cooper 	const double x = 0.0L / 0.0L;
11857718be8SEnji Cooper 	double y;
11957718be8SEnji Cooper 	size_t i;
12057718be8SEnji Cooper 
12157718be8SEnji Cooper 	ATF_REQUIRE(isnan(x) != 0);
12257718be8SEnji Cooper 
12357718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++) {
12457718be8SEnji Cooper 		y = scalbn(x, exps[i]);
12557718be8SEnji Cooper 		ATF_CHECK(isnan(y) != 0);
12657718be8SEnji Cooper 	}
12757718be8SEnji Cooper }
12857718be8SEnji Cooper 
12957718be8SEnji Cooper ATF_TC(scalbn_inf_neg);
ATF_TC_HEAD(scalbn_inf_neg,tc)13057718be8SEnji Cooper ATF_TC_HEAD(scalbn_inf_neg, tc)
13157718be8SEnji Cooper {
13257718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbn(-Inf, n) == -Inf");
13357718be8SEnji Cooper }
13457718be8SEnji Cooper 
ATF_TC_BODY(scalbn_inf_neg,tc)13557718be8SEnji Cooper ATF_TC_BODY(scalbn_inf_neg, tc)
13657718be8SEnji Cooper {
13757718be8SEnji Cooper 	const double x = -1.0L / 0.0L;
13857718be8SEnji Cooper 	size_t i;
13957718be8SEnji Cooper 
14057718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++)
14157718be8SEnji Cooper 		ATF_CHECK(scalbn(x, exps[i]) == x);
14257718be8SEnji Cooper }
14357718be8SEnji Cooper 
14457718be8SEnji Cooper ATF_TC(scalbn_inf_pos);
ATF_TC_HEAD(scalbn_inf_pos,tc)14557718be8SEnji Cooper ATF_TC_HEAD(scalbn_inf_pos, tc)
14657718be8SEnji Cooper {
14757718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbn(+Inf, n) == +Inf");
14857718be8SEnji Cooper }
14957718be8SEnji Cooper 
ATF_TC_BODY(scalbn_inf_pos,tc)15057718be8SEnji Cooper ATF_TC_BODY(scalbn_inf_pos, tc)
15157718be8SEnji Cooper {
15257718be8SEnji Cooper 	const double x = 1.0L / 0.0L;
15357718be8SEnji Cooper 	size_t i;
15457718be8SEnji Cooper 
15557718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++)
15657718be8SEnji Cooper 		ATF_CHECK(scalbn(x, exps[i]) == x);
15757718be8SEnji Cooper }
15857718be8SEnji Cooper 
15957718be8SEnji Cooper ATF_TC(scalbn_ldexp);
ATF_TC_HEAD(scalbn_ldexp,tc)16057718be8SEnji Cooper ATF_TC_HEAD(scalbn_ldexp, tc)
16157718be8SEnji Cooper {
16257718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbn(x, n) == ldexp(x, n)");
16357718be8SEnji Cooper }
16457718be8SEnji Cooper 
ATF_TC_BODY(scalbn_ldexp,tc)16557718be8SEnji Cooper ATF_TC_BODY(scalbn_ldexp, tc)
16657718be8SEnji Cooper {
16757718be8SEnji Cooper #if FLT_RADIX == 2
16857718be8SEnji Cooper 	const double x = 2.91288191221812821;
16957718be8SEnji Cooper 	double y;
17057718be8SEnji Cooper 	size_t i;
17157718be8SEnji Cooper 
17257718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++) {
17357718be8SEnji Cooper 		y = scalbn(x, exps[i]);
17457718be8SEnji Cooper 		ATF_CHECK_MSG(y == ldexp(x, exps[i]), "test %zu: exponent=%d, "
17557718be8SEnji Cooper 		    "y=%g, expected %g (diff: %g)", i, exps[i], y,
17657718be8SEnji Cooper 		    ldexp(x, exps[i]), y - ldexp(x, exps[i]));
17757718be8SEnji Cooper 	}
17857718be8SEnji Cooper #endif
17957718be8SEnji Cooper }
18057718be8SEnji Cooper 
18157718be8SEnji Cooper ATF_TC(scalbn_zero_neg);
ATF_TC_HEAD(scalbn_zero_neg,tc)18257718be8SEnji Cooper ATF_TC_HEAD(scalbn_zero_neg, tc)
18357718be8SEnji Cooper {
18457718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbn(-0.0, n) == -0.0");
18557718be8SEnji Cooper }
18657718be8SEnji Cooper 
ATF_TC_BODY(scalbn_zero_neg,tc)18757718be8SEnji Cooper ATF_TC_BODY(scalbn_zero_neg, tc)
18857718be8SEnji Cooper {
18957718be8SEnji Cooper 	const double x = -0.0L;
19057718be8SEnji Cooper 	double y;
19157718be8SEnji Cooper 	size_t i;
19257718be8SEnji Cooper 
19357718be8SEnji Cooper 	ATF_REQUIRE(signbit(x) != 0);
19457718be8SEnji Cooper 
19557718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++) {
19657718be8SEnji Cooper 		y = scalbn(x, exps[i]);
19757718be8SEnji Cooper 		ATF_CHECK(x == y);
19857718be8SEnji Cooper 		ATF_CHECK(signbit(y) != 0);
19957718be8SEnji Cooper 	}
20057718be8SEnji Cooper }
20157718be8SEnji Cooper 
20257718be8SEnji Cooper ATF_TC(scalbn_zero_pos);
ATF_TC_HEAD(scalbn_zero_pos,tc)20357718be8SEnji Cooper ATF_TC_HEAD(scalbn_zero_pos, tc)
20457718be8SEnji Cooper {
20557718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbn(+0.0, n) == +0.0");
20657718be8SEnji Cooper }
20757718be8SEnji Cooper 
ATF_TC_BODY(scalbn_zero_pos,tc)20857718be8SEnji Cooper ATF_TC_BODY(scalbn_zero_pos, tc)
20957718be8SEnji Cooper {
21057718be8SEnji Cooper 	const double x = 0.0L;
21157718be8SEnji Cooper 	double y;
21257718be8SEnji Cooper 	size_t i;
21357718be8SEnji Cooper 
21457718be8SEnji Cooper 	ATF_REQUIRE(signbit(x) == 0);
21557718be8SEnji Cooper 
21657718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++) {
21757718be8SEnji Cooper 		y = scalbn(x, exps[i]);
21857718be8SEnji Cooper 		ATF_CHECK(x == y);
21957718be8SEnji Cooper 		ATF_CHECK(signbit(y) == 0);
22057718be8SEnji Cooper 	}
22157718be8SEnji Cooper }
22257718be8SEnji Cooper 
22357718be8SEnji Cooper /*
22457718be8SEnji Cooper  * scalbnf(3)
22557718be8SEnji Cooper  */
22657718be8SEnji Cooper ATF_TC(scalbnf_val);
ATF_TC_HEAD(scalbnf_val,tc)22757718be8SEnji Cooper ATF_TC_HEAD(scalbnf_val, tc)
22857718be8SEnji Cooper {
22957718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbnf() for a few values");
23057718be8SEnji Cooper }
23157718be8SEnji Cooper 
ATF_TC_BODY(scalbnf_val,tc)23257718be8SEnji Cooper ATF_TC_BODY(scalbnf_val, tc)
23357718be8SEnji Cooper {
23457718be8SEnji Cooper 	const struct testcase *tests = test_vals;
23557718be8SEnji Cooper 	const size_t tcnt = __arraycount(test_vals);
23657718be8SEnji Cooper 	size_t i;
23757718be8SEnji Cooper 	double rv;
23857718be8SEnji Cooper 
23957718be8SEnji Cooper 	for (i = 0; i < tcnt; i++) {
2408fe9679fSEnji Cooper 		errno = 0;
24157718be8SEnji Cooper 		rv = scalbnf(tests[i].inval, tests[i].exp);
24257718be8SEnji Cooper 		ATF_CHECK_EQ_MSG(errno, tests[i].error,
24357718be8SEnji Cooper 		    "test %zu: errno %d instead of %d", i, errno,
24457718be8SEnji Cooper 		    tests[i].error);
2451ec3feb6SAlex Richardson 		/* scalbn is always exact except for underflow or overflow.  */
2461ec3feb6SAlex Richardson 		ATF_CHECK_MSG(rv == (float)tests[i].result,
2471ec3feb6SAlex Richardson 		    "test %zu: return value %.8g instead of %.8g"
2481ec3feb6SAlex Richardson 		    " (error %.8g)",
2491ec3feb6SAlex Richardson 		    i, rv, tests[i].result,
2501ec3feb6SAlex Richardson 		    fabs((tests[i].result - rv)/tests[i].result));
25157718be8SEnji Cooper 	}
25257718be8SEnji Cooper }
25357718be8SEnji Cooper 
25457718be8SEnji Cooper ATF_TC(scalbnf_nan);
ATF_TC_HEAD(scalbnf_nan,tc)25557718be8SEnji Cooper ATF_TC_HEAD(scalbnf_nan, tc)
25657718be8SEnji Cooper {
25757718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbnf(NaN, n) == NaN");
25857718be8SEnji Cooper }
25957718be8SEnji Cooper 
ATF_TC_BODY(scalbnf_nan,tc)26057718be8SEnji Cooper ATF_TC_BODY(scalbnf_nan, tc)
26157718be8SEnji Cooper {
26257718be8SEnji Cooper 	const float x = 0.0L / 0.0L;
26357718be8SEnji Cooper 	float y;
26457718be8SEnji Cooper 	size_t i;
26557718be8SEnji Cooper 
26657718be8SEnji Cooper 	ATF_REQUIRE(isnan(x) != 0);
26757718be8SEnji Cooper 
26857718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++) {
26957718be8SEnji Cooper 		y = scalbnf(x, exps[i]);
27057718be8SEnji Cooper 		ATF_CHECK(isnan(y) != 0);
27157718be8SEnji Cooper 	}
27257718be8SEnji Cooper }
27357718be8SEnji Cooper 
27457718be8SEnji Cooper ATF_TC(scalbnf_inf_neg);
ATF_TC_HEAD(scalbnf_inf_neg,tc)27557718be8SEnji Cooper ATF_TC_HEAD(scalbnf_inf_neg, tc)
27657718be8SEnji Cooper {
27757718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbnf(-Inf, n) == -Inf");
27857718be8SEnji Cooper }
27957718be8SEnji Cooper 
ATF_TC_BODY(scalbnf_inf_neg,tc)28057718be8SEnji Cooper ATF_TC_BODY(scalbnf_inf_neg, tc)
28157718be8SEnji Cooper {
28257718be8SEnji Cooper 	const float x = -1.0L / 0.0L;
28357718be8SEnji Cooper 	size_t i;
28457718be8SEnji Cooper 
28557718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++)
28657718be8SEnji Cooper 		ATF_CHECK(scalbnf(x, exps[i]) == x);
28757718be8SEnji Cooper }
28857718be8SEnji Cooper 
28957718be8SEnji Cooper ATF_TC(scalbnf_inf_pos);
ATF_TC_HEAD(scalbnf_inf_pos,tc)29057718be8SEnji Cooper ATF_TC_HEAD(scalbnf_inf_pos, tc)
29157718be8SEnji Cooper {
29257718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbnf(+Inf, n) == +Inf");
29357718be8SEnji Cooper }
29457718be8SEnji Cooper 
ATF_TC_BODY(scalbnf_inf_pos,tc)29557718be8SEnji Cooper ATF_TC_BODY(scalbnf_inf_pos, tc)
29657718be8SEnji Cooper {
29757718be8SEnji Cooper 	const float x = 1.0L / 0.0L;
29857718be8SEnji Cooper 	size_t i;
29957718be8SEnji Cooper 
30057718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++)
30157718be8SEnji Cooper 		ATF_CHECK(scalbnf(x, exps[i]) == x);
30257718be8SEnji Cooper }
30357718be8SEnji Cooper 
30457718be8SEnji Cooper ATF_TC(scalbnf_ldexpf);
ATF_TC_HEAD(scalbnf_ldexpf,tc)30557718be8SEnji Cooper ATF_TC_HEAD(scalbnf_ldexpf, tc)
30657718be8SEnji Cooper {
30757718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbnf(x, n) == ldexpf(x, n)");
30857718be8SEnji Cooper }
30957718be8SEnji Cooper 
ATF_TC_BODY(scalbnf_ldexpf,tc)31057718be8SEnji Cooper ATF_TC_BODY(scalbnf_ldexpf, tc)
31157718be8SEnji Cooper {
31257718be8SEnji Cooper #if FLT_RADIX == 2
31357718be8SEnji Cooper 	const float x = 2.91288191221812821;
31457718be8SEnji Cooper 	float y;
31557718be8SEnji Cooper 	size_t i;
31657718be8SEnji Cooper 
31757718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++) {
31857718be8SEnji Cooper 		y = scalbnf(x, exps[i]);
31957718be8SEnji Cooper 		ATF_CHECK_MSG(y == ldexpf(x, exps[i]),
32057718be8SEnji Cooper 		    "test %zu: exponent=%d, y=%g ldexpf returns %g (diff: %g)",
32157718be8SEnji Cooper 		    i, exps[i], y, ldexpf(x, exps[i]), y-ldexpf(x, exps[i]));
32257718be8SEnji Cooper 	}
32357718be8SEnji Cooper #endif
32457718be8SEnji Cooper }
32557718be8SEnji Cooper 
32657718be8SEnji Cooper ATF_TC(scalbnf_zero_neg);
ATF_TC_HEAD(scalbnf_zero_neg,tc)32757718be8SEnji Cooper ATF_TC_HEAD(scalbnf_zero_neg, tc)
32857718be8SEnji Cooper {
32957718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbnf(-0.0, n) == -0.0");
33057718be8SEnji Cooper }
33157718be8SEnji Cooper 
ATF_TC_BODY(scalbnf_zero_neg,tc)33257718be8SEnji Cooper ATF_TC_BODY(scalbnf_zero_neg, tc)
33357718be8SEnji Cooper {
33457718be8SEnji Cooper 	const float x = -0.0L;
33557718be8SEnji Cooper 	float y;
33657718be8SEnji Cooper 	size_t i;
33757718be8SEnji Cooper 
33857718be8SEnji Cooper 	ATF_REQUIRE(signbit(x) != 0);
33957718be8SEnji Cooper 
34057718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++) {
34157718be8SEnji Cooper 		y = scalbnf(x, exps[i]);
34257718be8SEnji Cooper 		ATF_CHECK(x == y);
34357718be8SEnji Cooper 		ATF_CHECK(signbit(y) != 0);
34457718be8SEnji Cooper 	}
34557718be8SEnji Cooper }
34657718be8SEnji Cooper 
34757718be8SEnji Cooper ATF_TC(scalbnf_zero_pos);
ATF_TC_HEAD(scalbnf_zero_pos,tc)34857718be8SEnji Cooper ATF_TC_HEAD(scalbnf_zero_pos, tc)
34957718be8SEnji Cooper {
35057718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbnf(+0.0, n) == +0.0");
35157718be8SEnji Cooper }
35257718be8SEnji Cooper 
ATF_TC_BODY(scalbnf_zero_pos,tc)35357718be8SEnji Cooper ATF_TC_BODY(scalbnf_zero_pos, tc)
35457718be8SEnji Cooper {
35557718be8SEnji Cooper 	const float x = 0.0L;
35657718be8SEnji Cooper 	float y;
35757718be8SEnji Cooper 	size_t i;
35857718be8SEnji Cooper 
35957718be8SEnji Cooper 	ATF_REQUIRE(signbit(x) == 0);
36057718be8SEnji Cooper 
36157718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++) {
36257718be8SEnji Cooper 		y = scalbnf(x, exps[i]);
36357718be8SEnji Cooper 		ATF_CHECK(x == y);
36457718be8SEnji Cooper 		ATF_CHECK(signbit(y) == 0);
36557718be8SEnji Cooper 	}
36657718be8SEnji Cooper }
36757718be8SEnji Cooper 
36857718be8SEnji Cooper /*
36957718be8SEnji Cooper  * scalbnl(3)
37057718be8SEnji Cooper  */
37157718be8SEnji Cooper ATF_TC(scalbnl_val);
ATF_TC_HEAD(scalbnl_val,tc)37257718be8SEnji Cooper ATF_TC_HEAD(scalbnl_val, tc)
37357718be8SEnji Cooper {
37457718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbnl() for a few values");
37557718be8SEnji Cooper }
37657718be8SEnji Cooper 
ATF_TC_BODY(scalbnl_val,tc)37757718be8SEnji Cooper ATF_TC_BODY(scalbnl_val, tc)
37857718be8SEnji Cooper {
37957718be8SEnji Cooper #ifndef __HAVE_LONG_DOUBLE
38057718be8SEnji Cooper 	atf_tc_skip("Requires long double support");
38157718be8SEnji Cooper #else
38257718be8SEnji Cooper 	const struct testcase *tests = test_vals;
38357718be8SEnji Cooper 	const size_t tcnt = __arraycount(test_vals);
38457718be8SEnji Cooper 	size_t i;
38557718be8SEnji Cooper 	long double rv;
38657718be8SEnji Cooper 
38757718be8SEnji Cooper 	for (i = 0; i < tcnt; i++) {
3888fe9679fSEnji Cooper 		errno = 0;
38957718be8SEnji Cooper 		rv = scalbnl(tests[i].inval, tests[i].exp);
39057718be8SEnji Cooper 		ATF_CHECK_EQ_MSG(errno, tests[i].error,
39157718be8SEnji Cooper 		    "test %zu: errno %d instead of %d", i, errno,
39257718be8SEnji Cooper 		    tests[i].error);
3931ec3feb6SAlex Richardson 		/* scalbn is always exact except for underflow or overflow.  */
3941ec3feb6SAlex Richardson 		ATF_CHECK_MSG(rv == (long double)tests[i].result,
3951ec3feb6SAlex Richardson 		    "test %zu: return value %.35Lg instead of %.35Lg"
3961ec3feb6SAlex Richardson 		    " (error %.35Lg)",
3971ec3feb6SAlex Richardson 		    i, rv, (long double)tests[i].result,
3981ec3feb6SAlex Richardson 		    fabsl(((long double)tests[i].result - rv)/tests[i].result));
39957718be8SEnji Cooper 	}
40057718be8SEnji Cooper #endif
40157718be8SEnji Cooper }
40257718be8SEnji Cooper 
40357718be8SEnji Cooper ATF_TC(scalbnl_nan);
ATF_TC_HEAD(scalbnl_nan,tc)40457718be8SEnji Cooper ATF_TC_HEAD(scalbnl_nan, tc)
40557718be8SEnji Cooper {
40657718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbnl(NaN, n) == NaN");
40757718be8SEnji Cooper }
40857718be8SEnji Cooper 
ATF_TC_BODY(scalbnl_nan,tc)40957718be8SEnji Cooper ATF_TC_BODY(scalbnl_nan, tc)
41057718be8SEnji Cooper {
41157718be8SEnji Cooper #ifndef __HAVE_LONG_DOUBLE
41257718be8SEnji Cooper 	atf_tc_skip("Requires long double support");
41357718be8SEnji Cooper #else
41457718be8SEnji Cooper 	const long double x = 0.0L / 0.0L;
41557718be8SEnji Cooper 	long double y;
41657718be8SEnji Cooper 	size_t i;
41757718be8SEnji Cooper 
41857718be8SEnji Cooper 	if (isnan(x) == 0) {
41957718be8SEnji Cooper 		atf_tc_expect_fail("PR lib/45362");
42057718be8SEnji Cooper 		atf_tc_fail("(0.0L / 0.0L) != NaN");
42157718be8SEnji Cooper 	}
42257718be8SEnji Cooper 
42357718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++) {
42457718be8SEnji Cooper 		y = scalbnl(x, exps[i]);
42557718be8SEnji Cooper 		ATF_CHECK(isnan(y) != 0);
42657718be8SEnji Cooper 	}
42757718be8SEnji Cooper #endif
42857718be8SEnji Cooper }
42957718be8SEnji Cooper 
43057718be8SEnji Cooper ATF_TC(scalbnl_inf_neg);
ATF_TC_HEAD(scalbnl_inf_neg,tc)43157718be8SEnji Cooper ATF_TC_HEAD(scalbnl_inf_neg, tc)
43257718be8SEnji Cooper {
43357718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbnl(-Inf, n) == -Inf");
43457718be8SEnji Cooper }
43557718be8SEnji Cooper 
ATF_TC_BODY(scalbnl_inf_neg,tc)43657718be8SEnji Cooper ATF_TC_BODY(scalbnl_inf_neg, tc)
43757718be8SEnji Cooper {
43857718be8SEnji Cooper #ifndef __HAVE_LONG_DOUBLE
43957718be8SEnji Cooper 	atf_tc_skip("Requires long double support");
44057718be8SEnji Cooper #else
44157718be8SEnji Cooper 	const long double x = -1.0L / 0.0L;
44257718be8SEnji Cooper 	size_t i;
44357718be8SEnji Cooper 
44457718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++)
44557718be8SEnji Cooper 		ATF_CHECK(scalbnl(x, exps[i]) == x);
44657718be8SEnji Cooper #endif
44757718be8SEnji Cooper }
44857718be8SEnji Cooper 
44957718be8SEnji Cooper ATF_TC(scalbnl_inf_pos);
ATF_TC_HEAD(scalbnl_inf_pos,tc)45057718be8SEnji Cooper ATF_TC_HEAD(scalbnl_inf_pos, tc)
45157718be8SEnji Cooper {
45257718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbnl(+Inf, n) == +Inf");
45357718be8SEnji Cooper }
45457718be8SEnji Cooper 
ATF_TC_BODY(scalbnl_inf_pos,tc)45557718be8SEnji Cooper ATF_TC_BODY(scalbnl_inf_pos, tc)
45657718be8SEnji Cooper {
45757718be8SEnji Cooper #ifndef __HAVE_LONG_DOUBLE
45857718be8SEnji Cooper 	atf_tc_skip("Requires long double support");
45957718be8SEnji Cooper #else
46057718be8SEnji Cooper 	const long double x = 1.0L / 0.0L;
46157718be8SEnji Cooper 	size_t i;
46257718be8SEnji Cooper 
46357718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++)
46457718be8SEnji Cooper 		ATF_CHECK(scalbnl(x, exps[i]) == x);
46557718be8SEnji Cooper #endif
46657718be8SEnji Cooper }
46757718be8SEnji Cooper 
46857718be8SEnji Cooper ATF_TC(scalbnl_zero_neg);
ATF_TC_HEAD(scalbnl_zero_neg,tc)46957718be8SEnji Cooper ATF_TC_HEAD(scalbnl_zero_neg, tc)
47057718be8SEnji Cooper {
47157718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbnl(-0.0, n) == -0.0");
47257718be8SEnji Cooper }
47357718be8SEnji Cooper 
ATF_TC_BODY(scalbnl_zero_neg,tc)47457718be8SEnji Cooper ATF_TC_BODY(scalbnl_zero_neg, tc)
47557718be8SEnji Cooper {
47657718be8SEnji Cooper #ifndef __HAVE_LONG_DOUBLE
47757718be8SEnji Cooper 	atf_tc_skip("Requires long double support");
47857718be8SEnji Cooper #else
47957718be8SEnji Cooper 	const long double x = -0.0L;
48057718be8SEnji Cooper 	long double y;
48157718be8SEnji Cooper 	size_t i;
48257718be8SEnji Cooper 
48357718be8SEnji Cooper 	ATF_REQUIRE(signbit(x) != 0);
48457718be8SEnji Cooper 
48557718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++) {
48657718be8SEnji Cooper 		y = scalbnl(x, exps[i]);
48757718be8SEnji Cooper 		ATF_CHECK(x == y);
48857718be8SEnji Cooper 		ATF_CHECK(signbit(y) != 0);
48957718be8SEnji Cooper 	}
49057718be8SEnji Cooper #endif
49157718be8SEnji Cooper }
49257718be8SEnji Cooper 
49357718be8SEnji Cooper ATF_TC(scalbnl_zero_pos);
ATF_TC_HEAD(scalbnl_zero_pos,tc)49457718be8SEnji Cooper ATF_TC_HEAD(scalbnl_zero_pos, tc)
49557718be8SEnji Cooper {
49657718be8SEnji Cooper 	atf_tc_set_md_var(tc, "descr", "Test scalbnl(+0.0, n) == +0.0");
49757718be8SEnji Cooper }
49857718be8SEnji Cooper 
ATF_TC_BODY(scalbnl_zero_pos,tc)49957718be8SEnji Cooper ATF_TC_BODY(scalbnl_zero_pos, tc)
50057718be8SEnji Cooper {
50157718be8SEnji Cooper #ifndef __HAVE_LONG_DOUBLE
50257718be8SEnji Cooper 	atf_tc_skip("Requires long double support");
50357718be8SEnji Cooper #else
50457718be8SEnji Cooper 	const long double x = 0.0L;
50557718be8SEnji Cooper 	long double y;
50657718be8SEnji Cooper 	size_t i;
50757718be8SEnji Cooper 
50857718be8SEnji Cooper 	ATF_REQUIRE(signbit(x) == 0);
50957718be8SEnji Cooper 
51057718be8SEnji Cooper 	for (i = 0; i < __arraycount(exps); i++) {
51157718be8SEnji Cooper 		y = scalbnl(x, exps[i]);
51257718be8SEnji Cooper 		ATF_CHECK(x == y);
51357718be8SEnji Cooper 		ATF_CHECK(signbit(y) == 0);
51457718be8SEnji Cooper 	}
51557718be8SEnji Cooper #endif
51657718be8SEnji Cooper }
51757718be8SEnji Cooper 
ATF_TP_ADD_TCS(tp)51857718be8SEnji Cooper ATF_TP_ADD_TCS(tp)
51957718be8SEnji Cooper {
52057718be8SEnji Cooper 
52157718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbn_val);
52257718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbn_nan);
52357718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbn_inf_neg);
52457718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbn_inf_pos);
52557718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbn_ldexp);
52657718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbn_zero_neg);
52757718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbn_zero_pos);
52857718be8SEnji Cooper 
52957718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbnf_val);
53057718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbnf_nan);
53157718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbnf_inf_neg);
53257718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbnf_inf_pos);
53357718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbnf_ldexpf);
53457718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbnf_zero_neg);
53557718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbnf_zero_pos);
53657718be8SEnji Cooper 
53757718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbnl_val);
53857718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbnl_nan);
53957718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbnl_inf_neg);
54057718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbnl_inf_pos);
54157718be8SEnji Cooper /*	ATF_TP_ADD_TC(tp, scalbnl_ldexp);	*/
54257718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbnl_zero_neg);
54357718be8SEnji Cooper 	ATF_TP_ADD_TC(tp, scalbnl_zero_pos);
54457718be8SEnji Cooper 
54557718be8SEnji Cooper 	return atf_no_error();
54657718be8SEnji Cooper }
547