t_scalbn.c revision 314817
1/* $NetBSD: t_scalbn.c,v 1.14 2017/01/13 21:09:12 agc 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.14 2017/01/13 21:09:12 agc 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		errno = 0;
85		rv = scalbn(tests[i].inval, tests[i].exp);
86		ATF_CHECK_EQ_MSG(errno, tests[i].error,
87		    "test %zu: errno %d instead of %d", i, errno,
88		    tests[i].error);
89		ATF_CHECK_MSG(fabs(rv-tests[i].result)<2.0*DBL_EPSILON,
90		    "test %zu: return value %g instead of %g (difference %g)",
91		    i, rv, tests[i].result, tests[i].result-rv);
92	}
93}
94
95ATF_TC(scalbn_nan);
96ATF_TC_HEAD(scalbn_nan, tc)
97{
98	atf_tc_set_md_var(tc, "descr", "Test scalbn(NaN, n) == NaN");
99}
100
101ATF_TC_BODY(scalbn_nan, tc)
102{
103	const double x = 0.0L / 0.0L;
104	double y;
105	size_t i;
106
107	ATF_REQUIRE(isnan(x) != 0);
108
109	for (i = 0; i < __arraycount(exps); i++) {
110		y = scalbn(x, exps[i]);
111		ATF_CHECK(isnan(y) != 0);
112	}
113}
114
115ATF_TC(scalbn_inf_neg);
116ATF_TC_HEAD(scalbn_inf_neg, tc)
117{
118	atf_tc_set_md_var(tc, "descr", "Test scalbn(-Inf, n) == -Inf");
119}
120
121ATF_TC_BODY(scalbn_inf_neg, tc)
122{
123	const double x = -1.0L / 0.0L;
124	size_t i;
125
126	for (i = 0; i < __arraycount(exps); i++)
127		ATF_CHECK(scalbn(x, exps[i]) == x);
128}
129
130ATF_TC(scalbn_inf_pos);
131ATF_TC_HEAD(scalbn_inf_pos, tc)
132{
133	atf_tc_set_md_var(tc, "descr", "Test scalbn(+Inf, n) == +Inf");
134}
135
136ATF_TC_BODY(scalbn_inf_pos, tc)
137{
138	const double x = 1.0L / 0.0L;
139	size_t i;
140
141	for (i = 0; i < __arraycount(exps); i++)
142		ATF_CHECK(scalbn(x, exps[i]) == x);
143}
144
145ATF_TC(scalbn_ldexp);
146ATF_TC_HEAD(scalbn_ldexp, tc)
147{
148	atf_tc_set_md_var(tc, "descr", "Test scalbn(x, n) == ldexp(x, n)");
149}
150
151ATF_TC_BODY(scalbn_ldexp, tc)
152{
153#if FLT_RADIX == 2
154	const double x = 2.91288191221812821;
155	double y;
156	size_t i;
157
158	for (i = 0; i < __arraycount(exps); i++) {
159		y = scalbn(x, exps[i]);
160		ATF_CHECK_MSG(y == ldexp(x, exps[i]), "test %zu: exponent=%d, "
161		    "y=%g, expected %g (diff: %g)", i, exps[i], y,
162		    ldexp(x, exps[i]), y - ldexp(x, exps[i]));
163	}
164#endif
165}
166
167ATF_TC(scalbn_zero_neg);
168ATF_TC_HEAD(scalbn_zero_neg, tc)
169{
170	atf_tc_set_md_var(tc, "descr", "Test scalbn(-0.0, n) == -0.0");
171}
172
173ATF_TC_BODY(scalbn_zero_neg, tc)
174{
175	const double x = -0.0L;
176	double y;
177	size_t i;
178
179	ATF_REQUIRE(signbit(x) != 0);
180
181	for (i = 0; i < __arraycount(exps); i++) {
182		y = scalbn(x, exps[i]);
183		ATF_CHECK(x == y);
184		ATF_CHECK(signbit(y) != 0);
185	}
186}
187
188ATF_TC(scalbn_zero_pos);
189ATF_TC_HEAD(scalbn_zero_pos, tc)
190{
191	atf_tc_set_md_var(tc, "descr", "Test scalbn(+0.0, n) == +0.0");
192}
193
194ATF_TC_BODY(scalbn_zero_pos, tc)
195{
196	const double x = 0.0L;
197	double y;
198	size_t i;
199
200	ATF_REQUIRE(signbit(x) == 0);
201
202	for (i = 0; i < __arraycount(exps); i++) {
203		y = scalbn(x, exps[i]);
204		ATF_CHECK(x == y);
205		ATF_CHECK(signbit(y) == 0);
206	}
207}
208
209/*
210 * scalbnf(3)
211 */
212ATF_TC(scalbnf_val);
213ATF_TC_HEAD(scalbnf_val, tc)
214{
215	atf_tc_set_md_var(tc, "descr", "Test scalbnf() for a few values");
216}
217
218ATF_TC_BODY(scalbnf_val, tc)
219{
220	const struct testcase *tests = test_vals;
221	const size_t tcnt = __arraycount(test_vals);
222	size_t i;
223	double rv;
224
225	for (i = 0; i < tcnt; i++) {
226		errno = 0;
227		rv = scalbnf(tests[i].inval, tests[i].exp);
228		ATF_CHECK_EQ_MSG(errno, tests[i].error,
229		    "test %zu: errno %d instead of %d", i, errno,
230		    tests[i].error);
231		ATF_CHECK_MSG(fabs(rv-tests[i].result)<2.0*FLT_EPSILON,
232		    "test %zu: return value %g instead of %g (difference %g)",
233		    i, rv, tests[i].result, tests[i].result-rv);
234	}
235}
236
237ATF_TC(scalbnf_nan);
238ATF_TC_HEAD(scalbnf_nan, tc)
239{
240	atf_tc_set_md_var(tc, "descr", "Test scalbnf(NaN, n) == NaN");
241}
242
243ATF_TC_BODY(scalbnf_nan, tc)
244{
245	const float x = 0.0L / 0.0L;
246	float y;
247	size_t i;
248
249	ATF_REQUIRE(isnan(x) != 0);
250
251	for (i = 0; i < __arraycount(exps); i++) {
252		y = scalbnf(x, exps[i]);
253		ATF_CHECK(isnan(y) != 0);
254	}
255}
256
257ATF_TC(scalbnf_inf_neg);
258ATF_TC_HEAD(scalbnf_inf_neg, tc)
259{
260	atf_tc_set_md_var(tc, "descr", "Test scalbnf(-Inf, n) == -Inf");
261}
262
263ATF_TC_BODY(scalbnf_inf_neg, tc)
264{
265	const float x = -1.0L / 0.0L;
266	size_t i;
267
268	for (i = 0; i < __arraycount(exps); i++)
269		ATF_CHECK(scalbnf(x, exps[i]) == x);
270}
271
272ATF_TC(scalbnf_inf_pos);
273ATF_TC_HEAD(scalbnf_inf_pos, tc)
274{
275	atf_tc_set_md_var(tc, "descr", "Test scalbnf(+Inf, n) == +Inf");
276}
277
278ATF_TC_BODY(scalbnf_inf_pos, tc)
279{
280	const float x = 1.0L / 0.0L;
281	size_t i;
282
283	for (i = 0; i < __arraycount(exps); i++)
284		ATF_CHECK(scalbnf(x, exps[i]) == x);
285}
286
287ATF_TC(scalbnf_ldexpf);
288ATF_TC_HEAD(scalbnf_ldexpf, tc)
289{
290	atf_tc_set_md_var(tc, "descr", "Test scalbnf(x, n) == ldexpf(x, n)");
291}
292
293ATF_TC_BODY(scalbnf_ldexpf, tc)
294{
295#if FLT_RADIX == 2
296	const float x = 2.91288191221812821;
297	float y;
298	size_t i;
299
300	for (i = 0; i < __arraycount(exps); i++) {
301		y = scalbnf(x, exps[i]);
302		ATF_CHECK_MSG(y == ldexpf(x, exps[i]),
303		    "test %zu: exponent=%d, y=%g ldexpf returns %g (diff: %g)",
304		    i, exps[i], y, ldexpf(x, exps[i]), y-ldexpf(x, exps[i]));
305	}
306#endif
307}
308
309ATF_TC(scalbnf_zero_neg);
310ATF_TC_HEAD(scalbnf_zero_neg, tc)
311{
312	atf_tc_set_md_var(tc, "descr", "Test scalbnf(-0.0, n) == -0.0");
313}
314
315ATF_TC_BODY(scalbnf_zero_neg, tc)
316{
317	const float x = -0.0L;
318	float y;
319	size_t i;
320
321	ATF_REQUIRE(signbit(x) != 0);
322
323	for (i = 0; i < __arraycount(exps); i++) {
324		y = scalbnf(x, exps[i]);
325		ATF_CHECK(x == y);
326		ATF_CHECK(signbit(y) != 0);
327	}
328}
329
330ATF_TC(scalbnf_zero_pos);
331ATF_TC_HEAD(scalbnf_zero_pos, tc)
332{
333	atf_tc_set_md_var(tc, "descr", "Test scalbnf(+0.0, n) == +0.0");
334}
335
336ATF_TC_BODY(scalbnf_zero_pos, tc)
337{
338	const float x = 0.0L;
339	float y;
340	size_t i;
341
342	ATF_REQUIRE(signbit(x) == 0);
343
344	for (i = 0; i < __arraycount(exps); i++) {
345		y = scalbnf(x, exps[i]);
346		ATF_CHECK(x == y);
347		ATF_CHECK(signbit(y) == 0);
348	}
349}
350
351/*
352 * scalbnl(3)
353 */
354ATF_TC(scalbnl_val);
355ATF_TC_HEAD(scalbnl_val, tc)
356{
357	atf_tc_set_md_var(tc, "descr", "Test scalbnl() for a few values");
358}
359
360ATF_TC_BODY(scalbnl_val, tc)
361{
362#ifndef __HAVE_LONG_DOUBLE
363	atf_tc_skip("Requires long double support");
364#else
365	const struct testcase *tests = test_vals;
366	const size_t tcnt = __arraycount(test_vals);
367	size_t i;
368	long double rv;
369
370	for (i = 0; i < tcnt; i++) {
371		errno = 0;
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