t_scalbn.c revision 276672
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#ifdef __FreeBSD__
229		errno = 0;
230#endif
231		rv = scalbnf(tests[i].inval, tests[i].exp);
232		ATF_CHECK_EQ_MSG(errno, tests[i].error,
233		    "test %zu: errno %d instead of %d", i, errno,
234		    tests[i].error);
235		ATF_CHECK_MSG(fabs(rv-tests[i].result)<2.0*FLT_EPSILON,
236		    "test %zu: return value %g instead of %g (difference %g)",
237		    i, rv, tests[i].result, tests[i].result-rv);
238	}
239}
240
241ATF_TC(scalbnf_nan);
242ATF_TC_HEAD(scalbnf_nan, tc)
243{
244	atf_tc_set_md_var(tc, "descr", "Test scalbnf(NaN, n) == NaN");
245}
246
247ATF_TC_BODY(scalbnf_nan, tc)
248{
249	const float x = 0.0L / 0.0L;
250	float y;
251	size_t i;
252
253	ATF_REQUIRE(isnan(x) != 0);
254
255	for (i = 0; i < __arraycount(exps); i++) {
256		y = scalbnf(x, exps[i]);
257		ATF_CHECK(isnan(y) != 0);
258	}
259}
260
261ATF_TC(scalbnf_inf_neg);
262ATF_TC_HEAD(scalbnf_inf_neg, tc)
263{
264	atf_tc_set_md_var(tc, "descr", "Test scalbnf(-Inf, n) == -Inf");
265}
266
267ATF_TC_BODY(scalbnf_inf_neg, tc)
268{
269	const float x = -1.0L / 0.0L;
270	size_t i;
271
272	for (i = 0; i < __arraycount(exps); i++)
273		ATF_CHECK(scalbnf(x, exps[i]) == x);
274}
275
276ATF_TC(scalbnf_inf_pos);
277ATF_TC_HEAD(scalbnf_inf_pos, tc)
278{
279	atf_tc_set_md_var(tc, "descr", "Test scalbnf(+Inf, n) == +Inf");
280}
281
282ATF_TC_BODY(scalbnf_inf_pos, tc)
283{
284	const float x = 1.0L / 0.0L;
285	size_t i;
286
287	for (i = 0; i < __arraycount(exps); i++)
288		ATF_CHECK(scalbnf(x, exps[i]) == x);
289}
290
291ATF_TC(scalbnf_ldexpf);
292ATF_TC_HEAD(scalbnf_ldexpf, tc)
293{
294	atf_tc_set_md_var(tc, "descr", "Test scalbnf(x, n) == ldexpf(x, n)");
295}
296
297ATF_TC_BODY(scalbnf_ldexpf, tc)
298{
299#if FLT_RADIX == 2
300	const float x = 2.91288191221812821;
301	float y;
302	size_t i;
303
304	for (i = 0; i < __arraycount(exps); i++) {
305		y = scalbnf(x, exps[i]);
306		ATF_CHECK_MSG(y == ldexpf(x, exps[i]),
307		    "test %zu: exponent=%d, y=%g ldexpf returns %g (diff: %g)",
308		    i, exps[i], y, ldexpf(x, exps[i]), y-ldexpf(x, exps[i]));
309	}
310#endif
311}
312
313ATF_TC(scalbnf_zero_neg);
314ATF_TC_HEAD(scalbnf_zero_neg, tc)
315{
316	atf_tc_set_md_var(tc, "descr", "Test scalbnf(-0.0, n) == -0.0");
317}
318
319ATF_TC_BODY(scalbnf_zero_neg, tc)
320{
321	const float x = -0.0L;
322	float y;
323	size_t i;
324
325	ATF_REQUIRE(signbit(x) != 0);
326
327	for (i = 0; i < __arraycount(exps); i++) {
328		y = scalbnf(x, exps[i]);
329		ATF_CHECK(x == y);
330		ATF_CHECK(signbit(y) != 0);
331	}
332}
333
334ATF_TC(scalbnf_zero_pos);
335ATF_TC_HEAD(scalbnf_zero_pos, tc)
336{
337	atf_tc_set_md_var(tc, "descr", "Test scalbnf(+0.0, n) == +0.0");
338}
339
340ATF_TC_BODY(scalbnf_zero_pos, tc)
341{
342	const float x = 0.0L;
343	float y;
344	size_t i;
345
346	ATF_REQUIRE(signbit(x) == 0);
347
348	for (i = 0; i < __arraycount(exps); i++) {
349		y = scalbnf(x, exps[i]);
350		ATF_CHECK(x == y);
351		ATF_CHECK(signbit(y) == 0);
352	}
353}
354
355/*
356 * scalbnl(3)
357 */
358ATF_TC(scalbnl_val);
359ATF_TC_HEAD(scalbnl_val, tc)
360{
361	atf_tc_set_md_var(tc, "descr", "Test scalbnl() for a few values");
362}
363
364ATF_TC_BODY(scalbnl_val, tc)
365{
366#ifndef __HAVE_LONG_DOUBLE
367	atf_tc_skip("Requires long double support");
368#else
369	const struct testcase *tests = test_vals;
370	const size_t tcnt = __arraycount(test_vals);
371	size_t i;
372	long double rv;
373
374	for (i = 0; i < tcnt; i++) {
375#ifdef __FreeBSD__
376		errno = 0;
377#endif
378		rv = scalbnl(tests[i].inval, tests[i].exp);
379		ATF_CHECK_EQ_MSG(errno, tests[i].error,
380		    "test %zu: errno %d instead of %d", i, errno,
381		    tests[i].error);
382		ATF_CHECK_MSG(fabsl(rv-(long double)tests[i].result)<2.0*LDBL_EPSILON,
383		    "test %zu: return value %Lg instead of %Lg (difference %Lg)",
384		    i, rv, (long double)tests[i].result, (long double)tests[i].result-rv);
385	}
386#endif
387}
388
389ATF_TC(scalbnl_nan);
390ATF_TC_HEAD(scalbnl_nan, tc)
391{
392	atf_tc_set_md_var(tc, "descr", "Test scalbnl(NaN, n) == NaN");
393}
394
395ATF_TC_BODY(scalbnl_nan, tc)
396{
397#ifndef __HAVE_LONG_DOUBLE
398	atf_tc_skip("Requires long double support");
399#else
400	const long double x = 0.0L / 0.0L;
401	long double y;
402	size_t i;
403
404	if (isnan(x) == 0) {
405		atf_tc_expect_fail("PR lib/45362");
406		atf_tc_fail("(0.0L / 0.0L) != NaN");
407	}
408
409	for (i = 0; i < __arraycount(exps); i++) {
410		y = scalbnl(x, exps[i]);
411		ATF_CHECK(isnan(y) != 0);
412	}
413#endif
414}
415
416ATF_TC(scalbnl_inf_neg);
417ATF_TC_HEAD(scalbnl_inf_neg, tc)
418{
419	atf_tc_set_md_var(tc, "descr", "Test scalbnl(-Inf, n) == -Inf");
420}
421
422ATF_TC_BODY(scalbnl_inf_neg, tc)
423{
424#ifndef __HAVE_LONG_DOUBLE
425	atf_tc_skip("Requires long double support");
426#else
427	const long double x = -1.0L / 0.0L;
428	size_t i;
429
430	for (i = 0; i < __arraycount(exps); i++)
431		ATF_CHECK(scalbnl(x, exps[i]) == x);
432#endif
433}
434
435ATF_TC(scalbnl_inf_pos);
436ATF_TC_HEAD(scalbnl_inf_pos, tc)
437{
438	atf_tc_set_md_var(tc, "descr", "Test scalbnl(+Inf, n) == +Inf");
439}
440
441ATF_TC_BODY(scalbnl_inf_pos, tc)
442{
443#ifndef __HAVE_LONG_DOUBLE
444	atf_tc_skip("Requires long double support");
445#else
446	const long double x = 1.0L / 0.0L;
447	size_t i;
448
449	for (i = 0; i < __arraycount(exps); i++)
450		ATF_CHECK(scalbnl(x, exps[i]) == x);
451#endif
452}
453
454ATF_TC(scalbnl_zero_neg);
455ATF_TC_HEAD(scalbnl_zero_neg, tc)
456{
457	atf_tc_set_md_var(tc, "descr", "Test scalbnl(-0.0, n) == -0.0");
458}
459
460ATF_TC_BODY(scalbnl_zero_neg, tc)
461{
462#ifndef __HAVE_LONG_DOUBLE
463	atf_tc_skip("Requires long double support");
464#else
465	const long double x = -0.0L;
466	long double y;
467	size_t i;
468
469	ATF_REQUIRE(signbit(x) != 0);
470
471	for (i = 0; i < __arraycount(exps); i++) {
472		y = scalbnl(x, exps[i]);
473		ATF_CHECK(x == y);
474		ATF_CHECK(signbit(y) != 0);
475	}
476#endif
477}
478
479ATF_TC(scalbnl_zero_pos);
480ATF_TC_HEAD(scalbnl_zero_pos, tc)
481{
482	atf_tc_set_md_var(tc, "descr", "Test scalbnl(+0.0, n) == +0.0");
483}
484
485ATF_TC_BODY(scalbnl_zero_pos, tc)
486{
487#ifndef __HAVE_LONG_DOUBLE
488	atf_tc_skip("Requires long double support");
489#else
490	const long double x = 0.0L;
491	long double y;
492	size_t i;
493
494	ATF_REQUIRE(signbit(x) == 0);
495
496	for (i = 0; i < __arraycount(exps); i++) {
497		y = scalbnl(x, exps[i]);
498		ATF_CHECK(x == y);
499		ATF_CHECK(signbit(y) == 0);
500	}
501#endif
502}
503
504ATF_TP_ADD_TCS(tp)
505{
506
507	ATF_TP_ADD_TC(tp, scalbn_val);
508	ATF_TP_ADD_TC(tp, scalbn_nan);
509	ATF_TP_ADD_TC(tp, scalbn_inf_neg);
510	ATF_TP_ADD_TC(tp, scalbn_inf_pos);
511	ATF_TP_ADD_TC(tp, scalbn_ldexp);
512	ATF_TP_ADD_TC(tp, scalbn_zero_neg);
513	ATF_TP_ADD_TC(tp, scalbn_zero_pos);
514
515	ATF_TP_ADD_TC(tp, scalbnf_val);
516	ATF_TP_ADD_TC(tp, scalbnf_nan);
517	ATF_TP_ADD_TC(tp, scalbnf_inf_neg);
518	ATF_TP_ADD_TC(tp, scalbnf_inf_pos);
519	ATF_TP_ADD_TC(tp, scalbnf_ldexpf);
520	ATF_TP_ADD_TC(tp, scalbnf_zero_neg);
521	ATF_TP_ADD_TC(tp, scalbnf_zero_pos);
522
523	ATF_TP_ADD_TC(tp, scalbnl_val);
524	ATF_TP_ADD_TC(tp, scalbnl_nan);
525	ATF_TP_ADD_TC(tp, scalbnl_inf_neg);
526	ATF_TP_ADD_TC(tp, scalbnl_inf_pos);
527/*	ATF_TP_ADD_TC(tp, scalbnl_ldexp);	*/
528	ATF_TP_ADD_TC(tp, scalbnl_zero_neg);
529	ATF_TP_ADD_TC(tp, scalbnl_zero_pos);
530
531	return atf_no_error();
532}
533