1 //  Copyright John Maddock 2007.
2 //  Use, modification and distribution are subject to the
3 //  Boost Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef BOOST_MATH_TRUNC_HPP
7 #define BOOST_MATH_TRUNC_HPP
8 
9 #ifdef _MSC_VER
10 #pragma once
11 #endif
12 
13 #include <type_traits>
14 #include <boost/math/special_functions/math_fwd.hpp>
15 #include <boost/math/tools/config.hpp>
16 #include <boost/math/policies/error_handling.hpp>
17 #include <boost/math/special_functions/fpclassify.hpp>
18 
19 namespace boost{ namespace math{ namespace detail{
20 
21 template <class T, class Policy>
trunc(const T & v,const Policy & pol,const std::false_type &)22 inline typename tools::promote_args<T>::type trunc(const T& v, const Policy& pol, const std::false_type&)
23 {
24    BOOST_MATH_STD_USING
25    typedef typename tools::promote_args<T>::type result_type;
26    if(!(boost::math::isfinite)(v))
27       return policies::raise_rounding_error("boost::math::trunc<%1%>(%1%)", 0, static_cast<result_type>(v), static_cast<result_type>(v), pol);
28    return (v >= 0) ? static_cast<result_type>(floor(v)) : static_cast<result_type>(ceil(v));
29 }
30 
31 template <class T, class Policy>
trunc(const T & v,const Policy &,const std::true_type &)32 inline typename tools::promote_args<T>::type trunc(const T& v, const Policy&, const std::true_type&)
33 {
34    return v;
35 }
36 
37 }
38 
39 template <class T, class Policy>
trunc(const T & v,const Policy & pol)40 inline typename tools::promote_args<T>::type trunc(const T& v, const Policy& pol)
41 {
42    return detail::trunc(v, pol, std::integral_constant<bool, detail::is_integer_for_rounding<T>::value>());
43 }
44 template <class T>
trunc(const T & v)45 inline typename tools::promote_args<T>::type trunc(const T& v)
46 {
47    return trunc(v, policies::policy<>());
48 }
49 //
50 // The following functions will not compile unless T has an
51 // implicit conversion to the integer types.  For user-defined
52 // number types this will likely not be the case.  In that case
53 // these functions should either be specialized for the UDT in
54 // question, or else overloads should be placed in the same
55 // namespace as the UDT: these will then be found via argument
56 // dependent lookup.  See our concept archetypes for examples.
57 //
58 // Non-standard numeric limits syntax "(std::numeric_limits<int>::max)()"
59 // is to avoid macro substiution from MSVC
60 // https://stackoverflow.com/questions/27442885/syntax-error-with-stdnumeric-limitsmax
61 //
62 template <class T, class Policy>
itrunc(const T & v,const Policy & pol)63 inline int itrunc(const T& v, const Policy& pol)
64 {
65    BOOST_MATH_STD_USING
66    typedef typename tools::promote_args<T>::type result_type;
67    result_type r = boost::math::trunc(v, pol);
68    if(r > static_cast<result_type>((std::numeric_limits<int>::max)()) || r < static_cast<result_type>((std::numeric_limits<int>::min)()))
69       return static_cast<int>(policies::raise_rounding_error("boost::math::itrunc<%1%>(%1%)", 0, static_cast<result_type>(v), 0, pol));
70    return static_cast<int>(r);
71 }
72 template <class T>
itrunc(const T & v)73 inline int itrunc(const T& v)
74 {
75    return itrunc(v, policies::policy<>());
76 }
77 
78 template <class T, class Policy>
ltrunc(const T & v,const Policy & pol)79 inline long ltrunc(const T& v, const Policy& pol)
80 {
81    BOOST_MATH_STD_USING
82    typedef typename tools::promote_args<T>::type result_type;
83    result_type r = boost::math::trunc(v, pol);
84    if(r > static_cast<result_type>((std::numeric_limits<long>::max)()) || r < static_cast<result_type>((std::numeric_limits<long>::min)()))
85       return static_cast<long>(policies::raise_rounding_error("boost::math::ltrunc<%1%>(%1%)", 0, static_cast<result_type>(v), 0L, pol));
86    return static_cast<long>(r);
87 }
88 template <class T>
ltrunc(const T & v)89 inline long ltrunc(const T& v)
90 {
91    return ltrunc(v, policies::policy<>());
92 }
93 
94 template <class T, class Policy>
lltrunc(const T & v,const Policy & pol)95 inline long long lltrunc(const T& v, const Policy& pol)
96 {
97    BOOST_MATH_STD_USING
98    typedef typename tools::promote_args<T>::type result_type;
99    result_type r = boost::math::trunc(v, pol);
100    if(r > static_cast<result_type>((std::numeric_limits<long long>::max)()) ||
101       r < static_cast<result_type>((std::numeric_limits<long long>::min)()))
102    {
103       return static_cast<long long>(policies::raise_rounding_error("boost::math::lltrunc<%1%>(%1%)", 0, v, static_cast<long long>(0), pol));
104    }
105    return static_cast<long long>(r);
106 }
107 template <class T>
lltrunc(const T & v)108 inline long long lltrunc(const T& v)
109 {
110    return lltrunc(v, policies::policy<>());
111 }
112 
113 template <class T, class Policy>
114 inline typename std::enable_if<std::is_constructible<int, T>::value, int>::type
iconvert(const T & v,const Policy &)115    iconvert(const T& v, const Policy&)
116 {
117    return static_cast<int>(v);
118 }
119 
120 template <class T, class Policy>
121 inline typename std::enable_if<!std::is_constructible<int, T>::value, int>::type
iconvert(const T & v,const Policy & pol)122    iconvert(const T& v, const Policy& pol)
123 {
124    using boost::math::itrunc;
125    return itrunc(v, pol);
126 }
127 
128 template <class T, class Policy>
129 inline typename std::enable_if<std::is_constructible<long, T>::value, long>::type
lconvert(const T & v,const Policy &)130    lconvert(const T& v, const Policy&)
131 {
132    return static_cast<long>(v);
133 }
134 
135 template <class T, class Policy>
136 inline typename std::enable_if<!std::is_constructible<long, T>::value, long>::type
lconvert(const T & v,const Policy & pol)137    lconvert(const T& v, const Policy& pol)
138 {
139    using boost::math::ltrunc;
140    return ltrunc(v, pol);
141 }
142 
143 template <class T, class Policy>
144 inline typename std::enable_if<std::is_constructible<long long, T>::value, long long>::type
llconvertert(const T & v,const Policy &)145    llconvertert(const T& v, const Policy&)
146 {
147    return static_cast<long long>(v);
148 }
149 
150 template <class T, class Policy>
151 inline typename std::enable_if<!std::is_constructible<long long, T>::value, long long>::type
llconvertert(const T & v,const Policy & pol)152    llconvertert(const T& v, const Policy& pol)
153 {
154    using boost::math::lltrunc;
155    return lltrunc(v, pol);
156 }
157 
158 }} // namespaces
159 
160 #endif // BOOST_MATH_TRUNC_HPP
161