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