1 ///////////////////////////////////////////////////////////////
2 //  Copyright 2012 John Maddock. Distributed under the Boost
3 //  Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
5 
6 #ifndef BOOST_MATH_CONCEPTS_ER_HPP
7 #define BOOST_MATH_CONCEPTS_ER_HPP
8 
9 #include <iostream>
10 #include <sstream>
11 #include <iomanip>
12 #include <cmath>
13 #include <boost/cstdint.hpp>
14 #include <boost/multiprecision/number.hpp>
15 #include <boost/math/special_functions/fpclassify.hpp>
16 #include <boost/mpl/list.hpp>
17 #include <boost/container_hash/hash.hpp>
18 
19 namespace boost{
20 namespace multiprecision{
21 namespace concepts{
22 
23 #ifdef BOOST_MSVC
24 #pragma warning(push)
25 #pragma warning(disable:4244)
26 #endif
27 
28 struct number_backend_float_architype
29 {
30    typedef mpl::list<boost::long_long_type>                 signed_types;
31    typedef mpl::list<boost::ulong_long_type>        unsigned_types;
32    typedef mpl::list<long double>               float_types;
33    typedef int                                  exponent_type;
34 
number_backend_float_architypeboost::multiprecision::concepts::number_backend_float_architype35    number_backend_float_architype()
36    {
37       m_value = 0;
38       std::cout << "Default construct" << std::endl;
39    }
number_backend_float_architypeboost::multiprecision::concepts::number_backend_float_architype40    number_backend_float_architype(const number_backend_float_architype& o)
41    {
42       std::cout << "Copy construct" << std::endl;
43       m_value = o.m_value;
44    }
operator =boost::multiprecision::concepts::number_backend_float_architype45    number_backend_float_architype& operator = (const number_backend_float_architype& o)
46    {
47       m_value = o.m_value;
48       std::cout << "Assignment (" << m_value << ")" << std::endl;
49       return *this;
50    }
operator =boost::multiprecision::concepts::number_backend_float_architype51    number_backend_float_architype& operator = (boost::ulong_long_type i)
52    {
53       m_value = i;
54       std::cout << "UInt Assignment (" << i << ")" << std::endl;
55       return *this;
56    }
operator =boost::multiprecision::concepts::number_backend_float_architype57    number_backend_float_architype& operator = (boost::long_long_type i)
58    {
59       m_value = i;
60       std::cout << "Int Assignment (" << i << ")" << std::endl;
61       return *this;
62    }
operator =boost::multiprecision::concepts::number_backend_float_architype63    number_backend_float_architype& operator = (long double d)
64    {
65       m_value = d;
66       std::cout << "long double Assignment (" << d << ")" << std::endl;
67       return *this;
68    }
operator =boost::multiprecision::concepts::number_backend_float_architype69    number_backend_float_architype& operator = (const char* s)
70    {
71 #ifndef BOOST_NO_EXCEPTIONS
72       try
73       {
74 #endif
75          m_value = boost::lexical_cast<long double>(s);
76 #ifndef BOOST_NO_EXCEPTIONS
77       }
78       catch(const std::exception&)
79       {
80          BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Unable to parse input string: \"") + s + std::string("\" as a valid floating point number.")));
81       }
82 #endif
83       std::cout << "const char* Assignment (" << s << ")" << std::endl;
84       return *this;
85    }
swapboost::multiprecision::concepts::number_backend_float_architype86    void swap(number_backend_float_architype& o)
87    {
88       std::cout << "Swapping (" << m_value << " with " << o.m_value << ")" << std::endl;
89       std::swap(m_value, o.m_value);
90    }
strboost::multiprecision::concepts::number_backend_float_architype91    std::string str(std::streamsize digits, std::ios_base::fmtflags f)const
92    {
93       std::stringstream ss;
94       ss.flags(f);
95       if(digits)
96          ss.precision(digits);
97       else
98          ss.precision(std::numeric_limits<long double>::digits10 + 3);
99       boost::intmax_t i = m_value;
100       boost::uintmax_t u = m_value;
101       if(!(f & std::ios_base::scientific) && m_value == i)
102          ss << i;
103       else if(!(f & std::ios_base::scientific) && m_value == u)
104          ss << u;
105       else
106          ss << m_value;
107       std::string s = ss.str();
108       std::cout << "Converting to string (" << s << ")" << std::endl;
109       return s;
110    }
negateboost::multiprecision::concepts::number_backend_float_architype111    void negate()
112    {
113       std::cout << "Negating (" << m_value << ")" << std::endl;
114       m_value = -m_value;
115    }
compareboost::multiprecision::concepts::number_backend_float_architype116    int compare(const number_backend_float_architype& o)const
117    {
118       std::cout << "Comparison" << std::endl;
119       return m_value > o.m_value ? 1 : (m_value < o.m_value ? -1 : 0);
120    }
compareboost::multiprecision::concepts::number_backend_float_architype121    int compare(boost::long_long_type i)const
122    {
123       std::cout << "Comparison with int" << std::endl;
124       return m_value > i ? 1 : (m_value < i ? -1 : 0);
125    }
compareboost::multiprecision::concepts::number_backend_float_architype126    int compare(boost::ulong_long_type i)const
127    {
128       std::cout << "Comparison with unsigned" << std::endl;
129       return m_value > i ? 1 : (m_value < i ? -1 : 0);
130    }
compareboost::multiprecision::concepts::number_backend_float_architype131    int compare(long double d)const
132    {
133       std::cout << "Comparison with long double" << std::endl;
134       return m_value > d ? 1 : (m_value < d ? -1 : 0);
135    }
136    long double m_value;
137 };
138 
eval_add(number_backend_float_architype & result,const number_backend_float_architype & o)139 inline void eval_add(number_backend_float_architype& result, const number_backend_float_architype& o)
140 {
141    std::cout << "Addition (" << result.m_value << " += " << o.m_value << ")" << std::endl;
142    result.m_value += o.m_value;
143 }
eval_subtract(number_backend_float_architype & result,const number_backend_float_architype & o)144 inline void eval_subtract(number_backend_float_architype& result, const number_backend_float_architype& o)
145 {
146    std::cout << "Subtraction (" << result.m_value << " -= " << o.m_value << ")" << std::endl;
147    result.m_value -= o.m_value;
148 }
eval_multiply(number_backend_float_architype & result,const number_backend_float_architype & o)149 inline void eval_multiply(number_backend_float_architype& result, const number_backend_float_architype& o)
150 {
151    std::cout << "Multiplication (" << result.m_value << " *= " << o.m_value << ")" << std::endl;
152    result.m_value *= o.m_value;
153 }
eval_divide(number_backend_float_architype & result,const number_backend_float_architype & o)154 inline void eval_divide(number_backend_float_architype& result, const number_backend_float_architype& o)
155 {
156    std::cout << "Division (" << result.m_value << " /= " << o.m_value << ")" << std::endl;
157    result.m_value /= o.m_value;
158 }
159 
eval_convert_to(boost::ulong_long_type * result,const number_backend_float_architype & val)160 inline void eval_convert_to(boost::ulong_long_type* result, const number_backend_float_architype& val)
161 {
162    *result = static_cast<boost::ulong_long_type>(val.m_value);
163 }
eval_convert_to(boost::long_long_type * result,const number_backend_float_architype & val)164 inline void eval_convert_to(boost::long_long_type* result, const number_backend_float_architype& val)
165 {
166    *result = static_cast<boost::long_long_type>(val.m_value);
167 }
eval_convert_to(long double * result,number_backend_float_architype & val)168 inline void eval_convert_to(long double* result, number_backend_float_architype& val)
169 {
170    *result = val.m_value;
171 }
172 
eval_frexp(number_backend_float_architype & result,const number_backend_float_architype & arg,int * exp)173 inline void eval_frexp(number_backend_float_architype& result, const number_backend_float_architype& arg, int* exp)
174 {
175    result = std::frexp(arg.m_value, exp);
176 }
177 
eval_ldexp(number_backend_float_architype & result,const number_backend_float_architype & arg,int exp)178 inline void eval_ldexp(number_backend_float_architype& result, const number_backend_float_architype& arg, int exp)
179 {
180    result = std::ldexp(arg.m_value, exp);
181 }
182 
eval_floor(number_backend_float_architype & result,const number_backend_float_architype & arg)183 inline void eval_floor(number_backend_float_architype& result, const number_backend_float_architype& arg)
184 {
185    result = std::floor(arg.m_value);
186 }
187 
eval_ceil(number_backend_float_architype & result,const number_backend_float_architype & arg)188 inline void eval_ceil(number_backend_float_architype& result, const number_backend_float_architype& arg)
189 {
190    result = std::ceil(arg.m_value);
191 }
192 
eval_sqrt(number_backend_float_architype & result,const number_backend_float_architype & arg)193 inline void eval_sqrt(number_backend_float_architype& result, const number_backend_float_architype& arg)
194 {
195    result = std::sqrt(arg.m_value);
196 }
197 
eval_fpclassify(const number_backend_float_architype & arg)198 inline int eval_fpclassify(const number_backend_float_architype& arg)
199 {
200    return (boost::math::fpclassify)(arg.m_value);
201 }
202 
hash_value(const number_backend_float_architype & v)203 inline std::size_t hash_value(const number_backend_float_architype& v)
204 {
205    boost::hash<long double> hasher;
206    return hasher(v.m_value);
207 }
208 
209 typedef boost::multiprecision::number<number_backend_float_architype> mp_number_float_architype;
210 
211 } // namespace
212 
213 template<>
214 struct number_category<concepts::number_backend_float_architype> : public mpl::int_<number_kind_floating_point>{};
215 
216 }} // namespaces
217 
218 namespace std{
219 
220 template <boost::multiprecision::expression_template_option ExpressionTemplates>
221 class numeric_limits<boost::multiprecision::number<boost::multiprecision::concepts::number_backend_float_architype, ExpressionTemplates> > : public std::numeric_limits<long double>
222 {
223    typedef std::numeric_limits<long double> base_type;
224    typedef boost::multiprecision::number<boost::multiprecision::concepts::number_backend_float_architype, ExpressionTemplates> number_type;
225 public:
number_type(min)226    static number_type (min)() BOOST_NOEXCEPT { return (base_type::min)(); }
number_type(max)227    static number_type (max)() BOOST_NOEXCEPT { return (base_type::max)(); }
lowest()228    static number_type lowest() BOOST_NOEXCEPT { return -(max)(); }
epsilon()229    static number_type epsilon() BOOST_NOEXCEPT { return base_type::epsilon(); }
round_error()230    static number_type round_error() BOOST_NOEXCEPT { return base_type::round_error(); }
infinity()231    static number_type infinity() BOOST_NOEXCEPT { return base_type::infinity(); }
quiet_NaN()232    static number_type quiet_NaN() BOOST_NOEXCEPT { return base_type::quiet_NaN(); }
signaling_NaN()233    static number_type signaling_NaN() BOOST_NOEXCEPT { return base_type::signaling_NaN(); }
denorm_min()234    static number_type denorm_min() BOOST_NOEXCEPT { return base_type::denorm_min(); }
235 };
236 
237 }
238 
239 #ifdef BOOST_MSVC
240 #pragma warning(pop)
241 #endif
242 
243 #endif
244