1// Copyright John Maddock 2007.
2// Copyright Matt Borland 2023.
3// Use, modification and distribution are subject to the
4// Boost Software License, Version 1.0. (See accompanying file
5// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7#ifndef BOOST_MATH_TRUNC_HPP
8#define BOOST_MATH_TRUNC_HPP
9
10#ifdef _MSC_VER
11#pragma once
12#endif
13
14#include <type_traits>
15#include <boost/math/special_functions/math_fwd.hpp>
16#include <boost/math/tools/config.hpp>
17#include <boost/math/ccmath/detail/config.hpp>
18#include <boost/math/policies/error_handling.hpp>
19#include <boost/math/special_functions/fpclassify.hpp>
20#include <boost/math/tools/is_constant_evaluated.hpp>
21
22#if !defined(BOOST_MATH_NO_CCMATH) && !defined(BOOST_MATH_NO_CONSTEXPR_DETECTION)
23#include <boost/math/ccmath/ldexp.hpp>
24# define BOOST_MATH_HAS_CONSTEXPR_LDEXP
25#endif
26
27namespace boost{ namespace math{ namespace detail{
28
29template <class T, class Policy>
30inline tools::promote_args_t<T> trunc(const T& v, const Policy& pol, const std::false_type&)
31{
32 BOOST_MATH_STD_USING
33 using result_type = tools::promote_args_t<T>;
34 if(!(boost::math::isfinite)(v))
35 {
36 return policies::raise_rounding_error("boost::math::trunc<%1%>(%1%)", nullptr, static_cast<result_type>(v), static_cast<result_type>(v), pol);
37 }
38 return (v >= 0) ? static_cast<result_type>(floor(v)) : static_cast<result_type>(ceil(v));
39}
40
41template <class T, class Policy>
42inline tools::promote_args_t<T> trunc(const T& v, const Policy&, const std::true_type&)
43{
44 return v;
45}
46
47}
48
49template <class T, class Policy>
50inline tools::promote_args_t<T> trunc(const T& v, const Policy& pol)
51{
52 return detail::trunc(v, pol, std::integral_constant<bool, detail::is_integer_for_rounding<T>::value>());
53}
54template <class T>
55inline tools::promote_args_t<T> trunc(const T& v)
56{
57 return trunc(v, policies::policy<>());
58}
59//
60// The following functions will not compile unless T has an
61// implicit conversion to the integer types. For user-defined
62// number types this will likely not be the case. In that case
63// these functions should either be specialized for the UDT in
64// question, or else overloads should be placed in the same
65// namespace as the UDT: these will then be found via argument
66// dependent lookup. See our concept archetypes for examples.
67//
68// Non-standard numeric limits syntax "(std::numeric_limits<int>::max)()"
69// is to avoid macro substiution from MSVC
70// https://stackoverflow.com/questions/27442885/syntax-error-with-stdnumeric-limitsmax
71//
72template <class T, class Policy>
73inline int itrunc(const T& v, const Policy& pol)
74{
75 BOOST_MATH_STD_USING
76 using result_type = tools::promote_args_t<T>;
77 result_type r = boost::math::trunc(v, pol);
78
79 #ifdef BOOST_MATH_HAS_CONSTEXPR_LDEXP
80 if constexpr (std::is_arithmetic_v<result_type>
81 #ifdef BOOST_MATH_FLOAT128_TYPE
82 && !std::is_same_v<BOOST_MATH_FLOAT128_TYPE, result_type>
83 #endif
84 )
85 {
86 constexpr result_type max_val = boost::math::ccmath::ldexp(static_cast<result_type>(1), std::numeric_limits<int>::digits);
87
88 if (r >= max_val || r < -max_val)
89 {
90 return static_cast<int>(boost::math::policies::raise_rounding_error("boost::math::itrunc<%1%>(%1%)", nullptr, v, static_cast<int>(0), pol));
91 }
92 }
93 else
94 {
95 static const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<int>::digits);
96
97 if (r >= max_val || r < -max_val)
98 {
99 return static_cast<int>(boost::math::policies::raise_rounding_error("boost::math::itrunc<%1%>(%1%)", nullptr, v, static_cast<int>(0), pol));
100 }
101 }
102 #else
103 static const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<int>::digits);
104
105 if (r >= max_val || r < -max_val)
106 {
107 return static_cast<int>(boost::math::policies::raise_rounding_error("boost::math::itrunc<%1%>(%1%)", nullptr, v, static_cast<int>(0), pol));
108 }
109 #endif
110
111 return static_cast<int>(r);
112}
113template <class T>
114inline int itrunc(const T& v)
115{
116 return itrunc(v, policies::policy<>());
117}
118
119template <class T, class Policy>
120inline long ltrunc(const T& v, const Policy& pol)
121{
122 BOOST_MATH_STD_USING
123 using result_type = tools::promote_args_t<T>;
124 result_type r = boost::math::trunc(v, pol);
125
126 #ifdef BOOST_MATH_HAS_CONSTEXPR_LDEXP
127 if constexpr (std::is_arithmetic_v<result_type>
128 #ifdef BOOST_MATH_FLOAT128_TYPE
129 && !std::is_same_v<BOOST_MATH_FLOAT128_TYPE, result_type>
130 #endif
131 )
132 {
133 constexpr result_type max_val = boost::math::ccmath::ldexp(static_cast<result_type>(1), std::numeric_limits<long>::digits);
134
135 if (r >= max_val || r < -max_val)
136 {
137 return static_cast<long>(boost::math::policies::raise_rounding_error("boost::math::ltrunc<%1%>(%1%)", nullptr, v, static_cast<long>(0), pol));
138 }
139 }
140 else
141 {
142 static const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<long>::digits);
143
144 if (r >= max_val || r < -max_val)
145 {
146 return static_cast<long>(boost::math::policies::raise_rounding_error("boost::math::ltrunc<%1%>(%1%)", nullptr, v, static_cast<long>(0), pol));
147 }
148 }
149 #else
150 static const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<long>::digits);
151
152 if (r >= max_val || r < -max_val)
153 {
154 return static_cast<long>(boost::math::policies::raise_rounding_error("boost::math::ltrunc<%1%>(%1%)", nullptr, v, static_cast<long>(0), pol));
155 }
156 #endif
157
158 return static_cast<long>(r);
159}
160template <class T>
161inline long ltrunc(const T& v)
162{
163 return ltrunc(v, policies::policy<>());
164}
165
166template <class T, class Policy>
167inline long long lltrunc(const T& v, const Policy& pol)
168{
169 BOOST_MATH_STD_USING
170 using result_type = tools::promote_args_t<T>;
171 result_type r = boost::math::trunc(v, pol);
172
173 #ifdef BOOST_MATH_HAS_CONSTEXPR_LDEXP
174 if constexpr (std::is_arithmetic_v<result_type>
175 #ifdef BOOST_MATH_FLOAT128_TYPE
176 && !std::is_same_v<BOOST_MATH_FLOAT128_TYPE, result_type>
177 #endif
178 )
179 {
180 constexpr result_type max_val = boost::math::ccmath::ldexp(static_cast<result_type>(1), std::numeric_limits<long long>::digits);
181
182 if (r >= max_val || r < -max_val)
183 {
184 return static_cast<long long>(boost::math::policies::raise_rounding_error("boost::math::lltrunc<%1%>(%1%)", nullptr, v, static_cast<long long>(0), pol));
185 }
186 }
187 else
188 {
189 static const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<long long>::digits);
190
191 if (r >= max_val || r < -max_val)
192 {
193 return static_cast<long long>(boost::math::policies::raise_rounding_error("boost::math::lltrunc<%1%>(%1%)", nullptr, v, static_cast<long long>(0), pol));
194 }
195 }
196 #else
197 static const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<long long>::digits);
198
199 if (r >= max_val || r < -max_val)
200 {
201 return static_cast<long long>(boost::math::policies::raise_rounding_error("boost::math::lltrunc<%1%>(%1%)", nullptr, v, static_cast<long long>(0), pol));
202 }
203 #endif
204
205 return static_cast<long long>(r);
206}
207template <class T>
208inline long long lltrunc(const T& v)
209{
210 return lltrunc(v, policies::policy<>());
211}
212
213template <class T, class Policy>
214inline typename std::enable_if<std::is_constructible<int, T>::value, int>::type
215 iconvert(const T& v, const Policy&)
216{
217 return static_cast<int>(v);
218}
219
220template <class T, class Policy>
221inline typename std::enable_if<!std::is_constructible<int, T>::value, int>::type
222 iconvert(const T& v, const Policy& pol)
223{
224 using boost::math::itrunc;
225 return itrunc(v, pol);
226}
227
228template <class T, class Policy>
229inline typename std::enable_if<std::is_constructible<long, T>::value, long>::type
230 lconvert(const T& v, const Policy&)
231{
232 return static_cast<long>(v);
233}
234
235template <class T, class Policy>
236inline typename std::enable_if<!std::is_constructible<long, T>::value, long>::type
237 lconvert(const T& v, const Policy& pol)
238{
239 using boost::math::ltrunc;
240 return ltrunc(v, pol);
241}
242
243template <class T, class Policy>
244inline typename std::enable_if<std::is_constructible<long long, T>::value, long long>::type
245 llconvertert(const T& v, const Policy&)
246{
247 return static_cast<long long>(v);
248}
249
250template <class T, class Policy>
251inline typename std::enable_if<!std::is_constructible<long long, T>::value, long long>::type
252 llconvertert(const T& v, const Policy& pol)
253{
254 using boost::math::lltrunc;
255 return lltrunc(v, pol);
256}
257
258}} // namespaces
259
260#endif // BOOST_MATH_TRUNC_HPP
261

source code of boost/libs/math/include/boost/math/special_functions/trunc.hpp