1 // Copyright 2016-2021 Francesco Biscani (bluescarni@gmail.com) 2 // 3 // This file is part of the mp++ library. 4 // 5 // This Source Code Form is subject to the terms of the Mozilla 6 // Public License v. 2.0. If a copy of the MPL was not distributed 7 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 9 #include <stdexcept> 10 #include <string> 11 #include <utility> 12 13 #include <mp++/config.hpp> 14 #include <mp++/integer.hpp> 15 #include <mp++/real.hpp> 16 17 #include "catch.hpp" 18 #include "test_utils.hpp" 19 20 // NOLINTNEXTLINE(google-build-using-namespace) 21 using namespace mppp; 22 23 TEST_CASE("real integer_p") 24 { 25 real r0{0}; 26 REQUIRE(r0.integer_p()); 27 REQUIRE(integer_p(r0)); 28 r0 = .1; 29 REQUIRE(!r0.integer_p()); 30 REQUIRE(!integer_p(r0)); 31 r0 = -.1; 32 REQUIRE(!r0.integer_p()); 33 REQUIRE(!integer_p(r0)); 34 r0 = 1; 35 REQUIRE(r0.integer_p()); 36 REQUIRE(integer_p(r0)); 37 r0 = -1; 38 REQUIRE(r0.integer_p()); 39 REQUIRE(integer_p(r0)); 40 r0 = 12345; 41 REQUIRE(r0.integer_p()); 42 REQUIRE(integer_p(r0)); 43 r0 = real{"inf", 128}; 44 REQUIRE(!r0.integer_p()); 45 REQUIRE(!integer_p(r0)); 46 r0 = -real{"inf", 128}; 47 REQUIRE(!r0.integer_p()); 48 REQUIRE(!integer_p(r0)); 49 r0 = real{"nan", 128}; 50 REQUIRE(!r0.integer_p()); 51 REQUIRE(!integer_p(r0)); 52 } 53 54 TEST_CASE("real trunc") 55 { 56 real r0{0}; 57 REQUIRE(r0.trunc() == 0); 58 r0 = 0.1; 59 REQUIRE(r0.trunc() == 0); 60 r0 = -0.1; 61 REQUIRE(r0.trunc() == 0); 62 r0 = 1.001; 63 REQUIRE(r0.trunc() == 1); 64 r0 = -1.001; 65 REQUIRE(r0.trunc() == -1); 66 r0 = 1.999; 67 REQUIRE(r0.trunc() == 1); 68 r0 = -1.9999; 69 REQUIRE(r0.trunc() == -1); 70 // The binary function. 71 real tmp{45.67, 50}; 72 r0.set_prec(4); 73 // NOLINTNEXTLINE(llvm-qualified-auto, readability-qualified-auto) 74 auto tmp_ptr = r0.get_mpfr_t()->_mpfr_d; 75 trunc(r0, std::move(tmp)); 76 REQUIRE(r0 == 45); 77 REQUIRE(get_prec(r0) == 50); 78 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 79 REQUIRE(tmp.get_mpfr_t()->_mpfr_d == tmp_ptr); 80 r0.set_prec(4); 81 tmp = real{-49.99, 50}; 82 trunc(r0, real{-49.99, 50}); 83 REQUIRE(r0 == -49); 84 REQUIRE(get_prec(r0) == 50); 85 // The unary function. 86 r0.set_prec(4); 87 tmp = real{45.67, 50}; 88 r0 = trunc(std::move(tmp)); 89 REQUIRE(r0 == 45); 90 REQUIRE(get_prec(r0) == 50); 91 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 92 REQUIRE(tmp.get_mpfr_t()->_mpfr_d == nullptr); 93 tmp = real{45.67, 50}; 94 r0 = trunc(tmp); 95 REQUIRE(r0 == 45); 96 REQUIRE(get_prec(r0) == 50); 97 r0.set_prec(4); 98 r0 = trunc(real{-49.99, 50}); 99 REQUIRE(r0 == -49); 100 REQUIRE(get_prec(r0) == 50); 101 // Failure modes. 102 r0.set_nan(); __anon20cbf0400102(const std::domain_error &ex) 103 REQUIRE_THROWS_PREDICATE(r0.trunc(), std::domain_error, [](const std::domain_error &ex) { 104 return ex.what() == std::string{"Cannot truncate a NaN value"}; 105 }); __anon20cbf0400202(const std::domain_error &ex) 106 REQUIRE_THROWS_PREDICATE(trunc(r0, real{"nan", 12}), std::domain_error, [](const std::domain_error &ex) { 107 return ex.what() == std::string{"Cannot truncate a NaN value"}; 108 }); __anon20cbf0400302(const std::domain_error &ex) 109 REQUIRE_THROWS_PREDICATE(trunc(real{"nan", 12}), std::domain_error, [](const std::domain_error &ex) { 110 return ex.what() == std::string{"Cannot truncate a NaN value"}; 111 }); 112 } 113 114 TEST_CASE("real ceil") 115 { 116 real r0{0}; 117 REQUIRE(r0.ceil() == 0); 118 r0 = 0.1; 119 REQUIRE(r0.ceil() == 1); 120 r0 = -0.1; 121 REQUIRE(r0.ceil() == 0); 122 r0 = 1.001; 123 REQUIRE(r0.ceil() == 2); 124 r0 = -1.001; 125 REQUIRE(r0.ceil() == -1); 126 r0 = 1.999; 127 REQUIRE(r0.ceil() == 2); 128 r0 = -1.9999; 129 REQUIRE(r0.ceil() == -1); 130 // The binary function. 131 real tmp{45.67, 50}; 132 r0.set_prec(4); 133 // NOLINTNEXTLINE(llvm-qualified-auto, readability-qualified-auto) 134 auto tmp_ptr = r0.get_mpfr_t()->_mpfr_d; 135 ceil(r0, std::move(tmp)); 136 REQUIRE(r0 == 46); 137 REQUIRE(get_prec(r0) == 50); 138 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 139 REQUIRE(tmp.get_mpfr_t()->_mpfr_d == tmp_ptr); 140 r0.set_prec(4); 141 tmp = real{-49.99, 50}; 142 ceil(r0, real{-49.99, 50}); 143 REQUIRE(r0 == -49); 144 REQUIRE(get_prec(r0) == 50); 145 // The unary function. 146 r0.set_prec(4); 147 tmp = real{45.67, 50}; 148 r0 = ceil(std::move(tmp)); 149 REQUIRE(r0 == 46); 150 REQUIRE(get_prec(r0) == 50); 151 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 152 REQUIRE(tmp.get_mpfr_t()->_mpfr_d == nullptr); 153 tmp = real{45.67, 50}; 154 r0 = ceil(tmp); 155 REQUIRE(r0 == 46); 156 REQUIRE(get_prec(r0) == 50); 157 r0.set_prec(4); 158 r0 = ceil(real{-49.99, 50}); 159 REQUIRE(r0 == -49); 160 REQUIRE(get_prec(r0) == 50); 161 // Failure modes. 162 r0.set_nan(); __anon20cbf0400402(const std::domain_error &ex) 163 REQUIRE_THROWS_PREDICATE(r0.ceil(), std::domain_error, [](const std::domain_error &ex) { 164 return ex.what() == std::string{"Cannot compute the ceiling of a NaN value"}; 165 }); __anon20cbf0400502(const std::domain_error &ex) 166 REQUIRE_THROWS_PREDICATE(ceil(r0, real{"nan", 12}), std::domain_error, [](const std::domain_error &ex) { 167 return ex.what() == std::string{"Cannot compute the ceiling of a NaN value"}; 168 }); __anon20cbf0400602(const std::domain_error &ex) 169 REQUIRE_THROWS_PREDICATE(ceil(real{"nan", 12}), std::domain_error, [](const std::domain_error &ex) { 170 return ex.what() == std::string{"Cannot compute the ceiling of a NaN value"}; 171 }); 172 } 173 174 TEST_CASE("real floor") 175 { 176 real r0{0}; 177 REQUIRE(r0.floor() == 0); 178 r0 = 0.1; 179 REQUIRE(r0.floor() == 0); 180 r0 = -0.1; 181 REQUIRE(r0.floor() == -1); 182 r0 = 1.001; 183 REQUIRE(r0.floor() == 1); 184 r0 = -1.001; 185 REQUIRE(r0.floor() == -2); 186 r0 = 1.999; 187 REQUIRE(r0.floor() == 1); 188 r0 = -1.9999; 189 REQUIRE(r0.floor() == -2); 190 // The binary function. 191 real tmp{45.67, 50}; 192 r0.set_prec(4); 193 // NOLINTNEXTLINE(llvm-qualified-auto, readability-qualified-auto) 194 auto tmp_ptr = r0.get_mpfr_t()->_mpfr_d; 195 floor(r0, std::move(tmp)); 196 REQUIRE(r0 == 45); 197 REQUIRE(get_prec(r0) == 50); 198 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 199 REQUIRE(tmp.get_mpfr_t()->_mpfr_d == tmp_ptr); 200 r0.set_prec(4); 201 tmp = real{-49.99, 50}; 202 floor(r0, real{-49.99, 50}); 203 REQUIRE(r0 == -50); 204 REQUIRE(get_prec(r0) == 50); 205 // The unary function. 206 r0.set_prec(4); 207 tmp = real{45.67, 50}; 208 r0 = floor(std::move(tmp)); 209 REQUIRE(r0 == 45); 210 REQUIRE(get_prec(r0) == 50); 211 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 212 REQUIRE(tmp.get_mpfr_t()->_mpfr_d == nullptr); 213 tmp = real{45.67, 50}; 214 r0 = floor(tmp); 215 REQUIRE(r0 == 45); 216 REQUIRE(get_prec(r0) == 50); 217 r0.set_prec(4); 218 r0 = floor(real{-49.99, 50}); 219 REQUIRE(r0 == -50); 220 REQUIRE(get_prec(r0) == 50); 221 // Failure modes. 222 r0.set_nan(); __anon20cbf0400702(const std::domain_error &ex) 223 REQUIRE_THROWS_PREDICATE(r0.floor(), std::domain_error, [](const std::domain_error &ex) { 224 return ex.what() == std::string{"Cannot compute the floor of a NaN value"}; 225 }); __anon20cbf0400802(const std::domain_error &ex) 226 REQUIRE_THROWS_PREDICATE(floor(r0, real{"nan", 12}), std::domain_error, [](const std::domain_error &ex) { 227 return ex.what() == std::string{"Cannot compute the floor of a NaN value"}; 228 }); __anon20cbf0400902(const std::domain_error &ex) 229 REQUIRE_THROWS_PREDICATE(floor(real{"nan", 12}), std::domain_error, [](const std::domain_error &ex) { 230 return ex.what() == std::string{"Cannot compute the floor of a NaN value"}; 231 }); 232 } 233 234 TEST_CASE("real round") 235 { 236 real r0{0}; 237 REQUIRE(r0.round() == 0); 238 r0 = 0.1; 239 REQUIRE(r0.round() == 0); 240 r0 = -0.1; 241 REQUIRE(r0.round() == 0); 242 r0 = 1.001; 243 REQUIRE(r0.round() == 1); 244 r0 = -1.001; 245 REQUIRE(r0.round() == -1); 246 r0 = 1.999; 247 REQUIRE(r0.round() == 2); 248 r0 = -1.9999; 249 REQUIRE(r0.round() == -2); 250 r0 = real{"1.5", 20}; 251 REQUIRE(r0.round() == 2); 252 r0 = real{"-1.5", 20}; 253 REQUIRE(r0.round() == -2); 254 r0 = real{"2.5", 20}; 255 REQUIRE(r0.round() == 3); 256 r0 = real{"-2.5", 20}; 257 REQUIRE(r0.round() == -3); 258 // The binary function. 259 real tmp{45.67, 50}; 260 r0.set_prec(4); 261 // NOLINTNEXTLINE(llvm-qualified-auto, readability-qualified-auto) 262 auto tmp_ptr = r0.get_mpfr_t()->_mpfr_d; 263 round(r0, std::move(tmp)); 264 REQUIRE(r0 == 46); 265 REQUIRE(get_prec(r0) == 50); 266 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 267 REQUIRE(tmp.get_mpfr_t()->_mpfr_d == tmp_ptr); 268 r0.set_prec(4); 269 tmp = real{-49.99, 50}; 270 round(r0, real{-49.99, 50}); 271 REQUIRE(r0 == -50); 272 REQUIRE(get_prec(r0) == 50); 273 // The unary function. 274 r0.set_prec(4); 275 tmp = real{45.67, 50}; 276 r0 = round(std::move(tmp)); 277 REQUIRE(r0 == 46); 278 REQUIRE(get_prec(r0) == 50); 279 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 280 REQUIRE(tmp.get_mpfr_t()->_mpfr_d == nullptr); 281 tmp = real{45.67, 50}; 282 r0 = round(tmp); 283 REQUIRE(r0 == 46); 284 REQUIRE(get_prec(r0) == 50); 285 r0.set_prec(4); 286 r0 = round(real{-49.99, 50}); 287 REQUIRE(r0 == -50); 288 REQUIRE(get_prec(r0) == 50); 289 // Failure modes. 290 r0.set_nan(); __anon20cbf0400a02(const std::domain_error &ex) 291 REQUIRE_THROWS_PREDICATE(r0.round(), std::domain_error, [](const std::domain_error &ex) { 292 return ex.what() == std::string{"Cannot round a NaN value"}; 293 }); __anon20cbf0400b02(const std::domain_error &ex) 294 REQUIRE_THROWS_PREDICATE(round(r0, real{"nan", 12}), std::domain_error, [](const std::domain_error &ex) { 295 return ex.what() == std::string{"Cannot round a NaN value"}; 296 }); __anon20cbf0400c02(const std::domain_error &ex) 297 REQUIRE_THROWS_PREDICATE(round(real{"nan", 12}), std::domain_error, [](const std::domain_error &ex) { 298 return ex.what() == std::string{"Cannot round a NaN value"}; 299 }); 300 301 // Couple of extra tests for the free functions. 302 REQUIRE(round(real{"1.5", 20}) == 2); 303 REQUIRE(round(real{"-1.5", 20}) == -2); 304 REQUIRE(round(real{"2.5", 20}) == 3); 305 REQUIRE(round(real{"-2.5", 20}) == -3); 306 } 307 308 #if defined(MPPP_MPFR_HAVE_MPFR_ROUNDEVEN) 309 310 TEST_CASE("real roundeven") 311 { 312 real r0{0}; 313 REQUIRE(r0.roundeven() == 0); 314 r0 = 0.1; 315 REQUIRE(r0.roundeven() == 0); 316 r0 = -0.1; 317 REQUIRE(r0.roundeven() == 0); 318 r0 = 1.001; 319 REQUIRE(r0.roundeven() == 1); 320 r0 = -1.001; 321 REQUIRE(r0.roundeven() == -1); 322 r0 = 1.999; 323 REQUIRE(r0.roundeven() == 2); 324 r0 = -1.9999; 325 REQUIRE(r0.roundeven() == -2); 326 r0 = real{"1.5", 20}; 327 REQUIRE(r0.roundeven() == 2); 328 r0 = real{"-1.5", 20}; 329 REQUIRE(r0.roundeven() == -2); 330 r0 = real{"2.5", 20}; 331 REQUIRE(r0.roundeven() == 2); 332 r0 = real{"-2.5", 20}; 333 REQUIRE(r0.roundeven() == -2); 334 r0 = real{"3.5", 20}; 335 REQUIRE(r0.roundeven() == 4); 336 r0 = real{"-3.5", 20}; 337 REQUIRE(r0.roundeven() == -4); 338 // The binary function. 339 real tmp{45.67, 50}; 340 r0.set_prec(4); 341 // NOLINTNEXTLINE(llvm-qualified-auto, readability-qualified-auto) 342 auto tmp_ptr = r0.get_mpfr_t()->_mpfr_d; 343 roundeven(r0, std::move(tmp)); 344 REQUIRE(r0 == 46); 345 REQUIRE(get_prec(r0) == 50); 346 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 347 REQUIRE(tmp.get_mpfr_t()->_mpfr_d == tmp_ptr); 348 r0.set_prec(4); 349 tmp = real{-49.99, 50}; 350 roundeven(r0, real{-49.99, 50}); 351 REQUIRE(r0 == -50); 352 REQUIRE(get_prec(r0) == 50); 353 // The unary function. 354 r0.set_prec(4); 355 tmp = real{45.67, 50}; 356 r0 = roundeven(std::move(tmp)); 357 REQUIRE(r0 == 46); 358 REQUIRE(get_prec(r0) == 50); 359 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 360 REQUIRE(tmp.get_mpfr_t()->_mpfr_d == nullptr); 361 tmp = real{45.67, 50}; 362 r0 = roundeven(tmp); 363 REQUIRE(r0 == 46); 364 REQUIRE(get_prec(r0) == 50); 365 r0.set_prec(4); 366 r0 = roundeven(real{-49.99, 50}); 367 REQUIRE(r0 == -50); 368 REQUIRE(get_prec(r0) == 50); 369 // Failure modes. 370 r0.set_nan(); __anon20cbf0400d02(const std::domain_error &ex) 371 REQUIRE_THROWS_PREDICATE(r0.roundeven(), std::domain_error, [](const std::domain_error &ex) { 372 return ex.what() == std::string{"Cannot round a NaN value"}; 373 }); __anon20cbf0400e02(const std::domain_error &ex) 374 REQUIRE_THROWS_PREDICATE(roundeven(r0, real{"nan", 12}), std::domain_error, [](const std::domain_error &ex) { 375 return ex.what() == std::string{"Cannot round a NaN value"}; 376 }); __anon20cbf0400f02(const std::domain_error &ex) 377 REQUIRE_THROWS_PREDICATE(roundeven(real{"nan", 12}), std::domain_error, [](const std::domain_error &ex) { 378 return ex.what() == std::string{"Cannot round a NaN value"}; 379 }); 380 381 // Couple of extra tests for the free functions. 382 REQUIRE(roundeven(real{"1.5", 20}) == 2); 383 REQUIRE(roundeven(real{"-1.5", 20}) == -2); 384 REQUIRE(roundeven(real{"2.5", 20}) == 2); 385 REQUIRE(roundeven(real{"-2.5", 20}) == -2); 386 } 387 388 #endif 389 390 TEST_CASE("real frac") 391 { 392 real r0{0}; 393 REQUIRE(r0.frac() == 0); 394 r0 = 0.1; 395 REQUIRE(r0.frac() == 0.1); 396 r0 = -0.1; 397 REQUIRE(r0.frac() == -0.1); 398 r0 = 1.001; 399 REQUIRE(r0.frac() == 1.001 - 1); 400 r0 = -1.001; 401 REQUIRE(r0.frac() == -1.001 + 1); 402 r0 = 1.999; 403 REQUIRE(r0.frac() == 1.999 - 1.); 404 r0 = -1.999; 405 REQUIRE(r0.frac() == -1.999 + 1); 406 // The binary function. 407 real tmp{45.67, 50}; 408 r0.set_prec(4); 409 // NOLINTNEXTLINE(llvm-qualified-auto, readability-qualified-auto) 410 auto tmp_ptr = r0.get_mpfr_t()->_mpfr_d; 411 frac(r0, std::move(tmp)); 412 REQUIRE(r0 == real{45.67, 50} - real{45, 50}); 413 REQUIRE(get_prec(r0) == 50); 414 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 415 REQUIRE(tmp.get_mpfr_t()->_mpfr_d == tmp_ptr); 416 r0.set_prec(4); 417 tmp = real{-49.99, 50}; 418 frac(r0, real{-49.99, 50}); 419 REQUIRE(r0 == real{-49.99, 50} + real{49, 50}); 420 REQUIRE(get_prec(r0) == 50); 421 // The unary function. 422 r0.set_prec(4); 423 tmp = real{45.67, 50}; 424 r0 = frac(std::move(tmp)); 425 REQUIRE(r0 == real{45.67, 50} - real{45, 50}); 426 REQUIRE(get_prec(r0) == 50); 427 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 428 REQUIRE(tmp.get_mpfr_t()->_mpfr_d == nullptr); 429 tmp = real{45.67, 50}; 430 r0 = frac(tmp); 431 REQUIRE(r0 == real{45.67, 50} - real{45, 50}); 432 REQUIRE(get_prec(r0) == 50); 433 r0.set_prec(4); 434 r0 = frac(real{-49.99, 50}); 435 REQUIRE(r0 == real{-49.99, 50} + real{49, 50}); 436 REQUIRE(get_prec(r0) == 50); 437 // Failure modes. 438 r0.set_nan(); __anon20cbf0401002(const std::domain_error &ex) 439 REQUIRE_THROWS_PREDICATE(r0.frac(), std::domain_error, [](const std::domain_error &ex) { 440 return ex.what() == std::string{"Cannot compute the fractional part of a NaN value"}; 441 }); __anon20cbf0401102(const std::domain_error &ex) 442 REQUIRE_THROWS_PREDICATE(frac(r0, real{"nan", 12}), std::domain_error, [](const std::domain_error &ex) { 443 return ex.what() == std::string{"Cannot compute the fractional part of a NaN value"}; 444 }); __anon20cbf0401202(const std::domain_error &ex) 445 REQUIRE_THROWS_PREDICATE(frac(real{"nan", 12}), std::domain_error, [](const std::domain_error &ex) { 446 return ex.what() == std::string{"Cannot compute the fractional part of a NaN value"}; 447 }); 448 } 449 450 TEST_CASE("real modf") 451 { 452 real iop, fop; 453 modf(iop, fop, real{"1.25", 10}); 454 REQUIRE(iop == 1); 455 REQUIRE(iop.get_prec() == 10); 456 REQUIRE(fop == real{"0.25", 10}); 457 REQUIRE(fop.get_prec() == 10); 458 459 REQUIRE_THROWS_PREDICATE( __anon20cbf0401302(const std::invalid_argument &ex) 460 modf(iop, iop, real{"1.25", 10}), std::invalid_argument, [](const std::invalid_argument &ex) { 461 return ex.what() 462 == std::string{ 463 "In the real modf() function, the return values 'iop' and 'fop' must be distinct objects"}; 464 }); __anon20cbf0401402(const std::domain_error &ex) 465 REQUIRE_THROWS_PREDICATE(modf(iop, fop, real{"nan", 10}), std::domain_error, [](const std::domain_error &ex) { 466 return ex.what() == std::string{"In the real modf() function, the input argument cannot be NaN"}; 467 }); 468 469 // Try with overlapping op/sop and op/cop. 470 iop = real{1, detail::real_deduce_precision(0) * 2}; 471 fop = real{2, detail::real_deduce_precision(0) * 3}; 472 modf(iop, fop, iop); 473 REQUIRE(iop.get_prec() == detail::real_deduce_precision(0) * 2); 474 REQUIRE(fop.get_prec() == detail::real_deduce_precision(0) * 2); 475 REQUIRE(iop == 1); 476 REQUIRE(fop == 0); 477 478 iop = real{1, detail::real_deduce_precision(0) * 2}; 479 fop = real{2, detail::real_deduce_precision(0) * 3}; 480 modf(fop, iop, fop); 481 REQUIRE(fop.get_prec() == detail::real_deduce_precision(0) * 3); 482 REQUIRE(iop.get_prec() == detail::real_deduce_precision(0) * 3); 483 REQUIRE(fop == 2); 484 REQUIRE(iop == 0); 485 } 486 487 TEST_CASE("real fmod") 488 { 489 real r0{12, 450}; 490 fmod(r0, real{1}, sqrt(real{2})); 491 REQUIRE(abs(r0 - 1) < 1E-6); 492 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 493 real tmp1{1}, tmp2{sqrt(real{2})}; 494 r0 = real{12, detail::real_deduce_precision(0) / 2}; 495 fmod(r0, std::move(tmp1), tmp2); 496 REQUIRE(abs(r0 - 1) < 1E-6); 497 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 498 // Check tmp1 was swapped for r0. 499 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 500 REQUIRE(tmp1 == real{12, detail::real_deduce_precision(0) / 2}); 501 REQUIRE(tmp1.get_prec() == detail::real_deduce_precision(0) / 2); 502 tmp1 = real{1}; 503 tmp2 = real{sqrt(real{2})}; 504 r0 = real{12, detail::real_deduce_precision(0) / 2}; 505 fmod(r0, tmp1, std::move(tmp2)); 506 REQUIRE(abs(r0 - 1) < 1E-6); 507 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 508 // Check tmp2 was swapped for r0. 509 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 510 REQUIRE(tmp2 == real{12, detail::real_deduce_precision(0) / 2}); 511 REQUIRE(tmp2.get_prec() == detail::real_deduce_precision(0) / 2); 512 513 // Some tests for the binary form too. 514 REQUIRE(abs(fmod(real{1}, real{sqrt(real{2})}) - 1) < 1E-6); 515 REQUIRE(fmod(real{4, 20}, real{5, 30}).get_prec() == 30); 516 REQUIRE(fmod(real{4}, 5.) == fmod(real{4}, real{5.})); 517 REQUIRE(fmod(5., real{4}) == fmod(real{5.}, real{4})); 518 REQUIRE(fmod(real{4}, 5) == fmod(real{4}, real{5})); 519 REQUIRE(fmod(5, real{4}) == fmod(real{5}, real{4})); 520 REQUIRE(fmod(5., real{4}) == fmod(real{5.}, real{4})); 521 REQUIRE(fmod(5, real{4}) == fmod(real{5}, real{4})); 522 REQUIRE(fmod(real{4}, integer<1>{5}) == fmod(real{4}, real{integer<1>{5}})); 523 REQUIRE(fmod(integer<1>{5}, real{4}) == fmod(real{integer<1>{5}}, real{4})); 524 REQUIRE(fmod(real{4, detail::real_deduce_precision(0.) / 2}, 5.).get_prec() == detail::real_deduce_precision(0.)); 525 REQUIRE(fmod(4., real{5, detail::real_deduce_precision(0.) / 2}).get_prec() == detail::real_deduce_precision(0.)); 526 REQUIRE(fmod(real{4, detail::real_deduce_precision(0) / 2}, 5).get_prec() == detail::real_deduce_precision(0)); 527 REQUIRE(fmod(4, real{5, detail::real_deduce_precision(0) / 2}).get_prec() == detail::real_deduce_precision(0)); 528 } 529 530 TEST_CASE("real remainder") 531 { 532 real r0{12, 450}; 533 remainder(r0, real{1}, sqrt(real{2})); 534 REQUIRE(abs(r0 - -0.414213562384) < 1E-6); 535 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 536 real tmp1{1}, tmp2{sqrt(real{2})}; 537 r0 = real{12, detail::real_deduce_precision(0) / 2}; 538 remainder(r0, std::move(tmp1), tmp2); 539 REQUIRE(abs(r0 - -0.414213562384) < 1E-6); 540 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 541 // Check tmp1 was swapped for r0. 542 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 543 REQUIRE(tmp1 == real{12, detail::real_deduce_precision(0) / 2}); 544 REQUIRE(tmp1.get_prec() == detail::real_deduce_precision(0) / 2); 545 tmp1 = real{1}; 546 tmp2 = real{sqrt(real{2})}; 547 r0 = real{12, detail::real_deduce_precision(0) / 2}; 548 remainder(r0, tmp1, std::move(tmp2)); 549 REQUIRE(abs(r0 - -0.414213562384) < 1E-6); 550 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 551 // Check tmp2 was swapped for r0. 552 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 553 REQUIRE(tmp2 == real{12, detail::real_deduce_precision(0) / 2}); 554 REQUIRE(tmp2.get_prec() == detail::real_deduce_precision(0) / 2); 555 556 // Some tests for the binary form too. 557 REQUIRE(abs(remainder(real{1}, real{sqrt(real{2})}) - -0.414213562384) < 1E-6); 558 REQUIRE(remainder(real{4, 20}, real{5, 30}).get_prec() == 30); 559 REQUIRE(remainder(real{4}, 5.) == remainder(real{4}, real{5.})); 560 REQUIRE(remainder(5., real{4}) == remainder(real{5.}, real{4})); 561 REQUIRE(remainder(real{4}, 5) == remainder(real{4}, real{5})); 562 REQUIRE(remainder(5, real{4}) == remainder(real{5}, real{4})); 563 REQUIRE(remainder(5., real{4}) == remainder(real{5.}, real{4})); 564 REQUIRE(remainder(5, real{4}) == remainder(real{5}, real{4})); 565 REQUIRE(remainder(real{4}, integer<1>{5}) == remainder(real{4}, real{integer<1>{5}})); 566 REQUIRE(remainder(integer<1>{5}, real{4}) == remainder(real{integer<1>{5}}, real{4})); 567 REQUIRE(remainder(real{4, detail::real_deduce_precision(0.) / 2}, 5.).get_prec() 568 == detail::real_deduce_precision(0.)); 569 REQUIRE(remainder(4., real{5, detail::real_deduce_precision(0.) / 2}).get_prec() 570 == detail::real_deduce_precision(0.)); 571 REQUIRE(remainder(real{4, detail::real_deduce_precision(0) / 2}, 5).get_prec() == detail::real_deduce_precision(0)); 572 REQUIRE(remainder(4, real{5, detail::real_deduce_precision(0) / 2}).get_prec() == detail::real_deduce_precision(0)); 573 } 574 575 TEST_CASE("real remquo") 576 { 577 long q = 0; 578 579 real r0{12, 450}; 580 remquo(r0, &q, real{1}, sqrt(real{2})); 581 REQUIRE(abs(r0 - -0.414213562384) < 1E-6); 582 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 583 real tmp1{1}, tmp2{sqrt(real{2})}; 584 r0 = real{12, detail::real_deduce_precision(0) / 2}; 585 remquo(r0, &q, std::move(tmp1), tmp2); 586 REQUIRE(abs(r0 - -0.414213562384) < 1E-6); 587 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 588 // Check tmp1 was swapped for r0. 589 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 590 REQUIRE(tmp1 == real{12, detail::real_deduce_precision(0) / 2}); 591 REQUIRE(tmp1.get_prec() == detail::real_deduce_precision(0) / 2); 592 tmp1 = real{1}; 593 tmp2 = real{sqrt(real{2})}; 594 r0 = real{12, detail::real_deduce_precision(0) / 2}; 595 remquo(r0, &q, tmp1, std::move(tmp2)); 596 REQUIRE(abs(r0 - -0.414213562384) < 1E-6); 597 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 598 // Check tmp2 was swapped for r0. 599 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 600 REQUIRE(tmp2 == real{12, detail::real_deduce_precision(0) / 2}); 601 REQUIRE(tmp2.get_prec() == detail::real_deduce_precision(0) / 2); 602 } 603 604 #if defined(MPPP_MPFR_HAVE_MPFR_FMODQUO) 605 606 TEST_CASE("real fmodquo") 607 { 608 long q = 0; 609 610 real r0{12, 450}; 611 fmodquo(r0, &q, real{1}, sqrt(real{2})); 612 REQUIRE(abs(r0 - 1) < 1E-6); 613 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 614 real tmp1{1}, tmp2{sqrt(real{2})}; 615 r0 = real{12, detail::real_deduce_precision(0) / 2}; 616 fmodquo(r0, &q, std::move(tmp1), tmp2); 617 REQUIRE(abs(r0 - 1) < 1E-6); 618 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 619 // Check tmp1 was swapped for r0. 620 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 621 REQUIRE(tmp1 == real{12, detail::real_deduce_precision(0) / 2}); 622 REQUIRE(tmp1.get_prec() == detail::real_deduce_precision(0) / 2); 623 tmp1 = real{1}; 624 tmp2 = real{sqrt(real{2})}; 625 r0 = real{12, detail::real_deduce_precision(0) / 2}; 626 fmodquo(r0, &q, tmp1, std::move(tmp2)); 627 REQUIRE(abs(r0 - 1) < 1E-6); 628 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 629 // Check tmp2 was swapped for r0. 630 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 631 REQUIRE(tmp2 == real{12, detail::real_deduce_precision(0) / 2}); 632 REQUIRE(tmp2.get_prec() == detail::real_deduce_precision(0) / 2); 633 } 634 635 #endif 636