]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
1 | /* |
2 | * Copyright Nick Thompson, 2020 | |
3 | * Use, modification and distribution are subject to the | |
4 | * Boost Software License, Version 1.0. (See accompanying file | |
5 | * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | */ | |
7 | ||
8 | #include "math_unit_test.hpp" | |
9 | #include <boost/math/tools/simple_continued_fraction.hpp> | |
10 | #include <boost/math/constants/constants.hpp> | |
1e59de90 | 11 | #include <boost/core/demangle.hpp> |
20effc67 TL |
12 | #ifdef BOOST_HAS_FLOAT128 |
13 | #include <boost/multiprecision/float128.hpp> | |
14 | using boost::multiprecision::float128; | |
15 | #endif | |
16 | #include <boost/multiprecision/cpp_bin_float.hpp> | |
17 | ||
18 | using boost::math::tools::simple_continued_fraction; | |
19 | using boost::multiprecision::cpp_bin_float_100; | |
20 | using boost::math::constants::pi; | |
21 | ||
22 | template<class Real> | |
23 | void test_integral() | |
24 | { | |
25 | for (int64_t i = -20; i < 20; ++i) { | |
26 | Real ii = i; | |
27 | auto cfrac = simple_continued_fraction<Real>(ii); | |
28 | auto const & a = cfrac.partial_denominators(); | |
29 | CHECK_EQUAL(size_t(1), a.size()); | |
30 | CHECK_EQUAL(i, a.front()); | |
31 | } | |
32 | } | |
33 | ||
34 | template<class Real> | |
35 | void test_halves() | |
36 | { | |
37 | for (int64_t i = -20; i < 20; ++i) { | |
38 | Real x = i + Real(1)/Real(2); | |
39 | auto cfrac = simple_continued_fraction<Real>(x); | |
40 | auto const & a = cfrac.partial_denominators(); | |
41 | CHECK_EQUAL(size_t(2), a.size()); | |
42 | CHECK_EQUAL(i, a.front()); | |
43 | CHECK_EQUAL(int64_t(2), a.back()); | |
44 | } | |
45 | ||
46 | // We'll also test quarters; why not? | |
47 | for (int64_t i = -20; i < 20; ++i) { | |
48 | Real x = i + Real(1)/Real(4); | |
49 | auto cfrac = simple_continued_fraction<Real>(x); | |
50 | auto const & a = cfrac.partial_denominators(); | |
51 | CHECK_EQUAL(size_t(2), a.size()); | |
52 | CHECK_EQUAL(i, a.front()); | |
53 | CHECK_EQUAL(int64_t(4), a.back()); | |
54 | } | |
55 | ||
56 | for (int64_t i = -20; i < 20; ++i) { | |
57 | Real x = i + Real(1)/Real(8); | |
58 | auto cfrac = simple_continued_fraction<Real>(x); | |
59 | auto const & a = cfrac.partial_denominators(); | |
60 | CHECK_EQUAL(size_t(2), a.size()); | |
61 | CHECK_EQUAL(i, a.front()); | |
62 | CHECK_EQUAL(int64_t(8), a.back()); | |
63 | } | |
64 | ||
65 | for (int64_t i = -20; i < 20; ++i) { | |
66 | Real x = i + Real(3)/Real(4); | |
67 | auto cfrac = simple_continued_fraction<Real>(x); | |
68 | auto const & a = cfrac.partial_denominators(); | |
69 | CHECK_EQUAL(size_t(3), a.size()); | |
70 | CHECK_EQUAL(i, a.front()); | |
71 | CHECK_EQUAL(int64_t(1), a[1]); | |
72 | CHECK_EQUAL(int64_t(3), a.back()); | |
73 | } | |
74 | ||
75 | for (int64_t i = -20; i < 20; ++i) { | |
76 | Real x = i + Real(7)/Real(8); | |
77 | auto cfrac = simple_continued_fraction<Real>(x); | |
78 | auto const & a = cfrac.partial_denominators(); | |
79 | CHECK_EQUAL(size_t(3), a.size()); | |
80 | CHECK_EQUAL(i, a.front()); | |
81 | CHECK_EQUAL(int64_t(1), a[1]); | |
82 | CHECK_EQUAL(int64_t(7), a.back()); | |
83 | } | |
84 | } | |
85 | ||
86 | template<typename Real> | |
87 | void test_simple() | |
88 | { | |
89 | std::cout << "Testing rational numbers on type " << boost::core::demangle(typeid(Real).name()) << "\n"; | |
90 | { | |
91 | Real x = Real(649)/200; | |
92 | // ContinuedFraction[649/200] = [3; 4, 12, 4] | |
93 | auto cfrac = simple_continued_fraction(x); | |
94 | auto const & a = cfrac.partial_denominators(); | |
95 | CHECK_EQUAL(size_t(4), a.size()); | |
96 | CHECK_EQUAL(int64_t(3), a[0]); | |
97 | CHECK_EQUAL(int64_t(4), a[1]); | |
98 | CHECK_EQUAL(int64_t(12), a[2]); | |
99 | CHECK_EQUAL(int64_t(4), a[3]); | |
100 | } | |
101 | ||
102 | { | |
103 | Real x = Real(415)/Real(93); | |
104 | // [4; 2, 6, 7]: | |
105 | auto cfrac = simple_continued_fraction(x); | |
106 | auto const & a = cfrac.partial_denominators(); | |
107 | CHECK_EQUAL(size_t(4), a.size()); | |
108 | CHECK_EQUAL(int64_t(4), a[0]); | |
109 | CHECK_EQUAL(int64_t(2), a[1]); | |
110 | CHECK_EQUAL(int64_t(6), a[2]); | |
111 | CHECK_EQUAL(int64_t(7), a[3]); | |
112 | } | |
113 | ||
114 | } | |
115 | ||
116 | template<typename Real> | |
117 | void test_khinchin() | |
118 | { | |
119 | // These are simply sanity checks; the convergence is too slow otherwise: | |
120 | auto cfrac = simple_continued_fraction(pi<Real>()); | |
121 | auto K0 = cfrac.khinchin_geometric_mean(); | |
122 | CHECK_MOLLIFIED_CLOSE(Real(2.6854520010), K0, 0.1); | |
123 | auto Km1 = cfrac.khinchin_harmonic_mean(); | |
124 | CHECK_MOLLIFIED_CLOSE(Real(1.74540566240), Km1, 0.1); | |
125 | ||
126 | using std::sqrt; | |
127 | auto rt_cfrac = simple_continued_fraction(sqrt(static_cast<Real>(2))); | |
128 | K0 = rt_cfrac.khinchin_geometric_mean(); | |
129 | CHECK_ULP_CLOSE(Real(2), K0, 10); | |
130 | Km1 = rt_cfrac.khinchin_harmonic_mean(); | |
131 | CHECK_ULP_CLOSE(Real(2), Km1, 10); | |
132 | } | |
133 | ||
134 | ||
135 | int main() | |
136 | { | |
137 | test_integral<float>(); | |
138 | test_integral<double>(); | |
139 | test_integral<long double>(); | |
140 | test_integral<cpp_bin_float_100>(); | |
141 | ||
142 | test_halves<float>(); | |
143 | test_halves<double>(); | |
144 | test_halves<long double>(); | |
145 | test_halves<cpp_bin_float_100>(); | |
146 | ||
147 | test_simple<float>(); | |
148 | test_simple<double>(); | |
149 | test_simple<long double>(); | |
150 | test_simple<cpp_bin_float_100>(); | |
151 | ||
152 | test_khinchin<cpp_bin_float_100>(); | |
153 | ||
154 | #ifdef BOOST_HAS_FLOAT128 | |
155 | test_integral<float128>(); | |
156 | test_halves<float128>(); | |
157 | test_simple<float128>(); | |
158 | test_khinchin<float128>(); | |
159 | #endif | |
160 | return boost::math::test::report_errors(); | |
161 | } |