1/* $NetBSD: t_scalbn.c,v 1.18 2024/06/09 16:53:12 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.18 2024/06/09 16:53:12 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 42static const int exps[] = { 0, 1, -1, 100, -100 }; 43 44/* tests here do not require specific precision, so we just use double */ 45struct testcase { 46 int exp; 47 double inval; 48 double result; 49 int error; 50 int except; 51}; 52struct 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 */ 72ATF_TC(scalbn_val); 73ATF_TC_HEAD(scalbn_val, tc) 74{ 75 atf_tc_set_md_var(tc, "descr", "Test scalbn() for a few values"); 76} 77 78ATF_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 109ATF_TC(scalbn_nan); 110ATF_TC_HEAD(scalbn_nan, tc) 111{ 112 atf_tc_set_md_var(tc, "descr", "Test scalbn(NaN, n) == NaN"); 113} 114 115ATF_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 129ATF_TC(scalbn_inf_neg); 130ATF_TC_HEAD(scalbn_inf_neg, tc) 131{ 132 atf_tc_set_md_var(tc, "descr", "Test scalbn(-Inf, n) == -Inf"); 133} 134 135ATF_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 144ATF_TC(scalbn_inf_pos); 145ATF_TC_HEAD(scalbn_inf_pos, tc) 146{ 147 atf_tc_set_md_var(tc, "descr", "Test scalbn(+Inf, n) == +Inf"); 148} 149 150ATF_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 159ATF_TC(scalbn_ldexp); 160ATF_TC_HEAD(scalbn_ldexp, tc) 161{ 162 atf_tc_set_md_var(tc, "descr", "Test scalbn(x, n) == ldexp(x, n)"); 163} 164 165ATF_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 181ATF_TC(scalbn_zero_neg); 182ATF_TC_HEAD(scalbn_zero_neg, tc) 183{ 184 atf_tc_set_md_var(tc, "descr", "Test scalbn(-0.0, n) == -0.0"); 185} 186 187ATF_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 202ATF_TC(scalbn_zero_pos); 203ATF_TC_HEAD(scalbn_zero_pos, tc) 204{ 205 atf_tc_set_md_var(tc, "descr", "Test scalbn(+0.0, n) == +0.0"); 206} 207 208ATF_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 */ 226ATF_TC(scalbnf_val); 227ATF_TC_HEAD(scalbnf_val, tc) 228{ 229 atf_tc_set_md_var(tc, "descr", "Test scalbnf() for a few values"); 230} 231 232ATF_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 fabsf((tests[i].result - rv)/tests[i].result)); 251 } 252} 253 254ATF_TC(scalbnf_nan); 255ATF_TC_HEAD(scalbnf_nan, tc) 256{ 257 atf_tc_set_md_var(tc, "descr", "Test scalbnf(NaN, n) == NaN"); 258} 259 260ATF_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 274ATF_TC(scalbnf_inf_neg); 275ATF_TC_HEAD(scalbnf_inf_neg, tc) 276{ 277 atf_tc_set_md_var(tc, "descr", "Test scalbnf(-Inf, n) == -Inf"); 278} 279 280ATF_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 289ATF_TC(scalbnf_inf_pos); 290ATF_TC_HEAD(scalbnf_inf_pos, tc) 291{ 292 atf_tc_set_md_var(tc, "descr", "Test scalbnf(+Inf, n) == +Inf"); 293} 294 295ATF_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 304ATF_TC(scalbnf_ldexpf); 305ATF_TC_HEAD(scalbnf_ldexpf, tc) 306{ 307 atf_tc_set_md_var(tc, "descr", "Test scalbnf(x, n) == ldexpf(x, n)"); 308} 309 310ATF_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 326ATF_TC(scalbnf_zero_neg); 327ATF_TC_HEAD(scalbnf_zero_neg, tc) 328{ 329 atf_tc_set_md_var(tc, "descr", "Test scalbnf(-0.0, n) == -0.0"); 330} 331 332ATF_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 347ATF_TC(scalbnf_zero_pos); 348ATF_TC_HEAD(scalbnf_zero_pos, tc) 349{ 350 atf_tc_set_md_var(tc, "descr", "Test scalbnf(+0.0, n) == +0.0"); 351} 352 353ATF_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 */ 371ATF_TC(scalbnl_val); 372ATF_TC_HEAD(scalbnl_val, tc) 373{ 374 atf_tc_set_md_var(tc, "descr", "Test scalbnl() for a few values"); 375} 376 377ATF_TC_BODY(scalbnl_val, tc) 378{ 379 const struct testcase *tests = test_vals; 380 const size_t tcnt = __arraycount(test_vals); 381 size_t i; 382 long double rv; 383 384 for (i = 0; i < tcnt; i++) { 385 errno = 0; 386 rv = scalbnl(tests[i].inval, tests[i].exp); 387 ATF_CHECK_EQ_MSG(errno, tests[i].error, 388 "test %zu: errno %d instead of %d", i, errno, 389 tests[i].error); 390 /* scalbn is always exact except for underflow or overflow. */ 391 ATF_CHECK_MSG(rv == (long double)tests[i].result, 392 "test %zu: return value %.35Lg instead of %.35Lg" 393 " (error %.35Lg)", 394 i, rv, (long double)tests[i].result, 395 fabsl(((long double)tests[i].result - rv)/tests[i].result)); 396 } 397} 398 399ATF_TC(scalbnl_nan); 400ATF_TC_HEAD(scalbnl_nan, tc) 401{ 402 atf_tc_set_md_var(tc, "descr", "Test scalbnl(NaN, n) == NaN"); 403} 404 405ATF_TC_BODY(scalbnl_nan, tc) 406{ 407 const long double x = 0.0L / 0.0L; 408 long double y; 409 size_t i; 410 411 ATF_CHECK_MSG(isnan(x), "x=%La", x); 412 413 for (i = 0; i < __arraycount(exps); i++) { 414 y = scalbnl(x, exps[i]); 415 ATF_CHECK_MSG(isnan(y), "y=%La", y); 416 } 417} 418 419ATF_TC(scalbnl_inf_neg); 420ATF_TC_HEAD(scalbnl_inf_neg, tc) 421{ 422 atf_tc_set_md_var(tc, "descr", "Test scalbnl(-Inf, n) == -Inf"); 423} 424 425ATF_TC_BODY(scalbnl_inf_neg, tc) 426{ 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} 433 434ATF_TC(scalbnl_inf_pos); 435ATF_TC_HEAD(scalbnl_inf_pos, tc) 436{ 437 atf_tc_set_md_var(tc, "descr", "Test scalbnl(+Inf, n) == +Inf"); 438} 439 440ATF_TC_BODY(scalbnl_inf_pos, tc) 441{ 442 const long double x = 1.0L / 0.0L; 443 size_t i; 444 445 for (i = 0; i < __arraycount(exps); i++) 446 ATF_CHECK(scalbnl(x, exps[i]) == x); 447} 448 449ATF_TC(scalbnl_zero_neg); 450ATF_TC_HEAD(scalbnl_zero_neg, tc) 451{ 452 atf_tc_set_md_var(tc, "descr", "Test scalbnl(-0.0, n) == -0.0"); 453} 454 455ATF_TC_BODY(scalbnl_zero_neg, tc) 456{ 457 const long double x = -0.0L; 458 long double y; 459 size_t i; 460 461 ATF_REQUIRE(signbit(x) != 0); 462 463 for (i = 0; i < __arraycount(exps); i++) { 464 y = scalbnl(x, exps[i]); 465 ATF_CHECK(x == y); 466 ATF_CHECK(signbit(y) != 0); 467 } 468} 469 470ATF_TC(scalbnl_zero_pos); 471ATF_TC_HEAD(scalbnl_zero_pos, tc) 472{ 473 atf_tc_set_md_var(tc, "descr", "Test scalbnl(+0.0, n) == +0.0"); 474} 475 476ATF_TC_BODY(scalbnl_zero_pos, tc) 477{ 478 const long double x = 0.0L; 479 long double y; 480 size_t i; 481 482 ATF_REQUIRE(signbit(x) == 0); 483 484 for (i = 0; i < __arraycount(exps); i++) { 485 y = scalbnl(x, exps[i]); 486 ATF_CHECK(x == y); 487 ATF_CHECK(signbit(y) == 0); 488 } 489} 490 491ATF_TP_ADD_TCS(tp) 492{ 493 494 ATF_TP_ADD_TC(tp, scalbn_val); 495 ATF_TP_ADD_TC(tp, scalbn_nan); 496 ATF_TP_ADD_TC(tp, scalbn_inf_neg); 497 ATF_TP_ADD_TC(tp, scalbn_inf_pos); 498 ATF_TP_ADD_TC(tp, scalbn_ldexp); 499 ATF_TP_ADD_TC(tp, scalbn_zero_neg); 500 ATF_TP_ADD_TC(tp, scalbn_zero_pos); 501 502 ATF_TP_ADD_TC(tp, scalbnf_val); 503 ATF_TP_ADD_TC(tp, scalbnf_nan); 504 ATF_TP_ADD_TC(tp, scalbnf_inf_neg); 505 ATF_TP_ADD_TC(tp, scalbnf_inf_pos); 506 ATF_TP_ADD_TC(tp, scalbnf_ldexpf); 507 ATF_TP_ADD_TC(tp, scalbnf_zero_neg); 508 ATF_TP_ADD_TC(tp, scalbnf_zero_pos); 509 510 ATF_TP_ADD_TC(tp, scalbnl_val); 511 ATF_TP_ADD_TC(tp, scalbnl_nan); 512 ATF_TP_ADD_TC(tp, scalbnl_inf_neg); 513 ATF_TP_ADD_TC(tp, scalbnl_inf_pos); 514/* ATF_TP_ADD_TC(tp, scalbnl_ldexp); */ 515 ATF_TP_ADD_TC(tp, scalbnl_zero_neg); 516 ATF_TP_ADD_TC(tp, scalbnl_zero_pos); 517 518 return atf_no_error(); 519} 520