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 trig") 24 { 25 real r0{0}; 26 r0.sin(); 27 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 28 REQUIRE(r0.zero_p()); 29 real rop; 30 REQUIRE(sin(rop, r0).zero_p()); 31 REQUIRE(rop.get_prec() == detail::real_deduce_precision(0)); 32 REQUIRE(sin(r0).zero_p()); 33 REQUIRE(sin(std::move(r0)).zero_p()); 34 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 35 REQUIRE(!r0.get_mpfr_t()->_mpfr_d); 36 37 r0 = real{0}; 38 r0.cos(); 39 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 40 REQUIRE(r0 == 1); 41 rop = real{}; 42 r0 = real{0}; 43 REQUIRE(cos(rop, r0) == 1); 44 REQUIRE(rop.get_prec() == detail::real_deduce_precision(0)); 45 REQUIRE(cos(r0) == 1); 46 REQUIRE(cos(std::move(r0)) == 1); 47 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 48 REQUIRE(!r0.get_mpfr_t()->_mpfr_d); 49 50 r0 = real{0}; 51 r0.tan(); 52 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 53 REQUIRE(r0 == 0); 54 rop = real{1}; 55 r0 = real{0}; 56 REQUIRE(tan(rop, r0) == 0); 57 REQUIRE(rop.get_prec() == detail::real_deduce_precision(0)); 58 REQUIRE(tan(r0) == 0); 59 REQUIRE(tan(std::move(r0)) == 0); 60 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 61 REQUIRE(!r0.get_mpfr_t()->_mpfr_d); 62 63 r0 = real{0}; 64 r0.sec(); 65 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 66 REQUIRE(r0 == 1); 67 r0 = real{0}; 68 rop = real{1}; 69 REQUIRE(sec(rop, r0) == 1); 70 REQUIRE(rop.get_prec() == detail::real_deduce_precision(0)); 71 REQUIRE(sec(r0) == 1); 72 REQUIRE(sec(std::move(r0)) == 1); 73 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 74 REQUIRE(!r0.get_mpfr_t()->_mpfr_d); 75 76 r0 = real{0}; 77 r0.csc(); 78 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 79 REQUIRE(r0.inf_p()); 80 r0 = real{0}; 81 rop = real{1}; 82 REQUIRE(csc(rop, r0).inf_p()); 83 REQUIRE(rop.get_prec() == detail::real_deduce_precision(0)); 84 REQUIRE(csc(r0).inf_p()); 85 REQUIRE(csc(std::move(r0)).inf_p()); 86 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 87 REQUIRE(!r0.get_mpfr_t()->_mpfr_d); 88 89 r0 = real{0}; 90 r0.cot(); 91 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 92 REQUIRE(r0.inf_p()); 93 r0 = real{0}; 94 rop = real{1}; 95 REQUIRE(cot(rop, r0).inf_p()); 96 REQUIRE(rop.get_prec() == detail::real_deduce_precision(0)); 97 REQUIRE(cot(r0).inf_p()); 98 REQUIRE(cot(std::move(r0)).inf_p()); 99 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 100 REQUIRE(!r0.get_mpfr_t()->_mpfr_d); 101 102 r0 = real{0}; 103 r0.asin(); 104 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 105 REQUIRE(r0 == 0); 106 rop = real{1}; 107 r0 = real{0}; 108 REQUIRE(asin(rop, r0) == 0); 109 REQUIRE(rop.get_prec() == detail::real_deduce_precision(0)); 110 REQUIRE(asin(r0) == 0); 111 REQUIRE(asin(std::move(r0)) == 0); 112 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 113 REQUIRE(!r0.get_mpfr_t()->_mpfr_d); 114 115 r0 = real{0}; 116 r0.acos(); 117 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 118 REQUIRE(r0 == real_pi(r0.get_prec()) / 2); 119 rop = real{1}; 120 r0 = real{0}; 121 REQUIRE(acos(rop, r0) == real_pi(r0.get_prec()) / 2); 122 REQUIRE(rop.get_prec() == detail::real_deduce_precision(0)); 123 REQUIRE(acos(r0) == real_pi(r0.get_prec()) / 2); 124 auto p_cmp = r0.get_prec(); 125 REQUIRE(acos(std::move(r0)) == real_pi(p_cmp) / 2); 126 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 127 REQUIRE(!r0.get_mpfr_t()->_mpfr_d); 128 129 r0 = real{1}; 130 r0.atan(); 131 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 132 REQUIRE(r0 == real_pi(r0.get_prec()) / 4); 133 rop = real{2}; 134 r0 = real{1}; 135 REQUIRE(atan(rop, r0) == real_pi(r0.get_prec()) / 4); 136 REQUIRE(rop.get_prec() == detail::real_deduce_precision(0)); 137 REQUIRE(atan(r0) == real_pi(r0.get_prec()) / 4); 138 p_cmp = r0.get_prec(); 139 REQUIRE(atan(std::move(r0)) == real_pi(p_cmp) / 4); 140 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 141 REQUIRE(!r0.get_mpfr_t()->_mpfr_d); 142 143 // sin_cos. 144 real sop{1, detail::real_deduce_precision(0) * 2}, cop{2, detail::real_deduce_precision(0) * 3}; 145 REQUIRE(sop.get_prec() != detail::real_deduce_precision(0)); 146 REQUIRE(cop.get_prec() != detail::real_deduce_precision(0)); 147 sin_cos(sop, cop, real{32}); 148 REQUIRE(sop.get_prec() == detail::real_deduce_precision(0)); 149 REQUIRE(cop.get_prec() == detail::real_deduce_precision(0)); 150 REQUIRE(sop == sin(real{32})); 151 REQUIRE(cop == cos(real{32})); 152 __anone7d30ac70102(const std::invalid_argument &ex) 153 REQUIRE_THROWS_PREDICATE(sin_cos(sop, sop, real{32}), std::invalid_argument, [](const std::invalid_argument &ex) { 154 return ex.what() 155 == std::string{ 156 "In the real sin_cos() function, the return values 'sop' and 'cop' must be distinct objects"}; 157 }); 158 159 // Try with overlapping op/sop and op/cop. 160 sop = real{1, detail::real_deduce_precision(0) * 2}; 161 cop = real{2, detail::real_deduce_precision(0) * 3}; 162 sin_cos(sop, cop, sop); 163 REQUIRE(sop.get_prec() == detail::real_deduce_precision(0) * 2); 164 REQUIRE(cop.get_prec() == detail::real_deduce_precision(0) * 2); 165 REQUIRE(sop == sin(real{1, detail::real_deduce_precision(0) * 2})); 166 REQUIRE(cop == cos(real{1, detail::real_deduce_precision(0) * 2})); 167 168 sop = real{1, detail::real_deduce_precision(0) * 2}; 169 cop = real{2, detail::real_deduce_precision(0) * 3}; 170 sin_cos(sop, cop, cop); 171 REQUIRE(sop.get_prec() == detail::real_deduce_precision(0) * 3); 172 REQUIRE(cop.get_prec() == detail::real_deduce_precision(0) * 3); 173 REQUIRE(sop == sin(real{2, detail::real_deduce_precision(0) * 3})); 174 REQUIRE(cop == cos(real{2, detail::real_deduce_precision(0) * 3})); 175 176 // atan2. 177 r0 = real{12, 450}; 178 atan2(r0, real{4}, real{5}); 179 REQUIRE(r0 == atan(real{4} / real{5})); 180 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 181 real tmp1{4}, tmp2{5}; 182 r0 = real{12, detail::real_deduce_precision(0) / 2}; 183 atan2(r0, std::move(tmp1), tmp2); 184 REQUIRE(r0 == atan(real{4} / real{5})); 185 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 186 // Check tmp1 was swapped for r0. 187 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 188 REQUIRE(tmp1 == real{12, detail::real_deduce_precision(0) / 2}); 189 REQUIRE(tmp1.get_prec() == detail::real_deduce_precision(0) / 2); 190 tmp1 = real{4}; 191 tmp2 = real{5}; 192 r0 = real{12, detail::real_deduce_precision(0) / 2}; 193 atan2(r0, tmp1, std::move(tmp2)); 194 REQUIRE(r0 == atan(real{4} / real{5})); 195 REQUIRE(r0.get_prec() == detail::real_deduce_precision(0)); 196 // Check tmp2 was swapped for r0. 197 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 198 REQUIRE(tmp2 == real{12, detail::real_deduce_precision(0) / 2}); 199 REQUIRE(tmp2.get_prec() == detail::real_deduce_precision(0) / 2); 200 201 // Some tests for the binary form too. 202 REQUIRE(atan2(real{4}, real{5}) == atan(real{4} / real{5})); 203 REQUIRE(atan2(real{4, 20}, real{5, 30}).get_prec() == 30); 204 REQUIRE(atan2(real{4}, 5.) == atan2(real{4}, real{5.})); 205 REQUIRE(atan2(5., real{4}) == atan2(real{5.}, real{4})); 206 REQUIRE(atan2(real{4}, 5) == atan2(real{4}, real{5})); 207 REQUIRE(atan2(5, real{4}) == atan2(real{5}, real{4})); 208 REQUIRE(atan2(real{4}, -5.) == atan2(real{4}, real{-5.})); 209 REQUIRE(atan2(-5., real{4}) == atan2(real{-5.}, real{4})); 210 REQUIRE(atan2(real{4}, -5) == atan2(real{4}, real{-5})); 211 REQUIRE(atan2(-5, real{4}) == atan2(real{-5}, real{4})); 212 REQUIRE(atan2(real{4}, integer<1>{-5}) == atan2(real{4}, real{integer<1>{-5}})); 213 REQUIRE(atan2(integer<1>{-5}, real{4}) == atan2(real{integer<1>{-5}}, real{4})); 214 REQUIRE(atan2(real{4, detail::real_deduce_precision(0.) / 2}, 5.).get_prec() == detail::real_deduce_precision(0.)); 215 REQUIRE(atan2(4., real{5, detail::real_deduce_precision(0.) / 2}).get_prec() == detail::real_deduce_precision(0.)); 216 REQUIRE(atan2(real{4, detail::real_deduce_precision(0) / 2}, 5).get_prec() == detail::real_deduce_precision(0)); 217 REQUIRE(atan2(4, real{5, detail::real_deduce_precision(0) / 2}).get_prec() == detail::real_deduce_precision(0)); 218 } 219 220 #if defined(MPPP_WITH_ARB) 221 222 // NOLINTNEXTLINE(google-readability-function-size, hicpp-function-size, readability-function-size) 223 TEST_CASE("real trig arb") 224 { 225 { 226 auto r0 = 1.23_r128; 227 r0.sin_pi(); 228 REQUIRE(r0.get_prec() == 128); 229 REQUIRE(abs(r0 - sin(real_pi(128) * 1.23_r128)) < mppp::pow(2_r128, -126)); 230 real rop{2, 12}; 231 r0 = 1.23_r128; 232 sin_pi(rop, r0); 233 REQUIRE(rop.get_prec() == 128); 234 REQUIRE(abs(rop - sin(real_pi(128) * 1.23_r128)) < mppp::pow(2_r128, -126)); 235 REQUIRE(sin_pi(std::move(r0)) == rop); 236 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 237 REQUIRE(!r0.is_valid()); 238 239 REQUIRE(sin_pi(real{"inf", 128}).nan_p()); 240 REQUIRE(sin_pi(real{"inf", 128}).get_prec() == 128); 241 REQUIRE(sin_pi(-real{"inf", 128}).nan_p()); 242 REQUIRE(sin_pi(-real{"inf", 128}).get_prec() == 128); 243 REQUIRE(sin_pi(real{"nan", 128}).nan_p()); 244 REQUIRE(sin_pi(real{"nan", 128}).get_prec() == 128); 245 } 246 247 { 248 auto r0 = 1.23_r128; 249 r0.cos_pi(); 250 REQUIRE(r0.get_prec() == 128); 251 REQUIRE(abs(r0 - cos(real_pi(128) * 1.23_r128)) < mppp::pow(2_r128, -126)); 252 real rop{2, 12}; 253 r0 = 1.23_r128; 254 cos_pi(rop, r0); 255 REQUIRE(rop.get_prec() == 128); 256 REQUIRE(abs(rop - cos(real_pi(128) * 1.23_r128)) < mppp::pow(2_r128, -126)); 257 REQUIRE(cos_pi(std::move(r0)) == rop); 258 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 259 REQUIRE(!r0.is_valid()); 260 261 REQUIRE(cos_pi(real{"inf", 128}).nan_p()); 262 REQUIRE(cos_pi(real{"inf", 128}).get_prec() == 128); 263 REQUIRE(cos_pi(-real{"inf", 128}).nan_p()); 264 REQUIRE(cos_pi(-real{"inf", 128}).get_prec() == 128); 265 REQUIRE(cos_pi(real{"nan", 128}).nan_p()); 266 REQUIRE(cos_pi(real{"nan", 128}).get_prec() == 128); 267 } 268 269 { 270 auto r0 = 1.23_r128; 271 r0.tan_pi(); 272 REQUIRE(r0.get_prec() == 128); 273 REQUIRE(abs(r0 - tan(real_pi(128) * 1.23_r128)) < mppp::pow(2_r128, -126)); 274 real rop{2, 12}; 275 r0 = 1.23_r128; 276 tan_pi(rop, r0); 277 REQUIRE(rop.get_prec() == 128); 278 REQUIRE(abs(rop - tan(real_pi(128) * 1.23_r128)) < mppp::pow(2_r128, -126)); 279 REQUIRE(tan_pi(std::move(r0)) == rop); 280 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 281 REQUIRE(!r0.is_valid()); 282 283 REQUIRE(tan_pi(real{"inf", 128}).nan_p()); 284 REQUIRE(tan_pi(real{"inf", 128}).get_prec() == 128); 285 REQUIRE(tan_pi(-real{"inf", 128}).nan_p()); 286 REQUIRE(tan_pi(-real{"inf", 128}).get_prec() == 128); 287 REQUIRE(tan_pi(real{"nan", 128}).nan_p()); 288 REQUIRE(tan_pi(real{"nan", 128}).get_prec() == 128); 289 290 // Special values. 291 REQUIRE(tan_pi(0_r128).zero_p()); 292 REQUIRE(tan_pi(0_r128).get_prec() == 128); 293 294 REQUIRE(tan_pi(0.5_r128).nan_p()); 295 REQUIRE(tan_pi(0.5_r128).get_prec() == 128); 296 297 REQUIRE(tan_pi(1.5_r128).nan_p()); 298 REQUIRE(tan_pi(1.5_r128).get_prec() == 128); 299 300 REQUIRE(tan_pi(2.5_r128).nan_p()); 301 REQUIRE(tan_pi(2.5_r128).get_prec() == 128); 302 303 REQUIRE(tan_pi(3.5_r128).nan_p()); 304 REQUIRE(tan_pi(3.5_r128).get_prec() == 128); 305 306 REQUIRE(tan_pi(650.5_r128).nan_p()); 307 REQUIRE(tan_pi(650.5_r128).get_prec() == 128); 308 309 REQUIRE(tan_pi(-0.5_r128).nan_p()); 310 REQUIRE(tan_pi(-0.5_r128).get_prec() == 128); 311 312 REQUIRE(tan_pi(-1.5_r128).nan_p()); 313 REQUIRE(tan_pi(-1.5_r128).get_prec() == 128); 314 315 REQUIRE(tan_pi(-2.5_r128).nan_p()); 316 REQUIRE(tan_pi(-2.5_r128).get_prec() == 128); 317 318 REQUIRE(tan_pi(-3.5_r128).nan_p()); 319 REQUIRE(tan_pi(-3.5_r128).get_prec() == 128); 320 321 REQUIRE(tan_pi(-650.5_r128).nan_p()); 322 REQUIRE(tan_pi(-650.5_r128).get_prec() == 128); 323 } 324 325 { 326 auto r0 = 1.23_r128; 327 r0.cot_pi(); 328 REQUIRE(r0.get_prec() == 128); 329 REQUIRE(abs(r0 - cot(real_pi(128) * 1.23_r128)) < mppp::pow(2_r128, -126)); 330 real rop{2, 12}; 331 r0 = 1.23_r128; 332 cot_pi(rop, r0); 333 REQUIRE(rop.get_prec() == 128); 334 REQUIRE(abs(rop - cot(real_pi(128) * 1.23_r128)) < mppp::pow(2_r128, -126)); 335 REQUIRE(cot_pi(std::move(r0)) == rop); 336 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 337 REQUIRE(!r0.is_valid()); 338 339 REQUIRE(cot_pi(real{"inf", 128}).nan_p()); 340 REQUIRE(cot_pi(real{"inf", 128}).get_prec() == 128); 341 REQUIRE(cot_pi(-real{"inf", 128}).nan_p()); 342 REQUIRE(cot_pi(-real{"inf", 128}).get_prec() == 128); 343 REQUIRE(cot_pi(real{"nan", 128}).nan_p()); 344 REQUIRE(cot_pi(real{"nan", 128}).get_prec() == 128); 345 346 // Special values. 347 REQUIRE(cot_pi(0_r128).nan_p()); 348 REQUIRE(cot_pi(0_r128).get_prec() == 128); 349 350 REQUIRE(cot_pi(1_r128).nan_p()); 351 REQUIRE(cot_pi(1_r128).get_prec() == 128); 352 353 REQUIRE(cot_pi(2._r128).nan_p()); 354 REQUIRE(cot_pi(2._r128).get_prec() == 128); 355 356 REQUIRE(cot_pi(3_r128).nan_p()); 357 REQUIRE(cot_pi(3_r128).get_prec() == 128); 358 359 REQUIRE(cot_pi(650_r128).nan_p()); 360 REQUIRE(cot_pi(650_r128).get_prec() == 128); 361 362 REQUIRE(cot_pi(-1_r128).nan_p()); 363 REQUIRE(cot_pi(-1_r128).get_prec() == 128); 364 365 REQUIRE(cot_pi(-2._r128).nan_p()); 366 REQUIRE(cot_pi(-2._r128).get_prec() == 128); 367 368 REQUIRE(cot_pi(-3_r128).nan_p()); 369 REQUIRE(cot_pi(-3_r128).get_prec() == 128); 370 371 REQUIRE(cot_pi(-650_r128).nan_p()); 372 REQUIRE(cot_pi(-650_r128).get_prec() == 128); 373 } 374 375 { 376 auto r0 = 1.23_r128; 377 r0.sinc(); 378 REQUIRE(r0.get_prec() == 128); 379 REQUIRE(abs(r0 - sin(1.23_r128) / 1.23_r128) < mppp::pow(2_r128, -126)); 380 real rop{2, 12}; 381 r0 = 1.23_r128; 382 sinc(rop, r0); 383 REQUIRE(rop.get_prec() == 128); 384 REQUIRE(abs(rop - sin(1.23_r128) / 1.23_r128) < mppp::pow(2_r128, -126)); 385 REQUIRE(sinc(std::move(r0)) == rop); 386 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 387 REQUIRE(!r0.is_valid()); 388 389 REQUIRE(sinc(real{"inf", 128}).zero_p()); 390 REQUIRE(sinc(real{"inf", 128}).get_prec() == 128); 391 REQUIRE(sinc(-real{"inf", 128}).zero_p()); 392 REQUIRE(sinc(-real{"inf", 128}).get_prec() == 128); 393 REQUIRE(sinc(real{"nan", 128}).nan_p()); 394 REQUIRE(sinc(real{"nan", 128}).get_prec() == 128); 395 REQUIRE(sinc(real{0, 128}) == 1); 396 REQUIRE(sinc(real{0, 128}).get_prec() == 128); 397 } 398 399 { 400 auto r0 = 1.23_r128; 401 r0.sinc_pi(); 402 REQUIRE(r0.get_prec() == 128); 403 REQUIRE(abs(r0 - sin(real_pi(128) * 1.23_r128) / (real_pi(128) * 1.23_r128)) < mppp::pow(2_r128, -126)); 404 real rop{2, 12}; 405 r0 = 1.23_r128; 406 sinc_pi(rop, r0); 407 REQUIRE(rop.get_prec() == 128); 408 REQUIRE(abs(rop - sin(real_pi(128) * 1.23_r128) / (real_pi(128) * 1.23_r128)) < mppp::pow(2_r128, -126)); 409 REQUIRE(sinc_pi(std::move(r0)) == rop); 410 // NOLINTNEXTLINE(bugprone-use-after-move, clang-analyzer-cplusplus.Move, hicpp-invalid-access-moved) 411 REQUIRE(!r0.is_valid()); 412 413 REQUIRE(sinc_pi(real{"inf", 128}).zero_p()); 414 REQUIRE(sinc_pi(real{"inf", 128}).get_prec() == 128); 415 REQUIRE(sinc_pi(-real{"inf", 128}).zero_p()); 416 REQUIRE(sinc_pi(-real{"inf", 128}).get_prec() == 128); 417 REQUIRE(sinc_pi(real{"nan", 128}).nan_p()); 418 REQUIRE(sinc_pi(real{"nan", 128}).get_prec() == 128); 419 REQUIRE(sinc_pi(real{0, 128}) == 1); 420 REQUIRE(sinc_pi(real{0, 128}).get_prec() == 128); 421 } 422 } 423 424 #endif 425