File indexing completed on 2025-01-18 09:40:40
0001
0002
0003
0004
0005
0006 #ifndef BOOST_MATH_TOOLS_LUROTH_EXPANSION_HPP
0007 #define BOOST_MATH_TOOLS_LUROTH_EXPANSION_HPP
0008
0009 #include <vector>
0010 #include <ostream>
0011 #include <iomanip>
0012 #include <cmath>
0013 #include <limits>
0014 #include <cstdint>
0015 #include <stdexcept>
0016
0017 #include <boost/math/tools/is_standalone.hpp>
0018 #ifndef BOOST_MATH_STANDALONE
0019 #include <boost/config.hpp>
0020 #ifdef BOOST_NO_CXX17_IF_CONSTEXPR
0021 #error "The header <boost/math/norms.hpp> can only be used in C++17 and later."
0022 #endif
0023 #endif
0024
0025 namespace boost::math::tools {
0026
0027 template<typename Real, typename Z = int64_t>
0028 class luroth_expansion {
0029 public:
0030 luroth_expansion(Real x) : x_{x}
0031 {
0032 using std::floor;
0033 using std::abs;
0034 using std::sqrt;
0035 using std::isfinite;
0036 if (!isfinite(x))
0037 {
0038 throw std::domain_error("Cannot convert non-finites into a Luroth representation.");
0039 }
0040 d_.reserve(50);
0041 Real dn1 = floor(x);
0042 d_.push_back(static_cast<Z>(dn1));
0043 if (dn1 == x)
0044 {
0045 d_.shrink_to_fit();
0046 return;
0047 }
0048
0049
0050 x = x - dn1;
0051 Real computed = dn1;
0052 Real prod = 1;
0053
0054
0055
0056 Real i = 1;
0057 Real scale = std::numeric_limits<Real>::epsilon()*abs(x_)/2;
0058 while (abs(x_ - computed) > (i++)*scale)
0059 {
0060 Real recip = 1/x;
0061 Real dn = floor(recip);
0062
0063
0064
0065
0066
0067 if (recip == dn) {
0068 d_.push_back(static_cast<Z>(dn - 1));
0069 break;
0070 }
0071 d_.push_back(static_cast<Z>(dn));
0072 Real tmp = 1/(dn+1);
0073 computed += prod*tmp;
0074 prod *= tmp/dn;
0075 x = dn*(dn+1)*(x - tmp);
0076 }
0077
0078 for (size_t i = 1; i < d_.size(); ++i)
0079 {
0080
0081 if (d_[i] <= 0)
0082 {
0083 throw std::domain_error("Found a digit <= 0; this is an error.");
0084 }
0085 }
0086 d_.shrink_to_fit();
0087 }
0088
0089
0090 const std::vector<Z>& digits() const {
0091 return d_;
0092 }
0093
0094
0095
0096 Real digit_geometric_mean() const {
0097 if (d_.size() == 1) {
0098 return std::numeric_limits<Real>::quiet_NaN();
0099 }
0100 using std::log;
0101 using std::exp;
0102 Real g = 0;
0103 for (size_t i = 1; i < d_.size(); ++i) {
0104 g += log(static_cast<Real>(d_[i]));
0105 }
0106 return exp(g/(d_.size() - 1));
0107 }
0108
0109 template<typename T, typename Z2>
0110 friend std::ostream& operator<<(std::ostream& out, luroth_expansion<T, Z2>& scf);
0111
0112 private:
0113 const Real x_;
0114 std::vector<Z> d_;
0115 };
0116
0117
0118 template<typename Real, typename Z2>
0119 std::ostream& operator<<(std::ostream& out, luroth_expansion<Real, Z2>& luroth)
0120 {
0121 constexpr const int p = std::numeric_limits<Real>::max_digits10;
0122 if constexpr (p == 2147483647)
0123 {
0124 out << std::setprecision(luroth.x_.backend().precision());
0125 }
0126 else
0127 {
0128 out << std::setprecision(p);
0129 }
0130
0131 out << "((" << luroth.d_.front();
0132 if (luroth.d_.size() > 1)
0133 {
0134 out << "; ";
0135 for (size_t i = 1; i < luroth.d_.size() -1; ++i)
0136 {
0137 out << luroth.d_[i] << ", ";
0138 }
0139 out << luroth.d_.back();
0140 }
0141 out << "))";
0142 return out;
0143 }
0144
0145
0146 }
0147 #endif