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