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