floor.hpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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. #ifndef BOOST_MATH_CCMATH_FLOOR_HPP
  6. #define BOOST_MATH_CCMATH_FLOOR_HPP
  7. #include <boost/math/ccmath/detail/config.hpp>
  8. #ifdef BOOST_MATH_NO_CCMATH
  9. #error "The header <boost/math/floor.hpp> can only be used in C++17 and later."
  10. #endif
  11. #include <boost/math/ccmath/abs.hpp>
  12. #include <boost/math/ccmath/isinf.hpp>
  13. #include <boost/math/ccmath/isnan.hpp>
  14. #include <limits>
  15. namespace boost::math::ccmath {
  16. namespace detail {
  17. template <typename T>
  18. inline constexpr T floor_pos_impl(T arg) noexcept
  19. {
  20. constexpr auto max_comp_val = T(1) / std::numeric_limits<T>::epsilon();
  21. if (arg >= max_comp_val)
  22. {
  23. return arg;
  24. }
  25. T result = 1;
  26. if(result < arg)
  27. {
  28. while(result < arg)
  29. {
  30. result *= 2;
  31. }
  32. while(result > arg)
  33. {
  34. --result;
  35. }
  36. return result;
  37. }
  38. else
  39. {
  40. return T(0);
  41. }
  42. }
  43. template <typename T>
  44. inline constexpr T floor_neg_impl(T arg) noexcept
  45. {
  46. T result = -1;
  47. if(result > arg)
  48. {
  49. while(result > arg)
  50. {
  51. result *= 2;
  52. }
  53. while(result < arg)
  54. {
  55. ++result;
  56. }
  57. if(result != arg)
  58. {
  59. --result;
  60. }
  61. }
  62. return result;
  63. }
  64. template <typename T>
  65. inline constexpr T floor_impl(T arg) noexcept
  66. {
  67. if(arg > 0)
  68. {
  69. return floor_pos_impl(arg);
  70. }
  71. else
  72. {
  73. return floor_neg_impl(arg);
  74. }
  75. }
  76. } // Namespace detail
  77. template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
  78. inline constexpr Real floor(Real arg) noexcept
  79. {
  80. if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
  81. {
  82. return boost::math::ccmath::abs(arg) == Real(0) ? arg :
  83. boost::math::ccmath::isinf(arg) ? arg :
  84. boost::math::ccmath::isnan(arg) ? arg :
  85. boost::math::ccmath::detail::floor_impl(arg);
  86. }
  87. else
  88. {
  89. using std::floor;
  90. return floor(arg);
  91. }
  92. }
  93. template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
  94. inline constexpr double floor(Z arg) noexcept
  95. {
  96. return boost::math::ccmath::floor(static_cast<double>(arg));
  97. }
  98. inline constexpr float floorf(float arg) noexcept
  99. {
  100. return boost::math::ccmath::floor(arg);
  101. }
  102. #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
  103. inline constexpr long double floorl(long double arg) noexcept
  104. {
  105. return boost::math::ccmath::floor(arg);
  106. }
  107. #endif
  108. } // Namespaces
  109. #endif // BOOST_MATH_CCMATH_FLOOR_HPP