next.hpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887
  1. // (C) Copyright John Maddock 2008.
  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_SPECIAL_NEXT_HPP
  6. #define BOOST_MATH_SPECIAL_NEXT_HPP
  7. #ifdef _MSC_VER
  8. #pragma once
  9. #endif
  10. #include <boost/math/tools/config.hpp>
  11. // TODO(mborland): Need to remove recurrsion from these algos
  12. #ifndef BOOST_MATH_HAS_NVRTC
  13. #include <boost/math/special_functions/math_fwd.hpp>
  14. #include <boost/math/policies/error_handling.hpp>
  15. #include <boost/math/special_functions/fpclassify.hpp>
  16. #include <boost/math/special_functions/sign.hpp>
  17. #include <boost/math/special_functions/trunc.hpp>
  18. #include <boost/math/tools/traits.hpp>
  19. #include <type_traits>
  20. #include <cfloat>
  21. #if !defined(_CRAYC) && !defined(__CUDACC__) && (!defined(__GNUC__) || (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ > 3)))
  22. #if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(__SSE2__)
  23. #include "xmmintrin.h"
  24. #define BOOST_MATH_CHECK_SSE2
  25. #endif
  26. #endif
  27. namespace boost{ namespace math{
  28. namespace concepts {
  29. class real_concept;
  30. class std_real_concept;
  31. }
  32. namespace detail{
  33. template <class T>
  34. struct has_hidden_guard_digits;
  35. template <>
  36. struct has_hidden_guard_digits<float> : public std::false_type {};
  37. template <>
  38. struct has_hidden_guard_digits<double> : public std::false_type {};
  39. template <>
  40. struct has_hidden_guard_digits<long double> : public std::false_type {};
  41. #ifdef BOOST_HAS_FLOAT128
  42. template <>
  43. struct has_hidden_guard_digits<__float128> : public std::false_type {};
  44. #endif
  45. template <>
  46. struct has_hidden_guard_digits<boost::math::concepts::real_concept> : public std::false_type {};
  47. template <>
  48. struct has_hidden_guard_digits<boost::math::concepts::std_real_concept> : public std::false_type {};
  49. template <class T, bool b>
  50. struct has_hidden_guard_digits_10 : public std::false_type {};
  51. template <class T>
  52. struct has_hidden_guard_digits_10<T, true> : public std::integral_constant<bool, (std::numeric_limits<T>::digits10 != std::numeric_limits<T>::max_digits10)> {};
  53. template <class T>
  54. struct has_hidden_guard_digits
  55. : public has_hidden_guard_digits_10<T,
  56. std::numeric_limits<T>::is_specialized
  57. && (std::numeric_limits<T>::radix == 10) >
  58. {};
  59. template <class T>
  60. inline const T& normalize_value(const T& val, const std::false_type&) { return val; }
  61. template <class T>
  62. inline T normalize_value(const T& val, const std::true_type&)
  63. {
  64. static_assert(std::numeric_limits<T>::is_specialized, "Type T must be specialized.");
  65. static_assert(std::numeric_limits<T>::radix != 2, "Type T must be specialized.");
  66. std::intmax_t shift = (std::intmax_t)std::numeric_limits<T>::digits - (std::intmax_t)ilogb(val) - 1;
  67. T result = scalbn(val, shift);
  68. result = round(result);
  69. return scalbn(result, -shift);
  70. }
  71. template <class T>
  72. inline T get_smallest_value(std::true_type const&) {
  73. static_assert(std::numeric_limits<T>::is_specialized, "Type T must be specialized.");
  74. //
  75. // numeric_limits lies about denorms being present - particularly
  76. // when this can be turned on or off at runtime, as is the case
  77. // when using the SSE2 registers in DAZ or FTZ mode.
  78. //
  79. static const T m = std::numeric_limits<T>::denorm_min();
  80. #ifdef BOOST_MATH_CHECK_SSE2
  81. return (_mm_getcsr() & (_MM_FLUSH_ZERO_ON | 0x40)) ? tools::min_value<T>() : m;
  82. #else
  83. return ((tools::min_value<T>() / 2) == 0) ? tools::min_value<T>() : m;
  84. #endif
  85. }
  86. template <class T>
  87. inline T get_smallest_value(std::false_type const&)
  88. {
  89. return tools::min_value<T>();
  90. }
  91. template <class T>
  92. inline T get_smallest_value()
  93. {
  94. return get_smallest_value<T>(std::integral_constant<bool, std::numeric_limits<T>::is_specialized>());
  95. }
  96. template <class T>
  97. inline bool has_denorm_now() {
  98. return get_smallest_value<T>() < tools::min_value<T>();
  99. }
  100. //
  101. // Returns the smallest value that won't generate denorms when
  102. // we calculate the value of the least-significant-bit:
  103. //
  104. template <class T>
  105. T get_min_shift_value();
  106. template <class T>
  107. inline T calc_min_shifted(const std::true_type&)
  108. {
  109. BOOST_MATH_STD_USING
  110. return ldexp(tools::min_value<T>(), tools::digits<T>() + 1);
  111. }
  112. template <class T>
  113. inline T calc_min_shifted(const std::false_type&)
  114. {
  115. static_assert(std::numeric_limits<T>::is_specialized, "Type T must be specialized.");
  116. static_assert(std::numeric_limits<T>::radix != 2, "Type T must be specialized.");
  117. return scalbn(tools::min_value<T>(), std::numeric_limits<T>::digits + 1);
  118. }
  119. template <class T>
  120. inline T get_min_shift_value()
  121. {
  122. static const T val = calc_min_shifted<T>(std::integral_constant<bool, !std::numeric_limits<T>::is_specialized || std::numeric_limits<T>::radix == 2>());
  123. return val;
  124. }
  125. template <class T, bool b = boost::math::tools::detail::has_backend_type<T>::value>
  126. struct exponent_type
  127. {
  128. typedef int type;
  129. };
  130. template <class T>
  131. struct exponent_type<T, true>
  132. {
  133. typedef typename T::backend_type::exponent_type type;
  134. };
  135. template <class T, class Policy>
  136. T float_next_imp(const T& val, const std::true_type&, const Policy& pol)
  137. {
  138. typedef typename exponent_type<T>::type exponent_type;
  139. BOOST_MATH_STD_USING
  140. exponent_type expon;
  141. static const char* function = "float_next<%1%>(%1%)";
  142. int fpclass = (boost::math::fpclassify)(val);
  143. if (fpclass == (int)FP_INFINITE)
  144. {
  145. if (val < 0)
  146. return -tools::max_value<T>();
  147. return val; // +INF
  148. }
  149. else if (fpclass == (int)FP_NAN)
  150. {
  151. return policies::raise_domain_error<T>(
  152. function,
  153. "Argument must be finite, but got %1%", val, pol);
  154. }
  155. if(val >= tools::max_value<T>())
  156. return policies::raise_overflow_error<T>(function, nullptr, pol);
  157. if(val == 0)
  158. return detail::get_smallest_value<T>();
  159. if((fpclass != (int)FP_SUBNORMAL) && (fpclass != (int)FP_ZERO) && (fabs(val) < detail::get_min_shift_value<T>()) && (val != -tools::min_value<T>()))
  160. {
  161. //
  162. // Special case: if the value of the least significant bit is a denorm, and the result
  163. // would not be a denorm, then shift the input, increment, and shift back.
  164. // This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
  165. //
  166. return ldexp(float_next(T(ldexp(val, 2 * tools::digits<T>())), pol), -2 * tools::digits<T>());
  167. }
  168. if(-0.5f == frexp(val, &expon))
  169. --expon; // reduce exponent when val is a power of two, and negative.
  170. T diff = ldexp(T(1), expon - tools::digits<T>());
  171. if(diff == 0)
  172. diff = detail::get_smallest_value<T>();
  173. return val + diff;
  174. } // float_next_imp
  175. //
  176. // Special version for some base other than 2:
  177. //
  178. template <class T, class Policy>
  179. T float_next_imp(const T& val, const std::false_type&, const Policy& pol)
  180. {
  181. typedef typename exponent_type<T>::type exponent_type;
  182. static_assert(std::numeric_limits<T>::is_specialized, "Type T must be specialized.");
  183. static_assert(std::numeric_limits<T>::radix != 2, "Type T must be specialized.");
  184. BOOST_MATH_STD_USING
  185. exponent_type expon;
  186. static const char* function = "float_next<%1%>(%1%)";
  187. int fpclass = (boost::math::fpclassify)(val);
  188. if (fpclass == (int)FP_INFINITE)
  189. {
  190. if (val < 0)
  191. return -tools::max_value<T>();
  192. return val; // +INF
  193. }
  194. else if (fpclass == (int)FP_NAN)
  195. {
  196. return policies::raise_domain_error<T>(
  197. function,
  198. "Argument must be finite, but got %1%", val, pol);
  199. }
  200. if(val >= tools::max_value<T>())
  201. return policies::raise_overflow_error<T>(function, nullptr, pol);
  202. if(val == 0)
  203. return detail::get_smallest_value<T>();
  204. if((fpclass != (int)FP_SUBNORMAL) && (fpclass != (int)FP_ZERO) && (fabs(val) < detail::get_min_shift_value<T>()) && (val != -tools::min_value<T>()))
  205. {
  206. //
  207. // Special case: if the value of the least significant bit is a denorm, and the result
  208. // would not be a denorm, then shift the input, increment, and shift back.
  209. // This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
  210. //
  211. return scalbn(float_next(T(scalbn(val, 2 * std::numeric_limits<T>::digits)), pol), -2 * std::numeric_limits<T>::digits);
  212. }
  213. expon = 1 + ilogb(val);
  214. if(-1 == scalbn(val, -expon) * std::numeric_limits<T>::radix)
  215. --expon; // reduce exponent when val is a power of base, and negative.
  216. T diff = scalbn(T(1), expon - std::numeric_limits<T>::digits);
  217. if(diff == 0)
  218. diff = detail::get_smallest_value<T>();
  219. return val + diff;
  220. } // float_next_imp
  221. } // namespace detail
  222. template <class T, class Policy>
  223. inline typename tools::promote_args<T>::type float_next(const T& val, const Policy& pol)
  224. {
  225. typedef typename tools::promote_args<T>::type result_type;
  226. return detail::float_next_imp(detail::normalize_value(static_cast<result_type>(val), typename detail::has_hidden_guard_digits<result_type>::type()), std::integral_constant<bool, !std::numeric_limits<result_type>::is_specialized || (std::numeric_limits<result_type>::radix == 2)>(), pol);
  227. }
  228. #if 0 //def BOOST_MSVC
  229. //
  230. // We used to use ::_nextafter here, but doing so fails when using
  231. // the SSE2 registers if the FTZ or DAZ flags are set, so use our own
  232. // - albeit slower - code instead as at least that gives the correct answer.
  233. //
  234. template <class Policy>
  235. inline double float_next(const double& val, const Policy& pol)
  236. {
  237. static const char* function = "float_next<%1%>(%1%)";
  238. if(!(boost::math::isfinite)(val) && (val > 0))
  239. return policies::raise_domain_error<double>(
  240. function,
  241. "Argument must be finite, but got %1%", val, pol);
  242. if(val >= tools::max_value<double>())
  243. return policies::raise_overflow_error<double>(function, nullptr, pol);
  244. return ::_nextafter(val, tools::max_value<double>());
  245. }
  246. #endif
  247. template <class T>
  248. inline typename tools::promote_args<T>::type float_next(const T& val)
  249. {
  250. return float_next(val, policies::policy<>());
  251. }
  252. namespace detail{
  253. template <class T, class Policy>
  254. T float_prior_imp(const T& val, const std::true_type&, const Policy& pol)
  255. {
  256. typedef typename exponent_type<T>::type exponent_type;
  257. BOOST_MATH_STD_USING
  258. exponent_type expon;
  259. static const char* function = "float_prior<%1%>(%1%)";
  260. int fpclass = (boost::math::fpclassify)(val);
  261. if (fpclass == (int)FP_INFINITE)
  262. {
  263. if (val > 0)
  264. return tools::max_value<T>();
  265. return val; // -INF
  266. }
  267. else if (fpclass == (int)FP_NAN)
  268. {
  269. return policies::raise_domain_error<T>(
  270. function,
  271. "Argument must be finite, but got %1%", val, pol);
  272. }
  273. if(val <= -tools::max_value<T>())
  274. return -policies::raise_overflow_error<T>(function, nullptr, pol);
  275. if(val == 0)
  276. return -detail::get_smallest_value<T>();
  277. if((fpclass != (int)FP_SUBNORMAL) && (fpclass != (int)FP_ZERO) && (fabs(val) < detail::get_min_shift_value<T>()) && (val != tools::min_value<T>()))
  278. {
  279. //
  280. // Special case: if the value of the least significant bit is a denorm, and the result
  281. // would not be a denorm, then shift the input, increment, and shift back.
  282. // This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
  283. //
  284. return ldexp(float_prior(T(ldexp(val, 2 * tools::digits<T>())), pol), -2 * tools::digits<T>());
  285. }
  286. T remain = frexp(val, &expon);
  287. if(remain == 0.5f)
  288. --expon; // when val is a power of two we must reduce the exponent
  289. T diff = ldexp(T(1), expon - tools::digits<T>());
  290. if(diff == 0)
  291. diff = detail::get_smallest_value<T>();
  292. return val - diff;
  293. } // float_prior_imp
  294. //
  295. // Special version for bases other than 2:
  296. //
  297. template <class T, class Policy>
  298. T float_prior_imp(const T& val, const std::false_type&, const Policy& pol)
  299. {
  300. typedef typename exponent_type<T>::type exponent_type;
  301. static_assert(std::numeric_limits<T>::is_specialized, "Type T must be specialized.");
  302. static_assert(std::numeric_limits<T>::radix != 2, "Type T must be specialized.");
  303. BOOST_MATH_STD_USING
  304. exponent_type expon;
  305. static const char* function = "float_prior<%1%>(%1%)";
  306. int fpclass = (boost::math::fpclassify)(val);
  307. if (fpclass == (int)FP_INFINITE)
  308. {
  309. if (val > 0)
  310. return tools::max_value<T>();
  311. return val; // -INF
  312. }
  313. else if (fpclass == (int)FP_NAN)
  314. {
  315. return policies::raise_domain_error<T>(
  316. function,
  317. "Argument must be finite, but got %1%", val, pol);
  318. }
  319. if(val <= -tools::max_value<T>())
  320. return -policies::raise_overflow_error<T>(function, nullptr, pol);
  321. if(val == 0)
  322. return -detail::get_smallest_value<T>();
  323. if((fpclass != (int)FP_SUBNORMAL) && (fpclass != (int)FP_ZERO) && (fabs(val) < detail::get_min_shift_value<T>()) && (val != tools::min_value<T>()))
  324. {
  325. //
  326. // Special case: if the value of the least significant bit is a denorm, and the result
  327. // would not be a denorm, then shift the input, increment, and shift back.
  328. // This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
  329. //
  330. return scalbn(float_prior(T(scalbn(val, 2 * std::numeric_limits<T>::digits)), pol), -2 * std::numeric_limits<T>::digits);
  331. }
  332. expon = 1 + ilogb(val);
  333. T remain = scalbn(val, -expon);
  334. if(remain * std::numeric_limits<T>::radix == 1)
  335. --expon; // when val is a power of two we must reduce the exponent
  336. T diff = scalbn(T(1), expon - std::numeric_limits<T>::digits);
  337. if(diff == 0)
  338. diff = detail::get_smallest_value<T>();
  339. return val - diff;
  340. } // float_prior_imp
  341. } // namespace detail
  342. template <class T, class Policy>
  343. inline typename tools::promote_args<T>::type float_prior(const T& val, const Policy& pol)
  344. {
  345. typedef typename tools::promote_args<T>::type result_type;
  346. return detail::float_prior_imp(detail::normalize_value(static_cast<result_type>(val), typename detail::has_hidden_guard_digits<result_type>::type()), std::integral_constant<bool, !std::numeric_limits<result_type>::is_specialized || (std::numeric_limits<result_type>::radix == 2)>(), pol);
  347. }
  348. #if 0 //def BOOST_MSVC
  349. //
  350. // We used to use ::_nextafter here, but doing so fails when using
  351. // the SSE2 registers if the FTZ or DAZ flags are set, so use our own
  352. // - albeit slower - code instead as at least that gives the correct answer.
  353. //
  354. template <class Policy>
  355. inline double float_prior(const double& val, const Policy& pol)
  356. {
  357. static const char* function = "float_prior<%1%>(%1%)";
  358. if(!(boost::math::isfinite)(val) && (val < 0))
  359. return policies::raise_domain_error<double>(
  360. function,
  361. "Argument must be finite, but got %1%", val, pol);
  362. if(val <= -tools::max_value<double>())
  363. return -policies::raise_overflow_error<double>(function, nullptr, pol);
  364. return ::_nextafter(val, -tools::max_value<double>());
  365. }
  366. #endif
  367. template <class T>
  368. inline typename tools::promote_args<T>::type float_prior(const T& val)
  369. {
  370. return float_prior(val, policies::policy<>());
  371. }
  372. template <class T, class U, class Policy>
  373. inline typename tools::promote_args<T, U>::type nextafter(const T& val, const U& direction, const Policy& pol)
  374. {
  375. typedef typename tools::promote_args<T, U>::type result_type;
  376. return val < direction ? boost::math::float_next<result_type>(val, pol) : val == direction ? val : boost::math::float_prior<result_type>(val, pol);
  377. }
  378. template <class T, class U>
  379. inline typename tools::promote_args<T, U>::type nextafter(const T& val, const U& direction)
  380. {
  381. return nextafter(val, direction, policies::policy<>());
  382. }
  383. namespace detail{
  384. template <class T, class Policy>
  385. T float_distance_imp(const T& a, const T& b, const std::true_type&, const Policy& pol)
  386. {
  387. BOOST_MATH_STD_USING
  388. //
  389. // Error handling:
  390. //
  391. static const char* function = "float_distance<%1%>(%1%, %1%)";
  392. if(!(boost::math::isfinite)(a))
  393. return policies::raise_domain_error<T>(function, "Argument a must be finite, but got %1%", a, pol);
  394. if(!(boost::math::isfinite)(b))
  395. return policies::raise_domain_error<T>(function, "Argument b must be finite, but got %1%", b, pol);
  396. //
  397. // Special cases:
  398. //
  399. if(a > b)
  400. return -float_distance(b, a, pol);
  401. if(a == b)
  402. return T(0);
  403. if(a == 0)
  404. return 1 + fabs(float_distance(static_cast<T>((b < 0) ? T(-detail::get_smallest_value<T>()) : detail::get_smallest_value<T>()), b, pol));
  405. if(b == 0)
  406. return 1 + fabs(float_distance(static_cast<T>((a < 0) ? T(-detail::get_smallest_value<T>()) : detail::get_smallest_value<T>()), a, pol));
  407. if(boost::math::sign(a) != boost::math::sign(b))
  408. return 2 + fabs(float_distance(static_cast<T>((b < 0) ? T(-detail::get_smallest_value<T>()) : detail::get_smallest_value<T>()), b, pol))
  409. + fabs(float_distance(static_cast<T>((a < 0) ? T(-detail::get_smallest_value<T>()) : detail::get_smallest_value<T>()), a, pol));
  410. //
  411. // By the time we get here, both a and b must have the same sign, we want
  412. // b > a and both positive for the following logic:
  413. //
  414. if(a < 0)
  415. return float_distance(static_cast<T>(-b), static_cast<T>(-a), pol);
  416. BOOST_MATH_ASSERT(a >= 0);
  417. BOOST_MATH_ASSERT(b >= a);
  418. int expon;
  419. //
  420. // Note that if a is a denorm then the usual formula fails
  421. // because we actually have fewer than tools::digits<T>()
  422. // significant bits in the representation:
  423. //
  424. (void)frexp(((boost::math::fpclassify)(a) == (int)FP_SUBNORMAL) ? tools::min_value<T>() : a, &expon);
  425. T upper = ldexp(T(1), expon);
  426. T result = T(0);
  427. //
  428. // If b is greater than upper, then we *must* split the calculation
  429. // as the size of the ULP changes with each order of magnitude change:
  430. //
  431. if(b > upper)
  432. {
  433. int expon2;
  434. (void)frexp(b, &expon2);
  435. T upper2 = ldexp(T(0.5), expon2);
  436. result = float_distance(upper2, b);
  437. result += (expon2 - expon - 1) * ldexp(T(1), tools::digits<T>() - 1);
  438. }
  439. //
  440. // Use compensated double-double addition to avoid rounding
  441. // errors in the subtraction:
  442. //
  443. expon = tools::digits<T>() - expon;
  444. T mb, x, y, z;
  445. if(((boost::math::fpclassify)(a) == (int)FP_SUBNORMAL) || (b - a < tools::min_value<T>()))
  446. {
  447. //
  448. // Special case - either one end of the range is a denormal, or else the difference is.
  449. // The regular code will fail if we're using the SSE2 registers on Intel and either
  450. // the FTZ or DAZ flags are set.
  451. //
  452. T a2 = ldexp(a, tools::digits<T>());
  453. T b2 = ldexp(b, tools::digits<T>());
  454. mb = -(std::min)(T(ldexp(upper, tools::digits<T>())), b2);
  455. x = a2 + mb;
  456. z = x - a2;
  457. y = (a2 - (x - z)) + (mb - z);
  458. expon -= tools::digits<T>();
  459. }
  460. else
  461. {
  462. mb = -(std::min)(upper, b);
  463. x = a + mb;
  464. z = x - a;
  465. y = (a - (x - z)) + (mb - z);
  466. }
  467. if(x < 0)
  468. {
  469. x = -x;
  470. y = -y;
  471. }
  472. result += ldexp(x, expon) + ldexp(y, expon);
  473. //
  474. // Result must be an integer:
  475. //
  476. BOOST_MATH_ASSERT(result == floor(result));
  477. return result;
  478. } // float_distance_imp
  479. //
  480. // Special versions for bases other than 2:
  481. //
  482. template <class T, class Policy>
  483. T float_distance_imp(const T& a, const T& b, const std::false_type&, const Policy& pol)
  484. {
  485. static_assert(std::numeric_limits<T>::is_specialized, "Type T must be specialized.");
  486. static_assert(std::numeric_limits<T>::radix != 2, "Type T must be specialized.");
  487. BOOST_MATH_STD_USING
  488. //
  489. // Error handling:
  490. //
  491. static const char* function = "float_distance<%1%>(%1%, %1%)";
  492. if(!(boost::math::isfinite)(a))
  493. return policies::raise_domain_error<T>(function, "Argument a must be finite, but got %1%", a, pol);
  494. if(!(boost::math::isfinite)(b))
  495. return policies::raise_domain_error<T>(function, "Argument b must be finite, but got %1%", b, pol);
  496. //
  497. // Special cases:
  498. //
  499. if(a > b)
  500. return -float_distance(b, a, pol);
  501. if(a == b)
  502. return T(0);
  503. if(a == 0)
  504. return 1 + fabs(float_distance(static_cast<T>((b < 0) ? T(-detail::get_smallest_value<T>()) : detail::get_smallest_value<T>()), b, pol));
  505. if(b == 0)
  506. return 1 + fabs(float_distance(static_cast<T>((a < 0) ? T(-detail::get_smallest_value<T>()) : detail::get_smallest_value<T>()), a, pol));
  507. if(boost::math::sign(a) != boost::math::sign(b))
  508. return 2 + fabs(float_distance(static_cast<T>((b < 0) ? T(-detail::get_smallest_value<T>()) : detail::get_smallest_value<T>()), b, pol))
  509. + fabs(float_distance(static_cast<T>((a < 0) ? T(-detail::get_smallest_value<T>()) : detail::get_smallest_value<T>()), a, pol));
  510. //
  511. // By the time we get here, both a and b must have the same sign, we want
  512. // b > a and both positive for the following logic:
  513. //
  514. if(a < 0)
  515. return float_distance(static_cast<T>(-b), static_cast<T>(-a), pol);
  516. BOOST_MATH_ASSERT(a >= 0);
  517. BOOST_MATH_ASSERT(b >= a);
  518. std::intmax_t expon;
  519. //
  520. // Note that if a is a denorm then the usual formula fails
  521. // because we actually have fewer than tools::digits<T>()
  522. // significant bits in the representation:
  523. //
  524. expon = 1 + ilogb(((boost::math::fpclassify)(a) == (int)FP_SUBNORMAL) ? tools::min_value<T>() : a);
  525. T upper = scalbn(T(1), expon);
  526. T result = T(0);
  527. //
  528. // If b is greater than upper, then we *must* split the calculation
  529. // as the size of the ULP changes with each order of magnitude change:
  530. //
  531. if(b > upper)
  532. {
  533. std::intmax_t expon2 = 1 + ilogb(b);
  534. T upper2 = scalbn(T(1), expon2 - 1);
  535. result = float_distance(upper2, b);
  536. result += (expon2 - expon - 1) * scalbn(T(1), std::numeric_limits<T>::digits - 1);
  537. }
  538. //
  539. // Use compensated double-double addition to avoid rounding
  540. // errors in the subtraction:
  541. //
  542. expon = std::numeric_limits<T>::digits - expon;
  543. T mb, x, y, z;
  544. if(((boost::math::fpclassify)(a) == (int)FP_SUBNORMAL) || (b - a < tools::min_value<T>()))
  545. {
  546. //
  547. // Special case - either one end of the range is a denormal, or else the difference is.
  548. // The regular code will fail if we're using the SSE2 registers on Intel and either
  549. // the FTZ or DAZ flags are set.
  550. //
  551. T a2 = scalbn(a, std::numeric_limits<T>::digits);
  552. T b2 = scalbn(b, std::numeric_limits<T>::digits);
  553. mb = -(std::min)(T(scalbn(upper, std::numeric_limits<T>::digits)), b2);
  554. x = a2 + mb;
  555. z = x - a2;
  556. y = (a2 - (x - z)) + (mb - z);
  557. expon -= std::numeric_limits<T>::digits;
  558. }
  559. else
  560. {
  561. mb = -(std::min)(upper, b);
  562. x = a + mb;
  563. z = x - a;
  564. y = (a - (x - z)) + (mb - z);
  565. }
  566. if(x < 0)
  567. {
  568. x = -x;
  569. y = -y;
  570. }
  571. result += scalbn(x, expon) + scalbn(y, expon);
  572. //
  573. // Result must be an integer:
  574. //
  575. BOOST_MATH_ASSERT(result == floor(result));
  576. return result;
  577. } // float_distance_imp
  578. } // namespace detail
  579. template <class T, class U, class Policy>
  580. inline typename tools::promote_args<T, U>::type float_distance(const T& a, const U& b, const Policy& pol)
  581. {
  582. //
  583. // We allow ONE of a and b to be an integer type, otherwise both must be the SAME type.
  584. //
  585. static_assert(
  586. (std::is_same<T, U>::value
  587. || (std::is_integral<T>::value && !std::is_integral<U>::value)
  588. || (!std::is_integral<T>::value && std::is_integral<U>::value)
  589. || (std::numeric_limits<T>::is_specialized && std::numeric_limits<U>::is_specialized
  590. && (std::numeric_limits<T>::digits == std::numeric_limits<U>::digits)
  591. && (std::numeric_limits<T>::radix == std::numeric_limits<U>::radix)
  592. && !std::numeric_limits<T>::is_integer && !std::numeric_limits<U>::is_integer)),
  593. "Float distance between two different floating point types is undefined.");
  594. BOOST_MATH_IF_CONSTEXPR (!std::is_same<T, U>::value)
  595. {
  596. BOOST_MATH_IF_CONSTEXPR(std::is_integral<T>::value)
  597. {
  598. return float_distance(static_cast<U>(a), b, pol);
  599. }
  600. else
  601. {
  602. return float_distance(a, static_cast<T>(b), pol);
  603. }
  604. }
  605. else
  606. {
  607. typedef typename tools::promote_args<T, U>::type result_type;
  608. return detail::float_distance_imp(detail::normalize_value(static_cast<result_type>(a), typename detail::has_hidden_guard_digits<result_type>::type()), detail::normalize_value(static_cast<result_type>(b), typename detail::has_hidden_guard_digits<result_type>::type()), std::integral_constant<bool, !std::numeric_limits<result_type>::is_specialized || (std::numeric_limits<result_type>::radix == 2)>(), pol);
  609. }
  610. }
  611. template <class T, class U>
  612. typename tools::promote_args<T, U>::type float_distance(const T& a, const U& b)
  613. {
  614. return boost::math::float_distance(a, b, policies::policy<>());
  615. }
  616. namespace detail{
  617. template <class T, class Policy>
  618. T float_advance_imp(T val, int distance, const std::true_type&, const Policy& pol)
  619. {
  620. BOOST_MATH_STD_USING
  621. //
  622. // Error handling:
  623. //
  624. static const char* function = "float_advance<%1%>(%1%, int)";
  625. int fpclass = (boost::math::fpclassify)(val);
  626. if((fpclass == (int)FP_NAN) || (fpclass == (int)FP_INFINITE))
  627. return policies::raise_domain_error<T>(function, "Argument val must be finite, but got %1%", val, pol);
  628. if(val < 0)
  629. return -float_advance(-val, -distance, pol);
  630. if(distance == 0)
  631. return val;
  632. if(distance == 1)
  633. return float_next(val, pol);
  634. if(distance == -1)
  635. return float_prior(val, pol);
  636. if(fabs(val) < detail::get_min_shift_value<T>())
  637. {
  638. //
  639. // Special case: if the value of the least significant bit is a denorm,
  640. // implement in terms of float_next/float_prior.
  641. // This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
  642. //
  643. if(distance > 0)
  644. {
  645. do{ val = float_next(val, pol); } while(--distance);
  646. }
  647. else
  648. {
  649. do{ val = float_prior(val, pol); } while(++distance);
  650. }
  651. return val;
  652. }
  653. int expon;
  654. (void)frexp(val, &expon);
  655. T limit = ldexp((distance < 0 ? T(0.5f) : T(1)), expon);
  656. // We can not have denorms here, since we have taken care of them above:
  657. BOOST_MATH_ASSERT(val > tools::min_value<T>());
  658. T limit_distance = float_distance(val, limit);
  659. while(fabs(limit_distance) < abs(distance))
  660. {
  661. distance -= itrunc(limit_distance);
  662. val = limit;
  663. if(distance < 0)
  664. {
  665. limit /= 2;
  666. expon--;
  667. }
  668. else
  669. {
  670. limit *= 2;
  671. expon++;
  672. }
  673. limit_distance = float_distance(val, limit);
  674. if(distance && (limit_distance == 0))
  675. {
  676. return policies::raise_evaluation_error<T>(function, "Internal logic failed while trying to increment floating point value %1%: most likely your FPU is in non-IEEE conforming mode.", val, pol); // LCOV_EXCL_LINE This *should* be unreachable.
  677. }
  678. }
  679. if((0.5f == frexp(val, &expon)) && (distance < 0))
  680. --expon;
  681. T diff = 0;
  682. if(val != 0)
  683. diff = distance * ldexp(T(1), expon - tools::digits<T>());
  684. if(diff == 0)
  685. diff = distance * detail::get_smallest_value<T>(); // LCOV_EXCL_LINE This *should* be unreachable given that denorms are handled above already.
  686. return val += diff;
  687. } // float_advance_imp
  688. //
  689. // Special version for bases other than 2:
  690. //
  691. template <class T, class Policy>
  692. T float_advance_imp(T val, int distance, const std::false_type&, const Policy& pol)
  693. {
  694. static_assert(std::numeric_limits<T>::is_specialized, "Type T must be specialized.");
  695. static_assert(std::numeric_limits<T>::radix != 2, "Type T must be specialized.");
  696. BOOST_MATH_STD_USING
  697. //
  698. // Error handling:
  699. //
  700. static const char* function = "float_advance<%1%>(%1%, int)";
  701. int fpclass = (boost::math::fpclassify)(val);
  702. if((fpclass == (int)FP_NAN) || (fpclass == (int)FP_INFINITE))
  703. return policies::raise_domain_error<T>(function, "Argument val must be finite, but got %1%", val, pol);
  704. if(val < 0)
  705. return -float_advance(-val, -distance, pol);
  706. if(distance == 0)
  707. return val;
  708. if(distance == 1)
  709. return float_next(val, pol);
  710. if(distance == -1)
  711. return float_prior(val, pol);
  712. if(fabs(val) < detail::get_min_shift_value<T>())
  713. {
  714. //
  715. // Special case: if the value of the least significant bit is a denorm,
  716. // implement in terms of float_next/float_prior.
  717. // This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
  718. //
  719. if(distance > 0)
  720. {
  721. do{ val = float_next(val, pol); } while(--distance);
  722. }
  723. else
  724. {
  725. do{ val = float_prior(val, pol); } while(++distance);
  726. }
  727. return val;
  728. }
  729. std::intmax_t expon = 1 + ilogb(val);
  730. T limit = scalbn(T(1), distance < 0 ? expon - 1 : expon);
  731. BOOST_MATH_ASSERT(val > tools::min_value<T>()); // denorms already handled.
  732. T limit_distance = float_distance(val, limit);
  733. while(fabs(limit_distance) < abs(distance))
  734. {
  735. distance -= itrunc(limit_distance);
  736. val = limit;
  737. if(distance < 0)
  738. {
  739. limit /= std::numeric_limits<T>::radix;
  740. expon--;
  741. }
  742. else
  743. {
  744. limit *= std::numeric_limits<T>::radix; // LCOV_EXCL_LINE Probably unreachable for the decimal types we have?
  745. expon++; // LCOV_EXCL_LINE
  746. }
  747. limit_distance = float_distance(val, limit);
  748. if(distance && (limit_distance == 0))
  749. {
  750. return policies::raise_evaluation_error<T>(function, "Internal logic failed while trying to increment floating point value %1%: most likely your FPU is in non-IEEE conforming mode.", val, pol); // LCOV_EXCL_LINE should never get here!
  751. }
  752. }
  753. /*expon = 1 + ilogb(val);
  754. if((1 == scalbn(val, 1 + expon)) && (distance < 0))
  755. --expon;*/
  756. T diff = 0;
  757. if(val != 0)
  758. diff = distance * scalbn(T(1), expon - std::numeric_limits<T>::digits);
  759. if(diff == 0)
  760. diff = distance * detail::get_smallest_value<T>(); // LCOV_EXCL_LINE This *should* be unreachable given that denorms are handled above.
  761. return val += diff;
  762. } // float_advance_imp
  763. } // namespace detail
  764. template <class T, class Policy>
  765. inline typename tools::promote_args<T>::type float_advance(T val, int distance, const Policy& pol)
  766. {
  767. typedef typename tools::promote_args<T>::type result_type;
  768. return detail::float_advance_imp(detail::normalize_value(static_cast<result_type>(val), typename detail::has_hidden_guard_digits<result_type>::type()), distance, std::integral_constant<bool, !std::numeric_limits<result_type>::is_specialized || (std::numeric_limits<result_type>::radix == 2)>(), pol);
  769. }
  770. template <class T>
  771. inline typename tools::promote_args<T>::type float_advance(const T& val, int distance)
  772. {
  773. return boost::math::float_advance(val, distance, policies::policy<>());
  774. }
  775. }} // boost math namespaces
  776. #endif
  777. #endif // BOOST_MATH_SPECIAL_NEXT_HPP