Skip to content

Commit 08f0490

Browse files
committed
Add free function for calculation of simple continued fraction coeffs
1 parent 63f452a commit 08f0490

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

include/boost/math/tools/simple_continued_fraction.hpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// (C) Copyright Nick Thompson 2020.
2+
// (C) Copyright Matt Borland 2023.
23
// Use, modification and distribution are subject to the
34
// Boost Software License, Version 1.0. (See accompanying file
45
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -14,12 +15,14 @@
1415
#include <limits>
1516
#include <stdexcept>
1617
#include <sstream>
18+
#include <utility>
19+
#include <cstdint>
1720

1821
#include <boost/math/tools/is_standalone.hpp>
1922
#ifndef BOOST_MATH_STANDALONE
2023
#include <boost/config.hpp>
2124
#ifdef BOOST_NO_CXX17_IF_CONSTEXPR
22-
#error "The header <boost/math/norms.hpp> can only be used in C++17 and later."
25+
#error "The header <boost/math/simple_continued_fraction.hpp> can only be used in C++17 and later."
2326
#endif
2427
#endif
2528

@@ -108,7 +111,7 @@ class simple_continued_fraction {
108111
// Precompute the most probable logarithms. See the Gauss-Kuzmin distribution for details.
109112
// Example: b_i = 1 has probability -log_2(3/4) ~ .415:
110113
// A random partial denominator has ~80% chance of being in this table:
111-
const std::array<Real, 7> logs{std::numeric_limits<Real>::quiet_NaN(), Real(0), log(static_cast<Real>(2)), log(static_cast<Real>(3)), log(static_cast<Real>(4)), log(static_cast<Real>(5)), log(static_cast<Real>(6))};
114+
const std::array<Real, 7> logs{std::numeric_limits<Real>::quiet_NaN(), static_cast<Real>(0), log(static_cast<Real>(2)), log(static_cast<Real>(3)), log(static_cast<Real>(4)), log(static_cast<Real>(5)), log(static_cast<Real>(6))};
112115
Real log_prod = 0;
113116
for (size_t i = 1; i < b_.size(); ++i) {
114117
if (b_[i] < static_cast<Z>(logs.size())) {
@@ -138,6 +141,11 @@ class simple_continued_fraction {
138141
const std::vector<Z>& partial_denominators() const {
139142
return b_;
140143
}
144+
145+
inline std::vector<Z>&& get_data() noexcept
146+
{
147+
return std::move(b_);
148+
}
141149

142150
template<typename T, typename Z2>
143151
friend std::ostream& operator<<(std::ostream& out, simple_continued_fraction<T, Z2>& scf);
@@ -171,6 +179,12 @@ std::ostream& operator<<(std::ostream& out, simple_continued_fraction<Real, Z2>&
171179
return out;
172180
}
173181

182+
template<typename Real, typename Z = std::int64_t>
183+
inline auto simple_continued_fraction_coefficients(Real x)
184+
{
185+
auto temp = simple_continued_fraction(x);
186+
return temp.get_data();
187+
}
174188

175189
}
176190
#endif

test/simple_continued_fraction_test.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright Nick Thompson, 2020
3+
* Copyright Matt Borland, 2023
34
* Use, modification and distribution are subject to the
45
* Boost Software License, Version 1.0. (See accompanying file
56
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -131,6 +132,38 @@ void test_khinchin()
131132
CHECK_ULP_CLOSE(Real(2), Km1, 10);
132133
}
133134

135+
template <typename Real>
136+
void test_git_issue_970()
137+
{
138+
using boost::math::tools::simple_continued_fraction_coefficients;
139+
140+
auto coefs1 = simple_continued_fraction_coefficients(static_cast<Real>(3.14155L)); // [3; 7, 15, 2, 7, 1, 4, 2]
141+
auto coefs2 = simple_continued_fraction_coefficients(static_cast<Real>(3.14165L)); // [3; 7, 16, 1, 3, 4, 2, 4]
142+
143+
const std::size_t max_size = (std::min)(coefs1.size(), coefs2.size());
144+
std::vector<std::int64_t> coefs;
145+
coefs.reserve(max_size);
146+
147+
for (std::size_t i = 0; i < max_size; ++i)
148+
{
149+
const auto c1 = coefs1[i];
150+
const auto c2 = coefs2[i];
151+
if (c1 == c2)
152+
{
153+
coefs.emplace_back(c1);
154+
continue;
155+
}
156+
157+
coefs.emplace_back((std::min)(c1, c2) + 1);
158+
break;
159+
}
160+
161+
// Result is [3; 7, 16]
162+
CHECK_EQUAL(coefs.size(), 3UL);
163+
CHECK_EQUAL(coefs[0], INT64_C(3));
164+
CHECK_EQUAL(coefs[1], INT64_C(7));
165+
CHECK_EQUAL(coefs[2], INT64_C(16));
166+
}
134167

135168
int main()
136169
{
@@ -157,5 +190,10 @@ int main()
157190
test_simple<float128>();
158191
test_khinchin<float128>();
159192
#endif
193+
194+
test_git_issue_970<float>();
195+
test_git_issue_970<double>();
196+
test_git_issue_970<long double>();
197+
160198
return boost::math::test::report_errors();
161199
}

0 commit comments

Comments
 (0)