t_scalbn.c revision 272343
1/* $NetBSD: t_scalbn.c,v 1.11 2014/03/03 10:39:08 martin 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#include <sys/cdefs.h>
32__RCSID("$NetBSD: t_scalbn.c,v 1.11 2014/03/03 10:39:08 martin Exp $");
33
34#include <math.h>
35#include <limits.h>
36#include <float.h>
37#include <errno.h>
38
39#include <atf-c.h>
40
41static const int exps[] = { 0, 1, -1, 100, -100 };
42
43/* tests here do not require specific precision, so we just use double */
44struct testcase {
45	int exp;
46	double inval;
47	double result;
48	int error;
49};
50struct testcase test_vals[] = {
51	{ 0,		1.00085,	1.00085,	0 },
52	{ 0,		0.99755,	0.99755,	0 },
53	{ 0,		-1.00085,	-1.00085,	0 },
54	{ 0,		-0.99755,	-0.99755,	0 },
55	{ 1,		1.00085,	2.0* 1.00085,	0 },
56	{ 1,		0.99755,	2.0* 0.99755,	0 },
57	{ 1,		-1.00085,	2.0* -1.00085,	0 },
58	{ 1,		-0.99755,	2.0* -0.99755,	0 },
59
60	/*
61	 * We could add more corner test cases here, but we would have to
62	 * add some ifdefs for the exact format and use a reliable
63	 * generator program - bail for now and only do trivial stuff above.
64	 */
65};
66
67/*
68 * scalbn(3)
69 */
70ATF_TC(scalbn_val);
71ATF_TC_HEAD(scalbn_val, tc)
72{
73	atf_tc_set_md_var(tc, "descr", "Test scalbn() for a few values");
74}
75
76ATF_TC_BODY(scalbn_val, tc)
77{
78	const struct testcase *tests = test_vals;
79	const size_t tcnt = __arraycount(test_vals);
80	size_t i;
81	double rv;
82
83	for (i = 0; i < tcnt; i++) {
84		rv = scalbn(tests[i].inval, tests[i].exp);
85		ATF_CHECK_EQ_MSG(errno, tests[i].error,
86		    "test %zu: errno %d instead of %d", i, errno,
87		    tests[i].error);
88		ATF_CHECK_MSG(fabs(rv-tests[i].result)<2.0*DBL_EPSILON,
89		    "test %zu: return value %g instead of %g (difference %g)",
90		    i, rv, tests[i].result, tests[i].result-rv);
91	}
92}
93
94ATF_TC(scalbn_nan);
95ATF_TC_HEAD(scalbn_nan, tc)
96{
97	atf_tc_set_md_var(tc, "descr", "Test scalbn(NaN, n) == NaN");
98}
99
100ATF_TC_BODY(scalbn_nan, tc)
101{
102	const double x = 0.0L / 0.0L;
103	double y;
104	size_t i;
105
106	ATF_REQUIRE(isnan(x) != 0);
107
108	for (i = 0; i < __arraycount(exps); i++) {
109		y = scalbn(x, exps[i]);
110		ATF_CHECK(isnan(y) != 0);
111	}
112}
113
114ATF_TC(scalbn_inf_neg);
115ATF_TC_HEAD(scalbn_inf_neg, tc)
116{
117	atf_tc_set_md_var(tc, "descr", "Test scalbn(-Inf, n) == -Inf");
118}
119
120ATF_TC_BODY(scalbn_inf_neg, tc)
121{
122	const double x = -1.0L / 0.0L;
123	size_t i;
124
125	for (i = 0; i < __arraycount(exps); i++)
126		ATF_CHECK(scalbn(x, exps[i]) == x);
127}
128
129ATF_TC(scalbn_inf_pos);
130ATF_TC_HEAD(scalbn_inf_pos, tc)
131{
132	atf_tc_set_md_var(tc, "descr", "Test scalbn(+Inf, n) == +Inf");
133}
134
135ATF_TC_BODY(scalbn_inf_pos, tc)
136{
137	const double x = 1.0L / 0.0L;
138	size_t i;
139
140	for (i = 0; i < __arraycount(exps); i++)
141		ATF_CHECK(scalbn(x, exps[i]) == x);
142}
143
144ATF_TC(scalbn_ldexp);
145ATF_TC_HEAD(scalbn_ldexp, tc)
146{
147	atf_tc_set_md_var(tc, "descr", "Test scalbn(x, n) == ldexp(x, n)");
148}
149
150ATF_TC_BODY(scalbn_ldexp, tc)
151{
152#if FLT_RADIX == 2
153	const double x = 2.91288191221812821;
154	double y;
155	size_t i;
156
157	for (i = 0; i < __arraycount(exps); i++) {
158		y = scalbn(x, exps[i]);
159		ATF_CHECK_MSG(y == ldexp(x, exps[i]), "test %zu: exponent=%d, "
160		    "y=%g, expected %g (diff: %g)", i, exps[i], y,
161		    ldexp(x, exps[i]), y - ldexp(x, exps[i]));
162	}
163#endif
164}
165
166ATF_TC(scalbn_zero_neg);
167ATF_TC_HEAD(scalbn_zero_neg, tc)
168{
169	atf_tc_set_md_var(tc, "descr", "Test scalbn(-0.0, n) == -0.0");
170}
171
172ATF_TC_BODY(scalbn_zero_neg, tc)
173{
174	const double x = -0.0L;
175	double y;
176	size_t i;
177
178	ATF_REQUIRE(signbit(x) != 0);
179
180	for (i = 0; i < __arraycount(exps); i++) {
181		y = scalbn(x, exps[i]);
182		ATF_CHECK(x == y);
183		ATF_CHECK(signbit(y) != 0);
184	}
185}
186
187ATF_TC(scalbn_zero_pos);
188ATF_TC_HEAD(scalbn_zero_pos, tc)
189{
190	atf_tc_set_md_var(tc, "descr", "Test scalbn(+0.0, n) == +0.0");
191}
192
193ATF_TC_BODY(scalbn_zero_pos, tc)
194{
195	const double x = 0.0L;
196	double y;
197	size_t i;
198
199	ATF_REQUIRE(signbit(x) == 0);
200
201	for (i = 0; i < __arraycount(exps); i++) {
202		y = scalbn(x, exps[i]);
203		ATF_CHECK(x == y);
204		ATF_CHECK(signbit(y) == 0);
205	}
206}
207
208/*
209 * scalbnf(3)
210 */
211ATF_TC(scalbnf_val);
212ATF_TC_HEAD(scalbnf_val, tc)
213{
214	atf_tc_set_md_var(tc, "descr", "Test scalbnf() for a few values");
215}
216
217ATF_TC_BODY(scalbnf_val, tc)
218{
219	const struct testcase *tests = test_vals;
220	const size_t tcnt = __arraycount(test_vals);
221	size_t i;
222	double rv;
223
224	for (i = 0; i < tcnt; i++) {
225		rv = scalbnf(tests[i].inval, tests[i].exp);
226		ATF_CHECK_EQ_MSG(errno, tests[i].error,
227		    "test %zu: errno %d instead of %d", i, errno,
228		    tests[i].error);
229		ATF_CHECK_MSG(fabs(rv-tests[i].result)<2.0*FLT_EPSILON,
230		    "test %zu: return value %g instead of %g (difference %g)",
231		    i, rv, tests[i].result, tests[i].result-rv);
232	}
233}
234
235ATF_TC(scalbnf_nan);
236ATF_TC_HEAD(scalbnf_nan, tc)
237{
238	atf_tc_set_md_var(tc, "descr", "Test scalbnf(NaN, n) == NaN");
239}
240
241ATF_TC_BODY(scalbnf_nan, tc)
242{
243	const float x = 0.0L / 0.0L;
244	float y;
245	size_t i;
246
247	ATF_REQUIRE(isnan(x) != 0);
248
249	for (i = 0; i < __arraycount(exps); i++) {
250		y = scalbnf(x, exps[i]);
251		ATF_CHECK(isnan(y) != 0);
252	}
253}
254
255ATF_TC(scalbnf_inf_neg);
256ATF_TC_HEAD(scalbnf_inf_neg, tc)
257{
258	atf_tc_set_md_var(tc, "descr", "Test scalbnf(-Inf, n) == -Inf");
259}
260
261ATF_TC_BODY(scalbnf_inf_neg, tc)
262{
263	const float x = -1.0L / 0.0L;
264	size_t i;
265
266	for (i = 0; i < __arraycount(exps); i++)
267		ATF_CHECK(scalbnf(x, exps[i]) == x);
268}
269
270ATF_TC(scalbnf_inf_pos);
271ATF_TC_HEAD(scalbnf_inf_pos, tc)
272{
273	atf_tc_set_md_var(tc, "descr", "Test scalbnf(+Inf, n) == +Inf");
274}
275
276ATF_TC_BODY(scalbnf_inf_pos, tc)
277{
278	const float x = 1.0L / 0.0L;
279	size_t i;
280
281	for (i = 0; i < __arraycount(exps); i++)
282		ATF_CHECK(scalbnf(x, exps[i]) == x);
283}
284
285ATF_TC(scalbnf_ldexpf);
286ATF_TC_HEAD(scalbnf_ldexpf, tc)
287{
288	atf_tc_set_md_var(tc, "descr", "Test scalbnf(x, n) == ldexpf(x, n)");
289}
290
291ATF_TC_BODY(scalbnf_ldexpf, tc)
292{
293#if FLT_RADIX == 2
294	const float x = 2.91288191221812821;
295	float y;
296	size_t i;
297
298	for (i = 0; i < __arraycount(exps); i++) {
299		y = scalbnf(x, exps[i]);
300		ATF_CHECK_MSG(y == ldexpf(x, exps[i]),
301		    "test %zu: exponent=%d, y=%g ldexpf returns %g (diff: %g)",
302		    i, exps[i], y, ldexpf(x, exps[i]), y-ldexpf(x, exps[i]));
303	}
304#endif
305}
306
307ATF_TC(scalbnf_zero_neg);
308ATF_TC_HEAD(scalbnf_zero_neg, tc)
309{
310	atf_tc_set_md_var(tc, "descr", "Test scalbnf(-0.0, n) == -0.0");
311}
312
313ATF_TC_BODY(scalbnf_zero_neg, tc)
314{
315	const float x = -0.0L;
316	float y;
317	size_t i;
318
319	ATF_REQUIRE(signbit(x) != 0);
320
321	for (i = 0; i < __arraycount(exps); i++) {
322		y = scalbnf(x, exps[i]);
323		ATF_CHECK(x == y);
324		ATF_CHECK(signbit(y) != 0);
325	}
326}
327
328ATF_TC(scalbnf_zero_pos);
329ATF_TC_HEAD(scalbnf_zero_pos, tc)
330{
331	atf_tc_set_md_var(tc, "descr", "Test scalbnf(+0.0, n) == +0.0");
332}
333
334ATF_TC_BODY(scalbnf_zero_pos, tc)
335{
336	const float x = 0.0L;
337	float y;
338	size_t i;
339
340	ATF_REQUIRE(signbit(x) == 0);
341
342	for (i = 0; i < __arraycount(exps); i++) {
343		y = scalbnf(x, exps[i]);
344		ATF_CHECK(x == y);
345		ATF_CHECK(signbit(y) == 0);
346	}
347}
348
349/*
350 * scalbnl(3)
351 */
352ATF_TC(scalbnl_val);
353ATF_TC_HEAD(scalbnl_val, tc)
354{
355	atf_tc_set_md_var(tc, "descr", "Test scalbnl() for a few values");
356}
357
358ATF_TC_BODY(scalbnl_val, tc)
359{
360#ifndef __HAVE_LONG_DOUBLE
361	atf_tc_skip("Requires long double support");
362#else
363	const struct testcase *tests = test_vals;
364	const size_t tcnt = __arraycount(test_vals);
365	size_t i;
366	long double rv;
367
368	for (i = 0; i < tcnt; i++) {
369		rv = scalbnl(tests[i].inval, tests[i].exp);
370		ATF_CHECK_EQ_MSG(errno, tests[i].error,
371		    "test %zu: errno %d instead of %d", i, errno,
372		    tests[i].error);
373		ATF_CHECK_MSG(fabsl(rv-(long double)tests[i].result)<2.0*LDBL_EPSILON,
374		    "test %zu: return value %Lg instead of %Lg (difference %Lg)",
375		    i, rv, (long double)tests[i].result, (long double)tests[i].result-rv);
376	}
377#endif
378}
379
380ATF_TC(scalbnl_nan);
381ATF_TC_HEAD(scalbnl_nan, tc)
382{
383	atf_tc_set_md_var(tc, "descr", "Test scalbnl(NaN, n) == NaN");
384}
385
386ATF_TC_BODY(scalbnl_nan, tc)
387{
388#ifndef __HAVE_LONG_DOUBLE
389	atf_tc_skip("Requires long double support");
390#else
391	const long double x = 0.0L / 0.0L;
392	long double y;
393	size_t i;
394
395	if (isnan(x) == 0) {
396		atf_tc_expect_fail("PR lib/45362");
397		atf_tc_fail("(0.0L / 0.0L) != NaN");
398	}
399
400	for (i = 0; i < __arraycount(exps); i++) {
401		y = scalbnl(x, exps[i]);
402		ATF_CHECK(isnan(y) != 0);
403	}
404#endif
405}
406
407ATF_TC(scalbnl_inf_neg);
408ATF_TC_HEAD(scalbnl_inf_neg, tc)
409{
410	atf_tc_set_md_var(tc, "descr", "Test scalbnl(-Inf, n) == -Inf");
411}
412
413ATF_TC_BODY(scalbnl_inf_neg, tc)
414{
415#ifndef __HAVE_LONG_DOUBLE
416	atf_tc_skip("Requires long double support");
417#else
418	const long double x = -1.0L / 0.0L;
419	size_t i;
420
421	for (i = 0; i < __arraycount(exps); i++)
422		ATF_CHECK(scalbnl(x, exps[i]) == x);
423#endif
424}
425
426ATF_TC(scalbnl_inf_pos);
427ATF_TC_HEAD(scalbnl_inf_pos, tc)
428{
429	atf_tc_set_md_var(tc, "descr", "Test scalbnl(+Inf, n) == +Inf");
430}
431
432ATF_TC_BODY(scalbnl_inf_pos, tc)
433{
434#ifndef __HAVE_LONG_DOUBLE
435	atf_tc_skip("Requires long double support");
436#else
437	const long double x = 1.0L / 0.0L;
438	size_t i;
439
440	for (i = 0; i < __arraycount(exps); i++)
441		ATF_CHECK(scalbnl(x, exps[i]) == x);
442#endif
443}
444
445ATF_TC(scalbnl_zero_neg);
446ATF_TC_HEAD(scalbnl_zero_neg, tc)
447{
448	atf_tc_set_md_var(tc, "descr", "Test scalbnl(-0.0, n) == -0.0");
449}
450
451ATF_TC_BODY(scalbnl_zero_neg, tc)
452{
453#ifndef __HAVE_LONG_DOUBLE
454	atf_tc_skip("Requires long double support");
455#else
456	const long double x = -0.0L;
457	long double y;
458	size_t i;
459
460	ATF_REQUIRE(signbit(x) != 0);
461
462	for (i = 0; i < __arraycount(exps); i++) {
463		y = scalbnl(x, exps[i]);
464		ATF_CHECK(x == y);
465		ATF_CHECK(signbit(y) != 0);
466	}
467#endif
468}
469
470ATF_TC(scalbnl_zero_pos);
471ATF_TC_HEAD(scalbnl_zero_pos, tc)
472{
473	atf_tc_set_md_var(tc, "descr", "Test scalbnl(+0.0, n) == +0.0");
474}
475
476ATF_TC_BODY(scalbnl_zero_pos, tc)
477{
478#ifndef __HAVE_LONG_DOUBLE
479	atf_tc_skip("Requires long double support");
480#else
481	const long double x = 0.0L;
482	long double y;
483	size_t i;
484
485	ATF_REQUIRE(signbit(x) == 0);
486
487	for (i = 0; i < __arraycount(exps); i++) {
488		y = scalbnl(x, exps[i]);
489		ATF_CHECK(x == y);
490		ATF_CHECK(signbit(y) == 0);
491	}
492#endif
493}
494
495ATF_TP_ADD_TCS(tp)
496{
497
498	ATF_TP_ADD_TC(tp, scalbn_val);
499	ATF_TP_ADD_TC(tp, scalbn_nan);
500	ATF_TP_ADD_TC(tp, scalbn_inf_neg);
501	ATF_TP_ADD_TC(tp, scalbn_inf_pos);
502	ATF_TP_ADD_TC(tp, scalbn_ldexp);
503	ATF_TP_ADD_TC(tp, scalbn_zero_neg);
504	ATF_TP_ADD_TC(tp, scalbn_zero_pos);
505
506	ATF_TP_ADD_TC(tp, scalbnf_val);
507	ATF_TP_ADD_TC(tp, scalbnf_nan);
508	ATF_TP_ADD_TC(tp, scalbnf_inf_neg);
509	ATF_TP_ADD_TC(tp, scalbnf_inf_pos);
510	ATF_TP_ADD_TC(tp, scalbnf_ldexpf);
511	ATF_TP_ADD_TC(tp, scalbnf_zero_neg);
512	ATF_TP_ADD_TC(tp, scalbnf_zero_pos);
513
514	ATF_TP_ADD_TC(tp, scalbnl_val);
515	ATF_TP_ADD_TC(tp, scalbnl_nan);
516	ATF_TP_ADD_TC(tp, scalbnl_inf_neg);
517	ATF_TP_ADD_TC(tp, scalbnl_inf_pos);
518/*	ATF_TP_ADD_TC(tp, scalbnl_ldexp);	*/
519	ATF_TP_ADD_TC(tp, scalbnl_zero_neg);
520	ATF_TP_ADD_TC(tp, scalbnl_zero_pos);
521
522	return atf_no_error();
523}
524