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