t_scalbn.c revision 1.15 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