annotate DEPENDENCIES/generic/include/boost/multiprecision/rational_adaptor.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 ///////////////////////////////////////////////////////////////
Chris@16 2 // Copyright 2011 John Maddock. Distributed under the Boost
Chris@16 3 // Software License, Version 1.0. (See accompanying file
Chris@16 4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
Chris@16 5
Chris@16 6 #ifndef BOOST_MATH_RATIONAL_ADAPTER_HPP
Chris@16 7 #define BOOST_MATH_RATIONAL_ADAPTER_HPP
Chris@16 8
Chris@16 9 #include <iostream>
Chris@16 10 #include <iomanip>
Chris@16 11 #include <sstream>
Chris@16 12 #include <boost/cstdint.hpp>
Chris@16 13 #include <boost/multiprecision/number.hpp>
Chris@16 14 #ifdef BOOST_MSVC
Chris@16 15 # pragma warning(push)
Chris@16 16 # pragma warning(disable:4512 4127)
Chris@16 17 #endif
Chris@16 18 #include <boost/rational.hpp>
Chris@16 19 #ifdef BOOST_MSVC
Chris@16 20 # pragma warning(pop)
Chris@16 21 #endif
Chris@16 22
Chris@16 23 namespace boost{
Chris@16 24 namespace multiprecision{
Chris@16 25 namespace backends{
Chris@16 26
Chris@16 27 template <class IntBackend>
Chris@16 28 struct rational_adaptor
Chris@16 29 {
Chris@16 30 typedef number<IntBackend> integer_type;
Chris@16 31 typedef boost::rational<integer_type> rational_type;
Chris@16 32
Chris@16 33 typedef typename IntBackend::signed_types signed_types;
Chris@16 34 typedef typename IntBackend::unsigned_types unsigned_types;
Chris@16 35 typedef typename IntBackend::float_types float_types;
Chris@16 36
Chris@101 37 rational_adaptor() BOOST_NOEXCEPT_IF(noexcept(rational_type())) {}
Chris@101 38 rational_adaptor(const rational_adaptor& o) BOOST_NOEXCEPT_IF(noexcept(std::declval<rational_type&>() = std::declval<const rational_type&>()))
Chris@16 39 {
Chris@16 40 m_value = o.m_value;
Chris@16 41 }
Chris@101 42 rational_adaptor(const IntBackend& o) BOOST_NOEXCEPT_IF(noexcept(rational_type(std::declval<const IntBackend&>()))) : m_value(o) {}
Chris@16 43
Chris@16 44 template <class U>
Chris@16 45 rational_adaptor(const U& u, typename enable_if_c<is_convertible<U, IntBackend>::value>::type* = 0)
Chris@101 46 : m_value(static_cast<integer_type>(u)){}
Chris@16 47 template <class U>
Chris@16 48 explicit rational_adaptor(const U& u,
Chris@16 49 typename enable_if_c<
Chris@16 50 boost::multiprecision::detail::is_explicitly_convertible<U, IntBackend>::value && !is_convertible<U, IntBackend>::value
Chris@16 51 >::type* = 0)
Chris@16 52 : m_value(IntBackend(u)){}
Chris@16 53 template <class U>
Chris@16 54 typename enable_if_c<(boost::multiprecision::detail::is_explicitly_convertible<U, IntBackend>::value && !is_arithmetic<U>::value), rational_adaptor&>::type operator = (const U& u)
Chris@16 55 {
Chris@16 56 m_value = IntBackend(u);
Chris@16 57 }
Chris@16 58
Chris@16 59 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
Chris@101 60 rational_adaptor(rational_adaptor&& o) BOOST_NOEXCEPT_IF(noexcept(rational_type(std::declval<rational_type>()))) : m_value(static_cast<rational_type&&>(o.m_value)) {}
Chris@101 61 rational_adaptor(IntBackend&& o) BOOST_NOEXCEPT_IF(noexcept(rational_type(std::declval<IntBackend>()))) : m_value(static_cast<IntBackend&&>(o)) {}
Chris@101 62 rational_adaptor& operator = (rational_adaptor&& o) BOOST_NOEXCEPT_IF(noexcept(std::declval<rational_type&>() = std::declval<rational_type>()))
Chris@16 63 {
Chris@16 64 m_value = static_cast<rational_type&&>(o.m_value);
Chris@16 65 return *this;
Chris@16 66 }
Chris@16 67 #endif
Chris@16 68 rational_adaptor& operator = (const rational_adaptor& o)
Chris@16 69 {
Chris@16 70 m_value = o.m_value;
Chris@16 71 return *this;
Chris@16 72 }
Chris@16 73 rational_adaptor& operator = (const IntBackend& o)
Chris@16 74 {
Chris@16 75 m_value = o;
Chris@16 76 return *this;
Chris@16 77 }
Chris@16 78 template <class Int>
Chris@16 79 typename enable_if<is_integral<Int>, rational_adaptor&>::type operator = (Int i)
Chris@16 80 {
Chris@16 81 m_value = i;
Chris@16 82 return *this;
Chris@16 83 }
Chris@16 84 template <class Float>
Chris@16 85 typename enable_if<is_floating_point<Float>, rational_adaptor&>::type operator = (Float i)
Chris@16 86 {
Chris@16 87 int e;
Chris@16 88 Float f = std::frexp(i, &e);
Chris@16 89 f = std::ldexp(f, std::numeric_limits<Float>::digits);
Chris@16 90 e -= std::numeric_limits<Float>::digits;
Chris@16 91 integer_type num(f);
Chris@16 92 integer_type denom(1u);
Chris@16 93 if(e > 0)
Chris@16 94 {
Chris@16 95 num <<= e;
Chris@16 96 }
Chris@16 97 else if(e < 0)
Chris@16 98 {
Chris@16 99 denom <<= -e;
Chris@16 100 }
Chris@16 101 m_value.assign(num, denom);
Chris@16 102 return *this;
Chris@16 103 }
Chris@16 104 rational_adaptor& operator = (const char* s)
Chris@16 105 {
Chris@16 106 std::string s1;
Chris@16 107 multiprecision::number<IntBackend> v1, v2;
Chris@16 108 char c;
Chris@16 109 bool have_hex = false;
Chris@16 110 const char* p = s; // saved for later
Chris@16 111
Chris@16 112 while((0 != (c = *s)) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F'))))
Chris@16 113 {
Chris@16 114 if(c == 'x' || c == 'X')
Chris@16 115 have_hex = true;
Chris@16 116 s1.append(1, c);
Chris@16 117 ++s;
Chris@16 118 }
Chris@16 119 v1.assign(s1);
Chris@16 120 s1.erase();
Chris@16 121 if(c == '/')
Chris@16 122 {
Chris@16 123 ++s;
Chris@16 124 while((0 != (c = *s)) && (c == 'x' || c == 'X' || c == '-' || c == '+' || (c >= '0' && c <= '9') || (have_hex && (c >= 'a' && c <= 'f')) || (have_hex && (c >= 'A' && c <= 'F'))))
Chris@16 125 {
Chris@16 126 if(c == 'x' || c == 'X')
Chris@16 127 have_hex = true;
Chris@16 128 s1.append(1, c);
Chris@16 129 ++s;
Chris@16 130 }
Chris@16 131 v2.assign(s1);
Chris@16 132 }
Chris@16 133 else
Chris@16 134 v2 = 1;
Chris@16 135 if(*s)
Chris@16 136 {
Chris@16 137 BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Could parse the string \"") + p + std::string("\" as a valid rational number.")));
Chris@16 138 }
Chris@16 139 data().assign(v1, v2);
Chris@16 140 return *this;
Chris@16 141 }
Chris@16 142 void swap(rational_adaptor& o)
Chris@16 143 {
Chris@16 144 std::swap(m_value, o.m_value);
Chris@16 145 }
Chris@16 146 std::string str(std::streamsize digits, std::ios_base::fmtflags f)const
Chris@16 147 {
Chris@16 148 //
Chris@16 149 // We format the string ourselves so we can match what GMP's mpq type does:
Chris@16 150 //
Chris@16 151 std::string result = data().numerator().str(digits, f);
Chris@16 152 if(data().denominator() != 1)
Chris@16 153 {
Chris@16 154 result.append(1, '/');
Chris@16 155 result.append(data().denominator().str(digits, f));
Chris@16 156 }
Chris@16 157 return result;
Chris@16 158 }
Chris@16 159 void negate()
Chris@16 160 {
Chris@16 161 m_value = -m_value;
Chris@16 162 }
Chris@16 163 int compare(const rational_adaptor& o)const
Chris@16 164 {
Chris@16 165 return m_value > o.m_value ? 1 : (m_value < o.m_value ? -1 : 0);
Chris@16 166 }
Chris@16 167 template <class Arithmatic>
Chris@101 168 typename enable_if_c<is_arithmetic<Arithmatic>::value && !is_floating_point<Arithmatic>::value, int>::type compare(Arithmatic i)const
Chris@16 169 {
Chris@16 170 return m_value > i ? 1 : (m_value < i ? -1 : 0);
Chris@16 171 }
Chris@101 172 template <class Arithmatic>
Chris@101 173 typename enable_if_c<is_floating_point<Arithmatic>::value, int>::type compare(Arithmatic i)const
Chris@101 174 {
Chris@101 175 rational_adaptor r;
Chris@101 176 r = i;
Chris@101 177 return this->compare(r);
Chris@101 178 }
Chris@16 179 rational_type& data() { return m_value; }
Chris@16 180 const rational_type& data()const { return m_value; }
Chris@16 181
Chris@16 182 template <class Archive>
Chris@16 183 void serialize(Archive& ar, const mpl::true_&)
Chris@16 184 {
Chris@16 185 // Saving
Chris@16 186 integer_type n(m_value.numerator()), d(m_value.denominator());
Chris@16 187 ar & n;
Chris@16 188 ar & d;
Chris@16 189 }
Chris@16 190 template <class Archive>
Chris@16 191 void serialize(Archive& ar, const mpl::false_&)
Chris@16 192 {
Chris@16 193 // Loading
Chris@16 194 integer_type n, d;
Chris@16 195 ar & n;
Chris@16 196 ar & d;
Chris@16 197 m_value.assign(n, d);
Chris@16 198 }
Chris@16 199 template <class Archive>
Chris@16 200 void serialize(Archive& ar, const unsigned int /*version*/)
Chris@16 201 {
Chris@16 202 typedef typename Archive::is_saving tag;
Chris@16 203 serialize(ar, tag());
Chris@16 204 }
Chris@16 205 private:
Chris@16 206 rational_type m_value;
Chris@16 207 };
Chris@16 208
Chris@16 209 template <class IntBackend>
Chris@16 210 inline void eval_add(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
Chris@16 211 {
Chris@16 212 result.data() += o.data();
Chris@16 213 }
Chris@16 214 template <class IntBackend>
Chris@16 215 inline void eval_subtract(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
Chris@16 216 {
Chris@16 217 result.data() -= o.data();
Chris@16 218 }
Chris@16 219 template <class IntBackend>
Chris@16 220 inline void eval_multiply(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
Chris@16 221 {
Chris@16 222 result.data() *= o.data();
Chris@16 223 }
Chris@16 224 template <class IntBackend>
Chris@16 225 inline void eval_divide(rational_adaptor<IntBackend>& result, const rational_adaptor<IntBackend>& o)
Chris@16 226 {
Chris@16 227 using default_ops::eval_is_zero;
Chris@16 228 if(eval_is_zero(o))
Chris@16 229 {
Chris@16 230 BOOST_THROW_EXCEPTION(std::overflow_error("Divide by zero."));
Chris@16 231 }
Chris@16 232 result.data() /= o.data();
Chris@16 233 }
Chris@16 234
Chris@16 235 template <class R, class IntBackend>
Chris@101 236 inline typename enable_if_c<number_category<R>::value == number_kind_floating_point>::type eval_convert_to(R* result, const rational_adaptor<IntBackend>& backend)
Chris@16 237 {
Chris@101 238 //
Chris@101 239 // The generic conversion is as good as anything we can write here:
Chris@101 240 //
Chris@101 241 ::boost::multiprecision::detail::generic_convert_rational_to_float(*result, backend);
Chris@101 242 }
Chris@101 243
Chris@101 244 template <class R, class IntBackend>
Chris@101 245 inline typename enable_if_c<(number_category<R>::value != number_kind_integer) && (number_category<R>::value != number_kind_floating_point)>::type eval_convert_to(R* result, const rational_adaptor<IntBackend>& backend)
Chris@101 246 {
Chris@101 247 typedef typename component_type<number<rational_adaptor<IntBackend> > >::type comp_t;
Chris@101 248 comp_t num(backend.data().numerator());
Chris@101 249 comp_t denom(backend.data().denominator());
Chris@101 250 *result = num.template convert_to<R>();
Chris@101 251 *result /= denom.template convert_to<R>();
Chris@101 252 }
Chris@101 253
Chris@101 254 template <class R, class IntBackend>
Chris@101 255 inline typename enable_if_c<number_category<R>::value == number_kind_integer>::type eval_convert_to(R* result, const rational_adaptor<IntBackend>& backend)
Chris@101 256 {
Chris@101 257 typedef typename component_type<number<rational_adaptor<IntBackend> > >::type comp_t;
Chris@101 258 comp_t t = backend.data().numerator();
Chris@101 259 t /= backend.data().denominator();
Chris@101 260 *result = t.template convert_to<R>();
Chris@16 261 }
Chris@16 262
Chris@16 263 template <class IntBackend>
Chris@16 264 inline bool eval_is_zero(const rational_adaptor<IntBackend>& val)
Chris@16 265 {
Chris@16 266 return eval_is_zero(val.data().numerator().backend());
Chris@16 267 }
Chris@16 268 template <class IntBackend>
Chris@16 269 inline int eval_get_sign(const rational_adaptor<IntBackend>& val)
Chris@16 270 {
Chris@16 271 return eval_get_sign(val.data().numerator().backend());
Chris@16 272 }
Chris@16 273
Chris@16 274 template<class IntBackend, class V>
Chris@16 275 inline void assign_components(rational_adaptor<IntBackend>& result, const V& v1, const V& v2)
Chris@16 276 {
Chris@16 277 result.data().assign(v1, v2);
Chris@16 278 }
Chris@16 279
Chris@16 280 } // namespace backends
Chris@16 281
Chris@16 282 template<class IntBackend>
Chris@16 283 struct expression_template_default<backends::rational_adaptor<IntBackend> > : public expression_template_default<IntBackend> {};
Chris@16 284
Chris@16 285 template<class IntBackend>
Chris@16 286 struct number_category<backends::rational_adaptor<IntBackend> > : public mpl::int_<number_kind_rational>{};
Chris@16 287
Chris@16 288 using boost::multiprecision::backends::rational_adaptor;
Chris@16 289
Chris@16 290 template <class T>
Chris@16 291 struct component_type<rational_adaptor<T> >
Chris@16 292 {
Chris@16 293 typedef number<T> type;
Chris@16 294 };
Chris@16 295
Chris@16 296 template <class IntBackend, expression_template_option ET>
Chris@16 297 inline number<IntBackend, ET> numerator(const number<rational_adaptor<IntBackend>, ET>& val)
Chris@16 298 {
Chris@16 299 return val.backend().data().numerator();
Chris@16 300 }
Chris@16 301 template <class IntBackend, expression_template_option ET>
Chris@16 302 inline number<IntBackend, ET> denominator(const number<rational_adaptor<IntBackend>, ET>& val)
Chris@16 303 {
Chris@16 304 return val.backend().data().denominator();
Chris@16 305 }
Chris@16 306
Chris@16 307 #ifdef BOOST_NO_SFINAE_EXPR
Chris@16 308
Chris@16 309 namespace detail{
Chris@16 310
Chris@16 311 template<class U, class IntBackend>
Chris@16 312 struct is_explicitly_convertible<U, rational_adaptor<IntBackend> > : public is_explicitly_convertible<U, IntBackend> {};
Chris@16 313
Chris@16 314 }
Chris@16 315
Chris@16 316 #endif
Chris@16 317
Chris@16 318 }} // namespaces
Chris@16 319
Chris@16 320
Chris@16 321 namespace std{
Chris@16 322
Chris@16 323 template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates>
Chris@16 324 class numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> > : public std::numeric_limits<boost::multiprecision::number<IntBackend, ExpressionTemplates> >
Chris@16 325 {
Chris@16 326 typedef std::numeric_limits<boost::multiprecision::number<IntBackend> > base_type;
Chris@16 327 typedef boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend> > number_type;
Chris@16 328 public:
Chris@16 329 BOOST_STATIC_CONSTEXPR bool is_integer = false;
Chris@16 330 BOOST_STATIC_CONSTEXPR bool is_exact = true;
Chris@16 331 BOOST_STATIC_CONSTEXPR number_type (min)() { return (base_type::min)(); }
Chris@16 332 BOOST_STATIC_CONSTEXPR number_type (max)() { return (base_type::max)(); }
Chris@16 333 BOOST_STATIC_CONSTEXPR number_type lowest() { return -(max)(); }
Chris@16 334 BOOST_STATIC_CONSTEXPR number_type epsilon() { return base_type::epsilon(); }
Chris@16 335 BOOST_STATIC_CONSTEXPR number_type round_error() { return epsilon() / 2; }
Chris@16 336 BOOST_STATIC_CONSTEXPR number_type infinity() { return base_type::infinity(); }
Chris@16 337 BOOST_STATIC_CONSTEXPR number_type quiet_NaN() { return base_type::quiet_NaN(); }
Chris@16 338 BOOST_STATIC_CONSTEXPR number_type signaling_NaN() { return base_type::signaling_NaN(); }
Chris@16 339 BOOST_STATIC_CONSTEXPR number_type denorm_min() { return base_type::denorm_min(); }
Chris@16 340 };
Chris@16 341
Chris@16 342 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
Chris@16 343
Chris@16 344 template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates>
Chris@16 345 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> >::is_integer;
Chris@16 346 template <class IntBackend, boost::multiprecision::expression_template_option ExpressionTemplates>
Chris@16 347 BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::rational_adaptor<IntBackend>, ExpressionTemplates> >::is_exact;
Chris@16 348
Chris@16 349 #endif
Chris@16 350
Chris@16 351
Chris@16 352 }
Chris@16 353
Chris@16 354 #endif