386 lines · plain
1// Copyright John Maddock 2007.2// Copyright Matt Borland 2023.3// Use, modification and distribution are subject to the4// Boost Software License, Version 1.0. (See accompanying file5// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)6 7#ifndef BOOST_MATH_TRUNC_HPP8#define BOOST_MATH_TRUNC_HPP9 10#ifdef _MSC_VER11#pragma once12#endif13 14#include <boost/math/tools/config.hpp>15#include <boost/math/tools/type_traits.hpp>16#include <boost/math/tools/numeric_limits.hpp>17 18#ifndef BOOST_MATH_HAS_NVRTC19 20#include <type_traits>21#include <boost/math/special_functions/math_fwd.hpp>22#include <boost/math/ccmath/detail/config.hpp>23#include <boost/math/policies/error_handling.hpp>24#include <boost/math/special_functions/fpclassify.hpp>25#include <boost/math/tools/is_constant_evaluated.hpp>26 27#if !defined(BOOST_MATH_NO_CCMATH) && !defined(BOOST_MATH_NO_CONSTEXPR_DETECTION)28#include <boost/math/ccmath/ldexp.hpp>29# define BOOST_MATH_HAS_CONSTEXPR_LDEXP30#endif31 32namespace boost{ namespace math{ namespace detail{33 34template <class T, class Policy>35BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T> trunc(const T& v, const Policy& pol, const std::false_type&)36{37 BOOST_MATH_STD_USING38 using result_type = tools::promote_args_t<T>;39 if(!(boost::math::isfinite)(v))40 {41 return policies::raise_rounding_error("boost::math::trunc<%1%>(%1%)", nullptr, static_cast<result_type>(v), static_cast<result_type>(v), pol);42 }43 return (v >= 0) ? static_cast<result_type>(floor(v)) : static_cast<result_type>(ceil(v));44}45 46template <class T, class Policy>47BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T> trunc(const T& v, const Policy&, const std::true_type&)48{49 return v;50}51 52} // Namespace detail53 54template <class T, class Policy>55BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T> trunc(const T& v, const Policy& pol)56{57 return detail::trunc(v, pol, std::integral_constant<bool, detail::is_integer_for_rounding<T>::value>());58}59 60template <class T>61BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T> trunc(const T& v)62{63 return trunc(v, policies::policy<>());64}65 66#else // Special handling for nvrtc67 68namespace boost {69namespace math {70 71namespace detail {72 73template <typename T>74BOOST_MATH_GPU_ENABLED double trunc_impl(T x)75{76 return static_cast<double>(x);77}78 79BOOST_MATH_GPU_ENABLED inline float trunc_impl(float x)80{81 return ::truncf(x);82}83 84BOOST_MATH_GPU_ENABLED inline double trunc_impl(double x)85{86 return ::trunc(x);87}88 89} // Namespace detail90 91template <typename T, typename Policy>92BOOST_MATH_GPU_ENABLED auto trunc(T x, const Policy&)93{94 return detail::trunc_impl(x);95}96 97template <typename T>98BOOST_MATH_GPU_ENABLED auto trunc(T x)99{100 return detail::trunc_impl(x);101}102 103#endif104 105#ifndef BOOST_MATH_HAS_NVRTC106 107//108// The following functions will not compile unless T has an109// implicit conversion to the integer types. For user-defined110// number types this will likely not be the case. In that case111// these functions should either be specialized for the UDT in112// question, or else overloads should be placed in the same113// namespace as the UDT: these will then be found via argument114// dependent lookup. See our concept archetypes for examples.115//116// Non-standard numeric limits syntax "(std::numeric_limits<int>::max)()"117// is to avoid macro substiution from MSVC118// https://stackoverflow.com/questions/27442885/syntax-error-with-stdnumeric-limitsmax119//120template <class T, class Policy>121BOOST_MATH_GPU_ENABLED inline int itrunc(const T& v, const Policy& pol)122{123 BOOST_MATH_STD_USING124 using result_type = tools::promote_args_t<T>;125 result_type r = boost::math::trunc(v, pol);126 127 #if defined(BOOST_MATH_HAS_CONSTEXPR_LDEXP) && !defined(BOOST_MATH_HAS_GPU_SUPPORT)128 if constexpr (std::is_arithmetic_v<result_type>129 #ifdef BOOST_MATH_FLOAT128_TYPE130 && !std::is_same_v<BOOST_MATH_FLOAT128_TYPE, result_type>131 #endif132 )133 {134 constexpr result_type max_val = boost::math::ccmath::ldexp(static_cast<result_type>(1), std::numeric_limits<int>::digits);135 136 if (r >= max_val || r < -max_val)137 {138 return static_cast<int>(boost::math::policies::raise_rounding_error("boost::math::itrunc<%1%>(%1%)", nullptr, v, static_cast<int>(0), pol));139 }140 }141 else142 {143 static const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<int>::digits);144 145 if (r >= max_val || r < -max_val)146 {147 return static_cast<int>(boost::math::policies::raise_rounding_error("boost::math::itrunc<%1%>(%1%)", nullptr, v, static_cast<int>(0), pol));148 }149 }150 #else151 BOOST_MATH_STATIC_LOCAL_VARIABLE const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<int>::digits);152 153 if (r >= max_val || r < -max_val)154 {155 return static_cast<int>(boost::math::policies::raise_rounding_error("boost::math::itrunc<%1%>(%1%)", nullptr, v, static_cast<int>(0), pol));156 }157 #endif158 159 return static_cast<int>(r);160}161 162template <class T>163BOOST_MATH_GPU_ENABLED inline int itrunc(const T& v)164{165 return itrunc(v, policies::policy<>());166}167 168template <class T, class Policy>169BOOST_MATH_GPU_ENABLED inline long ltrunc(const T& v, const Policy& pol)170{171 BOOST_MATH_STD_USING172 using result_type = tools::promote_args_t<T>;173 result_type r = boost::math::trunc(v, pol);174 175 #if defined(BOOST_MATH_HAS_CONSTEXPR_LDEXP) && !defined(BOOST_MATH_HAS_GPU_SUPPORT)176 if constexpr (std::is_arithmetic_v<result_type>177 #ifdef BOOST_MATH_FLOAT128_TYPE178 && !std::is_same_v<BOOST_MATH_FLOAT128_TYPE, result_type>179 #endif180 )181 {182 constexpr result_type max_val = boost::math::ccmath::ldexp(static_cast<result_type>(1), std::numeric_limits<long>::digits);183 184 if (r >= max_val || r < -max_val)185 {186 return static_cast<long>(boost::math::policies::raise_rounding_error("boost::math::ltrunc<%1%>(%1%)", nullptr, v, static_cast<long>(0), pol));187 }188 }189 else190 {191 static const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<long>::digits);192 193 if (r >= max_val || r < -max_val)194 {195 return static_cast<long>(boost::math::policies::raise_rounding_error("boost::math::ltrunc<%1%>(%1%)", nullptr, v, static_cast<long>(0), pol));196 }197 }198 #else199 BOOST_MATH_STATIC_LOCAL_VARIABLE const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<long>::digits);200 201 if (r >= max_val || r < -max_val)202 {203 return static_cast<long>(boost::math::policies::raise_rounding_error("boost::math::ltrunc<%1%>(%1%)", nullptr, v, static_cast<long>(0), pol));204 }205 #endif206 207 return static_cast<long>(r);208}209 210template <class T>211BOOST_MATH_GPU_ENABLED inline long ltrunc(const T& v)212{213 return ltrunc(v, policies::policy<>());214}215 216template <class T, class Policy>217BOOST_MATH_GPU_ENABLED inline long long lltrunc(const T& v, const Policy& pol)218{219 BOOST_MATH_STD_USING220 using result_type = tools::promote_args_t<T>;221 result_type r = boost::math::trunc(v, pol);222 223 #if defined(BOOST_MATH_HAS_CONSTEXPR_LDEXP) && !defined(BOOST_MATH_HAS_GPU_SUPPORT)224 if constexpr (std::is_arithmetic_v<result_type>225 #ifdef BOOST_MATH_FLOAT128_TYPE226 && !std::is_same_v<BOOST_MATH_FLOAT128_TYPE, result_type>227 #endif228 )229 {230 constexpr result_type max_val = boost::math::ccmath::ldexp(static_cast<result_type>(1), std::numeric_limits<long long>::digits);231 232 if (r >= max_val || r < -max_val)233 {234 return static_cast<long long>(boost::math::policies::raise_rounding_error("boost::math::lltrunc<%1%>(%1%)", nullptr, v, static_cast<long long>(0), pol));235 }236 }237 else238 {239 static const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<long long>::digits);240 241 if (r >= max_val || r < -max_val)242 {243 return static_cast<long long>(boost::math::policies::raise_rounding_error("boost::math::lltrunc<%1%>(%1%)", nullptr, v, static_cast<long long>(0), pol));244 }245 }246 #else247 BOOST_MATH_STATIC_LOCAL_VARIABLE const result_type max_val = ldexp(static_cast<result_type>(1), std::numeric_limits<long long>::digits);248 249 if (r >= max_val || r < -max_val)250 {251 return static_cast<long long>(boost::math::policies::raise_rounding_error("boost::math::lltrunc<%1%>(%1%)", nullptr, v, static_cast<long long>(0), pol));252 }253 #endif254 255 return static_cast<long long>(r);256}257 258template <class T>259BOOST_MATH_GPU_ENABLED inline long long lltrunc(const T& v)260{261 return lltrunc(v, policies::policy<>());262}263 264#else // Reduced impl specifically for NVRTC platform265 266namespace detail {267 268template <typename TargetType, typename T>269BOOST_MATH_GPU_ENABLED TargetType integer_trunc_impl(T v)270{271 double r = boost::math::trunc(v);272 273 const double max_val = ldexp(1.0, boost::math::numeric_limits<TargetType>::digits);274 275 if (r >= max_val || r < -max_val)276 {277 r = 0;278 }279 280 return static_cast<TargetType>(r);281}282 283} // Namespace detail284 285template <typename T>286BOOST_MATH_GPU_ENABLED int itrunc(T v)287{288 return detail::integer_trunc_impl<int>(v);289}290 291template <typename T, typename Policy>292BOOST_MATH_GPU_ENABLED int itrunc(T v, const Policy&)293{294 return detail::integer_trunc_impl<int>(v);295}296 297template <typename T>298BOOST_MATH_GPU_ENABLED long ltrunc(T v)299{300 return detail::integer_trunc_impl<long>(v);301}302 303template <typename T, typename Policy>304BOOST_MATH_GPU_ENABLED long ltrunc(T v, const Policy&)305{306 return detail::integer_trunc_impl<long>(v);307}308 309template <typename T>310BOOST_MATH_GPU_ENABLED long long lltrunc(T v)311{312 return detail::integer_trunc_impl<long long>(v);313}314 315template <typename T, typename Policy>316BOOST_MATH_GPU_ENABLED long long lltrunc(T v, const Policy&)317{318 return detail::integer_trunc_impl<long long>(v);319}320 321#endif // BOOST_MATH_HAS_NVRTC322 323template <class T, class Policy>324BOOST_MATH_GPU_ENABLED inline boost::math::enable_if_t<boost::math::is_constructible_v<int, T>, int>325 iconvert(const T& v, const Policy&)326{327 return static_cast<int>(v);328}329 330template <class T, class Policy>331BOOST_MATH_GPU_ENABLED inline boost::math::enable_if_t<!boost::math::is_constructible_v<int, T>, int>332 iconvert(const T& v, const Policy& pol)333{334 using boost::math::itrunc;335 return itrunc(v, pol);336}337 338template <class T, class Policy>339BOOST_MATH_GPU_ENABLED inline boost::math::enable_if_t<boost::math::is_constructible_v<long, T>, long>340 lconvert(const T& v, const Policy&)341{342 return static_cast<long>(v);343}344 345template <class T, class Policy>346BOOST_MATH_GPU_ENABLED inline boost::math::enable_if_t<!boost::math::is_constructible_v<long, T>, long>347 lconvert(const T& v, const Policy& pol)348{349 using boost::math::ltrunc;350 return ltrunc(v, pol);351}352 353template <class T, class Policy>354BOOST_MATH_GPU_ENABLED inline boost::math::enable_if_t<boost::math::is_constructible_v<long long, T>, long long>355 llconvert(const T& v, const Policy&)356{357 return static_cast<long long>(v);358}359 360template <class T, class Policy>361BOOST_MATH_GPU_ENABLED inline typename boost::math::enable_if_t<!boost::math::is_constructible_v<long long, T>, long long>362 llconvert(const T& v, const Policy& pol)363{364 using boost::math::lltrunc;365 return lltrunc(v, pol);366}367 368template <class T, class Policy>369BOOST_MATH_GPU_ENABLED [[deprecated("Use llconvert")]] inline boost::math::enable_if_t<boost::math::is_constructible_v<long long, T>, long long>370 llconvertert(const T& v, const Policy&)371{372 return static_cast<long long>(v);373}374 375template <class T, class Policy>376BOOST_MATH_GPU_ENABLED [[deprecated("Use llconvert")]] inline typename boost::math::enable_if_t<!boost::math::is_constructible_v<long long, T>, long long>377 llconvertert(const T& v, const Policy& pol)378{379 using boost::math::lltrunc;380 return lltrunc(v, pol);381}382 383}} // namespaces384 385#endif // BOOST_MATH_TRUNC_HPP386