]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | // (C) Copyright Matt Borland 2021. |
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_CCMATH_FLOOR_HPP | |
7 | #define BOOST_MATH_CCMATH_FLOOR_HPP | |
8 | ||
9 | #include <cmath> | |
10 | #include <limits> | |
11 | #include <type_traits> | |
12 | #include <boost/math/tools/is_constant_evaluated.hpp> | |
13 | #include <boost/math/ccmath/abs.hpp> | |
14 | #include <boost/math/ccmath/isinf.hpp> | |
15 | #include <boost/math/ccmath/isnan.hpp> | |
16 | ||
17 | namespace boost::math::ccmath { | |
18 | ||
19 | namespace detail { | |
20 | ||
21 | template <typename T> | |
22 | inline constexpr T floor_pos_impl(T arg) noexcept | |
23 | { | |
24 | T result = 1; | |
25 | ||
26 | if(result < arg) | |
27 | { | |
28 | while(result < arg) | |
29 | { | |
30 | result *= 2; | |
31 | } | |
32 | while(result > arg) | |
33 | { | |
34 | --result; | |
35 | } | |
36 | ||
37 | return result; | |
38 | } | |
39 | else | |
40 | { | |
41 | return T(0); | |
42 | } | |
43 | } | |
44 | ||
45 | template <typename T> | |
46 | inline constexpr T floor_neg_impl(T arg) noexcept | |
47 | { | |
48 | T result = -1; | |
49 | ||
50 | if(result > arg) | |
51 | { | |
52 | while(result > arg) | |
53 | { | |
54 | result *= 2; | |
55 | } | |
56 | while(result < arg) | |
57 | { | |
58 | ++result; | |
59 | } | |
60 | if(result != arg) | |
61 | { | |
62 | --result; | |
63 | } | |
64 | } | |
65 | ||
66 | return result; | |
67 | } | |
68 | ||
69 | template <typename T> | |
70 | inline constexpr T floor_impl(T arg) noexcept | |
71 | { | |
72 | if(arg > 0) | |
73 | { | |
74 | return floor_pos_impl(arg); | |
75 | } | |
76 | else | |
77 | { | |
78 | return floor_neg_impl(arg); | |
79 | } | |
80 | } | |
81 | ||
82 | } // Namespace detail | |
83 | ||
84 | template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true> | |
85 | inline constexpr Real floor(Real arg) noexcept | |
86 | { | |
87 | if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg)) | |
88 | { | |
89 | return boost::math::ccmath::abs(arg) == Real(0) ? arg : | |
90 | boost::math::ccmath::isinf(arg) ? arg : | |
91 | boost::math::ccmath::isnan(arg) ? arg : | |
92 | boost::math::ccmath::detail::floor_impl(arg); | |
93 | } | |
94 | else | |
95 | { | |
96 | using std::floor; | |
97 | return floor(arg); | |
98 | } | |
99 | } | |
100 | ||
101 | template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true> | |
102 | inline constexpr double floor(Z arg) noexcept | |
103 | { | |
104 | return boost::math::ccmath::floor(static_cast<double>(arg)); | |
105 | } | |
106 | ||
107 | inline constexpr float floorf(float arg) noexcept | |
108 | { | |
109 | return boost::math::ccmath::floor(arg); | |
110 | } | |
111 | ||
112 | #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS | |
113 | inline constexpr long double floorl(long double arg) noexcept | |
114 | { | |
115 | return boost::math::ccmath::floor(arg); | |
116 | } | |
117 | #endif | |
118 | ||
119 | } // Namespaces | |
120 | ||
121 | #endif // BOOST_MATH_CCMATH_FLOOR_HPP |