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