trunc.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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. #ifndef BOOST_MATH_TRUNC_HPP
  7. #define BOOST_MATH_TRUNC_HPP
  8. #ifdef _MSC_VER
  9. #pragma once
  10. #endif
  11. #include <boost/math/tools/config.hpp>
  12. #include <boost/math/tools/type_traits.hpp>
  13. #include <boost/math/tools/numeric_limits.hpp>
  14. #ifndef BOOST_MATH_HAS_NVRTC
  15. #include <type_traits>
  16. #include <boost/math/special_functions/math_fwd.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. #if !defined(BOOST_MATH_NO_CCMATH) && !defined(BOOST_MATH_NO_CONSTEXPR_DETECTION)
  22. #include <boost/math/ccmath/ldexp.hpp>
  23. # define BOOST_MATH_HAS_CONSTEXPR_LDEXP
  24. #endif
  25. namespace boost{ namespace math{ namespace detail{
  26. template <class T, class Policy>
  27. BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T> trunc(const T& v, const Policy& pol, const std::false_type&)
  28. {
  29. BOOST_MATH_STD_USING
  30. using result_type = tools::promote_args_t<T>;
  31. if(!(boost::math::isfinite)(v))
  32. {
  33. return policies::raise_rounding_error("boost::math::trunc<%1%>(%1%)", nullptr, static_cast<result_type>(v), static_cast<result_type>(v), pol);
  34. }
  35. return (v >= 0) ? static_cast<result_type>(floor(v)) : static_cast<result_type>(ceil(v));
  36. }
  37. template <class T, class Policy>
  38. BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T> trunc(const T& v, const Policy&, const std::true_type&)
  39. {
  40. return v;
  41. }
  42. } // Namespace detail
  43. template <class T, class Policy>
  44. BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T> trunc(const T& v, const Policy& pol)
  45. {
  46. return detail::trunc(v, pol, std::integral_constant<bool, detail::is_integer_for_rounding<T>::value>());
  47. }
  48. template <class T>
  49. BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T> trunc(const T& v)
  50. {
  51. return trunc(v, policies::policy<>());
  52. }
  53. #else // Special handling for nvrtc
  54. namespace boost {
  55. namespace math {
  56. namespace detail {
  57. template <typename T>
  58. BOOST_MATH_GPU_ENABLED double trunc_impl(T x)
  59. {
  60. return static_cast<double>(x);
  61. }
  62. BOOST_MATH_GPU_ENABLED inline float trunc_impl(float x)
  63. {
  64. return ::truncf(x);
  65. }
  66. BOOST_MATH_GPU_ENABLED inline double trunc_impl(double x)
  67. {
  68. return ::trunc(x);
  69. }
  70. } // Namespace detail
  71. template <typename T, typename Policy>
  72. BOOST_MATH_GPU_ENABLED auto trunc(T x, const Policy&)
  73. {
  74. return detail::trunc_impl(x);
  75. }
  76. template <typename T>
  77. BOOST_MATH_GPU_ENABLED auto trunc(T x)
  78. {
  79. return detail::trunc_impl(x);
  80. }
  81. #endif
  82. #ifndef BOOST_MATH_HAS_NVRTC
  83. //
  84. // The following functions will not compile unless T has an
  85. // implicit conversion to the integer types. For user-defined
  86. // number types this will likely not be the case. In that case
  87. // these functions should either be specialized for the UDT in
  88. // question, or else overloads should be placed in the same
  89. // namespace as the UDT: these will then be found via argument
  90. // dependent lookup. See our concept archetypes for examples.
  91. //
  92. // Non-standard numeric limits syntax "(std::numeric_limits<int>::max)()"
  93. // is to avoid macro substiution from MSVC
  94. // https://stackoverflow.com/questions/27442885/syntax-error-with-stdnumeric-limitsmax
  95. //
  96. template <class T, class Policy>
  97. BOOST_MATH_GPU_ENABLED inline int itrunc(const T& v, const Policy& pol)
  98. {
  99. BOOST_MATH_STD_USING
  100. using result_type = tools::promote_args_t<T>;
  101. result_type r = boost::math::trunc(v, pol);
  102. #if defined(BOOST_MATH_HAS_CONSTEXPR_LDEXP) && !defined(BOOST_MATH_HAS_GPU_SUPPORT)
  103. if constexpr (std::is_arithmetic_v<result_type>
  104. #ifdef BOOST_MATH_FLOAT128_TYPE
  105. && !std::is_same_v<BOOST_MATH_FLOAT128_TYPE, result_type>
  106. #endif
  107. )
  108. {
  109. constexpr result_type max_val = boost::math::ccmath::ldexp(static_cast<result_type>(1), std::numeric_limits<int>::digits);
  110. if (r >= max_val || r < -max_val)
  111. {
  112. return static_cast<int>(boost::math::policies::raise_rounding_error("boost::math::itrunc<%1%>(%1%)", nullptr, v, static_cast<int>(0), pol));
  113. }
  114. }
  115. else
  116. {
  117. static const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<int>::digits);
  118. if (r >= max_val || r < -max_val)
  119. {
  120. return static_cast<int>(boost::math::policies::raise_rounding_error("boost::math::itrunc<%1%>(%1%)", nullptr, v, static_cast<int>(0), pol));
  121. }
  122. }
  123. #else
  124. BOOST_MATH_STATIC_LOCAL_VARIABLE const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<int>::digits);
  125. if (r >= max_val || r < -max_val)
  126. {
  127. return static_cast<int>(boost::math::policies::raise_rounding_error("boost::math::itrunc<%1%>(%1%)", nullptr, v, static_cast<int>(0), pol));
  128. }
  129. #endif
  130. return static_cast<int>(r);
  131. }
  132. template <class T>
  133. BOOST_MATH_GPU_ENABLED inline int itrunc(const T& v)
  134. {
  135. return itrunc(v, policies::policy<>());
  136. }
  137. template <class T, class Policy>
  138. BOOST_MATH_GPU_ENABLED inline long ltrunc(const T& v, const Policy& pol)
  139. {
  140. BOOST_MATH_STD_USING
  141. using result_type = tools::promote_args_t<T>;
  142. result_type r = boost::math::trunc(v, pol);
  143. #if defined(BOOST_MATH_HAS_CONSTEXPR_LDEXP) && !defined(BOOST_MATH_HAS_GPU_SUPPORT)
  144. if constexpr (std::is_arithmetic_v<result_type>
  145. #ifdef BOOST_MATH_FLOAT128_TYPE
  146. && !std::is_same_v<BOOST_MATH_FLOAT128_TYPE, result_type>
  147. #endif
  148. )
  149. {
  150. constexpr result_type max_val = boost::math::ccmath::ldexp(static_cast<result_type>(1), std::numeric_limits<long>::digits);
  151. if (r >= max_val || r < -max_val)
  152. {
  153. return static_cast<long>(boost::math::policies::raise_rounding_error("boost::math::ltrunc<%1%>(%1%)", nullptr, v, static_cast<long>(0), pol));
  154. }
  155. }
  156. else
  157. {
  158. static const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<long>::digits);
  159. if (r >= max_val || r < -max_val)
  160. {
  161. return static_cast<long>(boost::math::policies::raise_rounding_error("boost::math::ltrunc<%1%>(%1%)", nullptr, v, static_cast<long>(0), pol));
  162. }
  163. }
  164. #else
  165. BOOST_MATH_STATIC_LOCAL_VARIABLE const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<long>::digits);
  166. if (r >= max_val || r < -max_val)
  167. {
  168. return static_cast<long>(boost::math::policies::raise_rounding_error("boost::math::ltrunc<%1%>(%1%)", nullptr, v, static_cast<long>(0), pol));
  169. }
  170. #endif
  171. return static_cast<long>(r);
  172. }
  173. template <class T>
  174. BOOST_MATH_GPU_ENABLED inline long ltrunc(const T& v)
  175. {
  176. return ltrunc(v, policies::policy<>());
  177. }
  178. template <class T, class Policy>
  179. BOOST_MATH_GPU_ENABLED inline long long lltrunc(const T& v, const Policy& pol)
  180. {
  181. BOOST_MATH_STD_USING
  182. using result_type = tools::promote_args_t<T>;
  183. result_type r = boost::math::trunc(v, pol);
  184. #if defined(BOOST_MATH_HAS_CONSTEXPR_LDEXP) && !defined(BOOST_MATH_HAS_GPU_SUPPORT)
  185. if constexpr (std::is_arithmetic_v<result_type>
  186. #ifdef BOOST_MATH_FLOAT128_TYPE
  187. && !std::is_same_v<BOOST_MATH_FLOAT128_TYPE, result_type>
  188. #endif
  189. )
  190. {
  191. constexpr result_type max_val = boost::math::ccmath::ldexp(static_cast<result_type>(1), std::numeric_limits<long long>::digits);
  192. if (r >= max_val || r < -max_val)
  193. {
  194. return static_cast<long long>(boost::math::policies::raise_rounding_error("boost::math::lltrunc<%1%>(%1%)", nullptr, v, static_cast<long long>(0), pol));
  195. }
  196. }
  197. else
  198. {
  199. static const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<long long>::digits);
  200. if (r >= max_val || r < -max_val)
  201. {
  202. return static_cast<long long>(boost::math::policies::raise_rounding_error("boost::math::lltrunc<%1%>(%1%)", nullptr, v, static_cast<long long>(0), pol));
  203. }
  204. }
  205. #else
  206. BOOST_MATH_STATIC_LOCAL_VARIABLE const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<long long>::digits);
  207. if (r >= max_val || r < -max_val)
  208. {
  209. return static_cast<long long>(boost::math::policies::raise_rounding_error("boost::math::lltrunc<%1%>(%1%)", nullptr, v, static_cast<long long>(0), pol));
  210. }
  211. #endif
  212. return static_cast<long long>(r);
  213. }
  214. template <class T>
  215. BOOST_MATH_GPU_ENABLED inline long long lltrunc(const T& v)
  216. {
  217. return lltrunc(v, policies::policy<>());
  218. }
  219. #else // Reduced impl specifically for NVRTC platform
  220. namespace detail {
  221. template <typename TargetType, typename T>
  222. BOOST_MATH_GPU_ENABLED TargetType integer_trunc_impl(T v)
  223. {
  224. double r = boost::math::trunc(v);
  225. const double max_val = ldexp(1.0, boost::math::numeric_limits<TargetType>::digits);
  226. if (r >= max_val || r < -max_val)
  227. {
  228. r = 0;
  229. }
  230. return static_cast<TargetType>(r);
  231. }
  232. } // Namespace detail
  233. template <typename T>
  234. BOOST_MATH_GPU_ENABLED int itrunc(T v)
  235. {
  236. return detail::integer_trunc_impl<int>(v);
  237. }
  238. template <typename T, typename Policy>
  239. BOOST_MATH_GPU_ENABLED int itrunc(T v, const Policy&)
  240. {
  241. return detail::integer_trunc_impl<int>(v);
  242. }
  243. template <typename T>
  244. BOOST_MATH_GPU_ENABLED long ltrunc(T v)
  245. {
  246. return detail::integer_trunc_impl<long>(v);
  247. }
  248. template <typename T, typename Policy>
  249. BOOST_MATH_GPU_ENABLED long ltrunc(T v, const Policy&)
  250. {
  251. return detail::integer_trunc_impl<long>(v);
  252. }
  253. template <typename T>
  254. BOOST_MATH_GPU_ENABLED long long lltrunc(T v)
  255. {
  256. return detail::integer_trunc_impl<long long>(v);
  257. }
  258. template <typename T, typename Policy>
  259. BOOST_MATH_GPU_ENABLED long long lltrunc(T v, const Policy&)
  260. {
  261. return detail::integer_trunc_impl<long long>(v);
  262. }
  263. #endif // BOOST_MATH_HAS_NVRTC
  264. template <class T, class Policy>
  265. BOOST_MATH_GPU_ENABLED inline boost::math::enable_if_t<boost::math::is_constructible_v<int, T>, int>
  266. iconvert(const T& v, const Policy&)
  267. {
  268. return static_cast<int>(v);
  269. }
  270. template <class T, class Policy>
  271. BOOST_MATH_GPU_ENABLED inline boost::math::enable_if_t<!boost::math::is_constructible_v<int, T>, int>
  272. iconvert(const T& v, const Policy& pol)
  273. {
  274. using boost::math::itrunc;
  275. return itrunc(v, pol);
  276. }
  277. template <class T, class Policy>
  278. BOOST_MATH_GPU_ENABLED inline boost::math::enable_if_t<boost::math::is_constructible_v<long, T>, long>
  279. lconvert(const T& v, const Policy&)
  280. {
  281. return static_cast<long>(v);
  282. }
  283. template <class T, class Policy>
  284. BOOST_MATH_GPU_ENABLED inline boost::math::enable_if_t<!boost::math::is_constructible_v<long, T>, long>
  285. lconvert(const T& v, const Policy& pol)
  286. {
  287. using boost::math::ltrunc;
  288. return ltrunc(v, pol);
  289. }
  290. template <class T, class Policy>
  291. BOOST_MATH_GPU_ENABLED inline boost::math::enable_if_t<boost::math::is_constructible_v<long long, T>, long long>
  292. llconvert(const T& v, const Policy&)
  293. {
  294. return static_cast<long long>(v);
  295. }
  296. template <class T, class Policy>
  297. BOOST_MATH_GPU_ENABLED inline typename boost::math::enable_if_t<!boost::math::is_constructible_v<long long, T>, long long>
  298. llconvert(const T& v, const Policy& pol)
  299. {
  300. using boost::math::lltrunc;
  301. return lltrunc(v, pol);
  302. }
  303. template <class T, class Policy>
  304. BOOST_MATH_GPU_ENABLED [[deprecated("Use llconvert")]] inline boost::math::enable_if_t<boost::math::is_constructible_v<long long, T>, long long>
  305. llconvertert(const T& v, const Policy&)
  306. {
  307. return static_cast<long long>(v);
  308. }
  309. template <class T, class Policy>
  310. BOOST_MATH_GPU_ENABLED [[deprecated("Use llconvert")]] inline typename boost::math::enable_if_t<!boost::math::is_constructible_v<long long, T>, long long>
  311. llconvertert(const T& v, const Policy& pol)
  312. {
  313. using boost::math::lltrunc;
  314. return lltrunc(v, pol);
  315. }
  316. }} // namespaces
  317. #endif // BOOST_MATH_TRUNC_HPP