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_ROUND_HPP
7#define BOOST_MATH_ROUND_HPP
8
9#ifdef _MSC_VER
10#pragma once
11#endif
12
13#include <boost/math/tools/config.hpp>
14#include <boost/math/policies/error_handling.hpp>
15#include <boost/math/special_functions/math_fwd.hpp>
16#include <boost/math/special_functions/fpclassify.hpp>
17
18namespace boost{ namespace math{
19
20namespace detail{
21
22template <class T, class Policy>
23inline typename tools::promote_args<T>::type round(const T& v, const Policy& pol, const boost::false_type&)
24{
25 BOOST_MATH_STD_USING
26 typedef typename tools::promote_args<T>::type result_type;
27 if(!(boost::math::isfinite)(v))
28 return policies::raise_rounding_error("boost::math::round<%1%>(%1%)", 0, static_cast<result_type>(v), static_cast<result_type>(v), pol);
29 //
30 // The logic here is rather convoluted, but avoids a number of traps,
31 // see discussion here https://github.com/boostorg/math/pull/8
32 //
33 if (-0.5 < v && v < 0.5)
34 {
35 // special case to avoid rounding error on the direct
36 // predecessor of +0.5 resp. the direct successor of -0.5 in
37 // IEEE floating point types
38 return static_cast<result_type>(0);
39 }
40 else if (v > 0)
41 {
42 // subtract v from ceil(v) first in order to avoid rounding
43 // errors on largest representable integer numbers
44 result_type c(ceil(v));
45 return 0.5 < c - v ? c - 1 : c;
46 }
47 else
48 {
49 // see former branch
50 result_type f(floor(v));
51 return 0.5 < v - f ? f + 1 : f;
52 }
53}
54template <class T, class Policy>
55inline typename tools::promote_args<T>::type round(const T& v, const Policy&, const boost::true_type&)
56{
57 return v;
58}
59
60} // namespace detail
61
62template <class T, class Policy>
63inline typename tools::promote_args<T>::type round(const T& v, const Policy& pol)
64{
65 return detail::round(v, pol, boost::integral_constant<bool, detail::is_integer_for_rounding<T>::value>());
66}
67template <class T>
68inline typename tools::promote_args<T>::type round(const T& v)
69{
70 return round(v, policies::policy<>());
71}
72//
73// The following functions will not compile unless T has an
74// implicit conversion to the integer types. For user-defined
75// number types this will likely not be the case. In that case
76// these functions should either be specialized for the UDT in
77// question, or else overloads should be placed in the same
78// namespace as the UDT: these will then be found via argument
79// dependent lookup. See our concept archetypes for examples.
80//
81template <class T, class Policy>
82inline int iround(const T& v, const Policy& pol)
83{
84 BOOST_MATH_STD_USING
85 T r = boost::math::round(v, pol);
86 if((r > (std::numeric_limits<int>::max)()) || (r < (std::numeric_limits<int>::min)()))
87 return static_cast<int>(policies::raise_rounding_error("boost::math::iround<%1%>(%1%)", 0, v, 0, pol));
88 return static_cast<int>(r);
89}
90template <class T>
91inline int iround(const T& v)
92{
93 return iround(v, policies::policy<>());
94}
95
96template <class T, class Policy>
97inline long lround(const T& v, const Policy& pol)
98{
99 BOOST_MATH_STD_USING
100 T r = boost::math::round(v, pol);
101 if((r > (std::numeric_limits<long>::max)()) || (r < (std::numeric_limits<long>::min)()))
102 return static_cast<long int>(policies::raise_rounding_error("boost::math::lround<%1%>(%1%)", 0, v, 0L, pol));
103 return static_cast<long int>(r);
104}
105template <class T>
106inline long lround(const T& v)
107{
108 return lround(v, policies::policy<>());
109}
110
111#ifdef BOOST_HAS_LONG_LONG
112
113template <class T, class Policy>
114inline boost::long_long_type llround(const T& v, const Policy& pol)
115{
116 BOOST_MATH_STD_USING
117 T r = boost::math::round(v, pol);
118 if((r > (std::numeric_limits<boost::long_long_type>::max)()) || (r < (std::numeric_limits<boost::long_long_type>::min)()))
119 return static_cast<boost::long_long_type>(policies::raise_rounding_error("boost::math::llround<%1%>(%1%)", 0, v, static_cast<boost::long_long_type>(0), pol));
120 return static_cast<boost::long_long_type>(r);
121}
122template <class T>
123inline boost::long_long_type llround(const T& v)
124{
125 return llround(v, policies::policy<>());
126}
127
128#endif
129
130}} // namespaces
131
132#endif // BOOST_MATH_ROUND_HPP
133

source code of include/boost/math/special_functions/round.hpp