next.hpp 28 KB

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