Skip to content

Commit d83bd53

Browse files
author
Tomáš Kolárik
committed
Typedef for Z int_type; replaced member variable x_ with precision_
1 parent 1f3a079 commit d83bd53

File tree

1 file changed

+39
-32
lines changed

1 file changed

+39
-32
lines changed

include/boost/math/tools/simple_continued_fraction.hpp

+39-32
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,25 @@ namespace boost::math::tools {
3535
template<typename Real, typename Z = int64_t>
3636
class simple_continued_fraction {
3737
public:
38-
simple_continued_fraction(Real x) : x_{x} {
38+
typedef Z int_type;
39+
40+
simple_continued_fraction(Real x) {
3941
using std::floor;
4042
using std::abs;
4143
using std::sqrt;
4244
using std::isfinite;
45+
const Real orig_x = x;
4346
if (!isfinite(x)) {
44-
throw std::domain_error("Cannot convert non-finites into continued fractions.");
47+
throw std::domain_error("Cannot convert non-finites into continued fractions.");
48+
}
49+
50+
constexpr int p = std::numeric_limits<Real>::max_digits10;
51+
if constexpr (p == 2147483647) {
52+
precision_ = orig_x.backend().precision();
53+
} else {
54+
precision_ = p;
4555
}
56+
4657
b_.reserve(50);
4758
Real bj = floor(x);
4859
b_.push_back(static_cast<Z>(bj));
@@ -57,12 +68,11 @@ class simple_continued_fraction {
5768
}
5869
Real C = f;
5970
Real D = 0;
60-
int i = 0;
61-
// the "1 + i++" lets the error bound grow slowly with the number of convergents.
71+
// the "1 + i" lets the error bound grow slowly with the number of convergents.
6272
// I have not worked out the error propagation of the Modified Lentz's method to see if it does indeed grow at this rate.
6373
// Numerical Recipes claims that no one has worked out the error analysis of the modified Lentz's method.
64-
while (abs(f - x_) >= (1 + i++)*std::numeric_limits<Real>::epsilon()*abs(x_))
65-
{
74+
const Real eps_abs_orig_x = std::numeric_limits<Real>::epsilon()*abs(orig_x);
75+
for (int i = 0; abs(f - orig_x) >= (1 + i)*eps_abs_orig_x; ++i) {
6676
bj = floor(x);
6777
b_.push_back(static_cast<Z>(bj));
6878
x = 1/(x-bj);
@@ -81,12 +91,13 @@ class simple_continued_fraction {
8191
// The shorter representation is considered the canonical representation,
8292
// so if we compute a non-canonical representation, change it to canonical:
8393
if (b_.size() > 2 && b_.back() == 1) {
84-
b_[b_.size() - 2] += 1;
85-
b_.resize(b_.size() - 1);
94+
b_.pop_back();
95+
b_.back() += 1;
8696
}
8797
b_.shrink_to_fit();
88-
89-
for (size_t i = 1; i < b_.size(); ++i) {
98+
99+
const size_t size_ = b_.size();
100+
for (size_t i = 1; i < size_; ++i) {
90101
if (b_[i] <= 0) {
91102
std::ostringstream oss;
92103
oss << "Found a negative partial denominator: b[" << i << "] = " << b_[i] << "."
@@ -101,9 +112,10 @@ class simple_continued_fraction {
101112
}
102113
}
103114
}
104-
115+
105116
Real khinchin_geometric_mean() const {
106-
if (b_.size() == 1) {
117+
const size_t size_ = b_.size();
118+
if (size_ == 1) {
107119
return std::numeric_limits<Real>::quiet_NaN();
108120
}
109121
using std::log;
@@ -113,7 +125,7 @@ class simple_continued_fraction {
113125
// A random partial denominator has ~80% chance of being in this table:
114126
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))};
115127
Real log_prod = 0;
116-
for (size_t i = 1; i < b_.size(); ++i) {
128+
for (size_t i = 1; i < size_; ++i) {
117129
if (b_[i] < static_cast<Z>(logs.size())) {
118130
log_prod += logs[b_[i]];
119131
}
@@ -122,49 +134,44 @@ class simple_continued_fraction {
122134
log_prod += log(static_cast<Real>(b_[i]));
123135
}
124136
}
125-
log_prod /= (b_.size()-1);
137+
log_prod /= (size_-1);
126138
return exp(log_prod);
127139
}
128-
140+
129141
Real khinchin_harmonic_mean() const {
130-
if (b_.size() == 1) {
142+
const size_t size_ = b_.size();
143+
if (size_ == 1) {
131144
return std::numeric_limits<Real>::quiet_NaN();
132145
}
133-
Real n = b_.size() - 1;
146+
Real n = size_ - 1;
134147
Real denom = 0;
135-
for (size_t i = 1; i < b_.size(); ++i) {
148+
for (size_t i = 1; i < size_; ++i) {
136149
denom += 1/static_cast<Real>(b_[i]);
137150
}
138151
return n/denom;
139152
}
140-
153+
154+
// Note that this also includes the integer part (i.e. all the coefficients)
141155
const std::vector<Z>& partial_denominators() const {
142156
return b_;
143157
}
144158

145-
inline std::vector<Z>&& get_data() noexcept
146-
{
159+
inline std::vector<Z>&& get_data() noexcept {
147160
return std::move(b_);
148161
}
149-
162+
150163
template<typename T, typename Z2>
151164
friend std::ostream& operator<<(std::ostream& out, simple_continued_fraction<T, Z2>& scf);
152-
153165
private:
154-
const Real x_;
155-
std::vector<Z> b_;
166+
std::vector<Z> b_{};
167+
168+
int precision_{};
156169
};
157170

158171

159172
template<typename Real, typename Z2>
160173
std::ostream& operator<<(std::ostream& out, simple_continued_fraction<Real, Z2>& scf) {
161-
constexpr const int p = std::numeric_limits<Real>::max_digits10;
162-
if constexpr (p == 2147483647) {
163-
out << std::setprecision(scf.x_.backend().precision());
164-
} else {
165-
out << std::setprecision(p);
166-
}
167-
174+
out << std::setprecision(scf.precision_);
168175
out << "[" << scf.b_.front();
169176
if (scf.b_.size() > 1)
170177
{

0 commit comments

Comments
 (0)