pow.hpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. // Copyright 2011 - 2025 John Maddock.
  2. // Copyright Christopher Kormanyos 2002 - 2025.
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. // This work is based on an earlier work:
  7. // "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
  8. // in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469
  9. //
  10. // This file has no include guards or namespaces - it's expanded inline inside default_ops.hpp
  11. //
  12. #ifdef BOOST_MSVC
  13. #pragma warning(push)
  14. #pragma warning(disable : 6326) // comparison of two constants
  15. #pragma warning(disable : 4127) // conditional expression is constant
  16. #endif
  17. #include <boost/multiprecision/detail/standalone_config.hpp>
  18. #include <boost/multiprecision/detail/no_exceptions_support.hpp>
  19. #include <boost/multiprecision/detail/assert.hpp>
  20. namespace detail {
  21. template <typename T, typename U>
  22. inline void pow_imp(T& result, const T& t, const U& p, const std::integral_constant<bool, false>&)
  23. {
  24. // Compute the pure power of typename T t^p.
  25. // Use the S-and-X binary method, as described in
  26. // D. E. Knuth, "The Art of Computer Programming", Vol. 2,
  27. // Section 4.6.3 . The resulting computational complexity
  28. // is order log2[abs(p)].
  29. using int_type = typename boost::multiprecision::detail::canonical<U, T>::type;
  30. if (&result == &t)
  31. {
  32. T temp;
  33. pow_imp(temp, t, p, std::integral_constant<bool, false>());
  34. result = temp;
  35. return;
  36. }
  37. switch (p)
  38. {
  39. case 0:
  40. result = int_type(1);
  41. return;
  42. case 1:
  43. result = t;
  44. return;
  45. case 2:
  46. eval_multiply(result, t, t);
  47. return;
  48. case 3:
  49. eval_multiply(result, t, t);
  50. eval_multiply(result, t);
  51. return;
  52. case 4:
  53. eval_multiply(result, t, t);
  54. eval_multiply(result, result);
  55. return;
  56. default:
  57. break;
  58. }
  59. // This will store the result.
  60. if (U(p % U(2)) != U(0))
  61. {
  62. result = t;
  63. }
  64. else
  65. result = int_type(1);
  66. U p2(p);
  67. // The variable x stores the binary powers of t.
  68. T x(t);
  69. while (U(p2 /= 2) != U(0))
  70. {
  71. // Square x for each binary power.
  72. eval_multiply(x, x);
  73. const bool has_binary_power = (U(p2 % U(2)) != U(0));
  74. if (has_binary_power)
  75. {
  76. // Multiply the result with each binary power contained in the exponent.
  77. eval_multiply(result, x);
  78. }
  79. }
  80. }
  81. template <typename T, typename U>
  82. inline void pow_imp(T& result, const T& t, const U& p, const std::integral_constant<bool, true>&)
  83. {
  84. // Signed integer power, just take care of the sign then call the unsigned version:
  85. using int_type = typename boost::multiprecision::detail::canonical<U, T>::type;
  86. using ui_type = typename boost::multiprecision::detail::make_unsigned<U>::type;
  87. if (p < 0)
  88. {
  89. T temp;
  90. temp = static_cast<int_type>(1);
  91. T denom;
  92. pow_imp(denom, t, static_cast<ui_type>(-p), std::integral_constant<bool, false>());
  93. eval_divide(result, temp, denom);
  94. return;
  95. }
  96. pow_imp(result, t, static_cast<ui_type>(p), std::integral_constant<bool, false>());
  97. }
  98. } // namespace detail
  99. template <typename T, typename U>
  100. inline typename std::enable_if<boost::multiprecision::detail::is_integral<U>::value>::type eval_pow(T& result, const T& t, const U& p)
  101. {
  102. detail::pow_imp(result, t, p, boost::multiprecision::detail::is_signed<U>());
  103. }
  104. template <class T>
  105. void hyp0F0(T& H0F0, const T& x)
  106. {
  107. // Compute the series representation of Hypergeometric0F0 taken from
  108. // http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric0F0/06/01/
  109. // There are no checks on input range or parameter boundaries.
  110. using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
  111. BOOST_MP_ASSERT(&H0F0 != &x);
  112. long tol = boost::multiprecision::detail::digits2<number<T, et_on> >::value();
  113. T x_pow_n_div_n_fact(x);
  114. eval_add(H0F0, x_pow_n_div_n_fact, ui_type(1));
  115. T lim;
  116. eval_ldexp(lim, H0F0, static_cast<int>(1L - tol));
  117. if (eval_get_sign(lim) < 0)
  118. lim.negate();
  119. ui_type n;
  120. const unsigned series_limit =
  121. boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100
  122. ? 100
  123. : boost::multiprecision::detail::digits2<number<T, et_on> >::value();
  124. // Series expansion of hyperg_0f0(; ; x).
  125. for (n = 2; n < series_limit; ++n)
  126. {
  127. eval_multiply(x_pow_n_div_n_fact, x);
  128. eval_divide(x_pow_n_div_n_fact, n);
  129. eval_add(H0F0, x_pow_n_div_n_fact);
  130. bool neg = eval_get_sign(x_pow_n_div_n_fact) < 0;
  131. if (neg)
  132. x_pow_n_div_n_fact.negate();
  133. if (lim.compare(x_pow_n_div_n_fact) > 0)
  134. break;
  135. if (neg)
  136. x_pow_n_div_n_fact.negate();
  137. }
  138. if (n >= series_limit)
  139. BOOST_MP_THROW_EXCEPTION(std::runtime_error("H0F0 failed to converge")); // LCOV_EXCL_LINE
  140. }
  141. template <class T>
  142. void hyp1F0(T& H1F0, const T& a, const T& x)
  143. {
  144. // Compute the series representation of Hypergeometric1F0 taken from
  145. // http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric1F0/06/01/01/
  146. // and also see the corresponding section for the power function (i.e. x^a).
  147. // There are no checks on input range or parameter boundaries.
  148. using si_type = typename boost::multiprecision::detail::canonical<int, T>::type;
  149. BOOST_MP_ASSERT(&H1F0 != &x);
  150. BOOST_MP_ASSERT(&H1F0 != &a);
  151. T x_pow_n_div_n_fact(x);
  152. T pochham_a(a);
  153. T ap(a);
  154. eval_multiply(H1F0, pochham_a, x_pow_n_div_n_fact);
  155. eval_add(H1F0, si_type(1));
  156. T lim;
  157. eval_ldexp(lim, H1F0, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
  158. if (eval_get_sign(lim) < 0)
  159. lim.negate();
  160. si_type n;
  161. T term;
  162. const si_type series_limit =
  163. boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100
  164. ? 100
  165. : boost::multiprecision::detail::digits2<number<T, et_on> >::value();
  166. // Series expansion of hyperg_1f0(a; ; x).
  167. for (n = 2; n < series_limit; n++)
  168. {
  169. eval_multiply(x_pow_n_div_n_fact, x);
  170. eval_divide(x_pow_n_div_n_fact, n);
  171. eval_increment(ap);
  172. eval_multiply(pochham_a, ap);
  173. eval_multiply(term, pochham_a, x_pow_n_div_n_fact);
  174. eval_add(H1F0, term);
  175. if (eval_get_sign(term) < 0)
  176. term.negate();
  177. if (lim.compare(term) >= 0)
  178. break;
  179. }
  180. if (n >= series_limit)
  181. BOOST_MP_THROW_EXCEPTION(std::runtime_error("H1F0 failed to converge")); // LCOV_EXCL_LINE
  182. }
  183. template <class T>
  184. void eval_exp(T& result, const T& x)
  185. {
  186. static_assert(number_category<T>::value == number_kind_floating_point, "The exp function is only valid for floating point types.");
  187. if (&x == &result)
  188. {
  189. T temp;
  190. eval_exp(temp, x);
  191. result = temp;
  192. return;
  193. }
  194. using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
  195. using si_type = typename boost::multiprecision::detail::canonical<int, T>::type;
  196. using exp_type = typename T::exponent_type;
  197. using canonical_exp_type = typename boost::multiprecision::detail::canonical<exp_type, T>::type;
  198. // Handle special arguments.
  199. int type = eval_fpclassify(x);
  200. bool isneg = eval_get_sign(x) < 0;
  201. if (type == static_cast<int>(FP_NAN))
  202. {
  203. result = x;
  204. errno = EDOM;
  205. return;
  206. }
  207. else if (type == static_cast<int>(FP_INFINITE))
  208. {
  209. if (isneg)
  210. result = ui_type(0u);
  211. else
  212. result = x;
  213. return;
  214. }
  215. else if (type == static_cast<int>(FP_ZERO))
  216. {
  217. result = ui_type(1);
  218. return;
  219. }
  220. // Get local copy of argument and force it to be positive.
  221. T xx = x;
  222. T exp_series;
  223. if (isneg)
  224. xx.negate();
  225. // Check the range of the argument.
  226. if (xx.compare(si_type(1)) <= 0)
  227. {
  228. //
  229. // Use series for exp(x) - 1:
  230. //
  231. T lim;
  232. BOOST_IF_CONSTEXPR(std::numeric_limits<number<T, et_on> >::is_specialized)
  233. lim = std::numeric_limits<number<T, et_on> >::epsilon().backend();
  234. else
  235. {
  236. result = ui_type(1);
  237. eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
  238. }
  239. unsigned k = 2;
  240. exp_series = xx;
  241. result = si_type(1);
  242. if (isneg)
  243. eval_subtract(result, exp_series);
  244. else
  245. eval_add(result, exp_series);
  246. eval_multiply(exp_series, xx);
  247. eval_divide(exp_series, ui_type(k));
  248. eval_add(result, exp_series);
  249. while (exp_series.compare(lim) > 0)
  250. {
  251. ++k;
  252. eval_multiply(exp_series, xx);
  253. eval_divide(exp_series, ui_type(k));
  254. if (isneg && (k & 1))
  255. eval_subtract(result, exp_series);
  256. else
  257. eval_add(result, exp_series);
  258. }
  259. return;
  260. }
  261. // Check for pure-integer arguments which can be either signed or unsigned.
  262. typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type ll;
  263. eval_trunc(exp_series, x);
  264. eval_convert_to(&ll, exp_series);
  265. if (x.compare(ll) == 0)
  266. {
  267. detail::pow_imp(result, get_constant_e<T>(), ll, std::integral_constant<bool, true>());
  268. return;
  269. }
  270. else if (exp_series.compare(x) == 0)
  271. {
  272. // We have a value that has no fractional part, but is too large to fit
  273. // in a long long, in this situation the code below will fail, so
  274. // we're just going to assume that this will overflow:
  275. if (isneg)
  276. result = ui_type(0);
  277. else
  278. result = std::numeric_limits<number<T> >::has_infinity ? std::numeric_limits<number<T> >::infinity().backend() : (std::numeric_limits<number<T> >::max)().backend();
  279. return;
  280. }
  281. // The algorithm for exp has been taken from MPFUN.
  282. // exp(t) = [ (1 + r + r^2/2! + r^3/3! + r^4/4! ...)^p2 ] * 2^n
  283. // where p2 is a power of 2 such as 2048, r = t_prime / p2, and
  284. // t_prime = t - n*ln2, with n chosen to minimize the absolute
  285. // value of t_prime. In the resulting Taylor series, which is
  286. // implemented as a hypergeometric function, |r| is bounded by
  287. // ln2 / p2. For small arguments, no scaling is done.
  288. // Compute the exponential series of the (possibly) scaled argument.
  289. eval_divide(result, xx, get_constant_ln2<T>());
  290. exp_type n;
  291. eval_convert_to(&n, result);
  292. if (n == (std::numeric_limits<exp_type>::max)())
  293. {
  294. // Exponent is too large to fit in our exponent type:
  295. if (isneg)
  296. result = ui_type(0);
  297. else
  298. result = std::numeric_limits<number<T> >::has_infinity ? std::numeric_limits<number<T> >::infinity().backend() : (std::numeric_limits<number<T> >::max)().backend();
  299. return;
  300. }
  301. // The scaling is 2^11 = 2048.
  302. const si_type p2 = static_cast<si_type>(si_type(1) << 11);
  303. eval_multiply(exp_series, get_constant_ln2<T>(), static_cast<canonical_exp_type>(n));
  304. eval_subtract(exp_series, xx);
  305. eval_divide(exp_series, p2);
  306. exp_series.negate();
  307. hyp0F0(result, exp_series);
  308. detail::pow_imp(exp_series, result, p2, std::integral_constant<bool, true>());
  309. result = ui_type(1);
  310. eval_ldexp(result, result, n);
  311. eval_multiply(exp_series, result);
  312. if (isneg)
  313. eval_divide(result, ui_type(1), exp_series);
  314. else
  315. result = exp_series;
  316. }
  317. template <class T>
  318. void eval_log(T& result, const T& arg)
  319. {
  320. static_assert(number_category<T>::value == number_kind_floating_point, "The log function is only valid for floating point types.");
  321. //
  322. // We use a variation of http://dlmf.nist.gov/4.45#i
  323. // using frexp to reduce the argument to x * 2^n,
  324. // then let y = x - 1 and compute:
  325. // log(x) = log(2) * n + log1p(1 + y)
  326. //
  327. using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
  328. using exp_type = typename T::exponent_type;
  329. using canonical_exp_type = typename boost::multiprecision::detail::canonical<exp_type, T>::type;
  330. using fp_type = typename std::tuple_element<0, typename T::float_types>::type;
  331. const int s = eval_signbit(arg);
  332. switch (eval_fpclassify(arg))
  333. {
  334. case FP_NAN:
  335. result = arg;
  336. errno = EDOM;
  337. return;
  338. case FP_INFINITE:
  339. if (s)
  340. break;
  341. result = arg;
  342. return;
  343. case FP_ZERO:
  344. result = std::numeric_limits<number<T> >::has_infinity ? std::numeric_limits<number<T> >::infinity().backend() : (std::numeric_limits<number<T> >::max)().backend();
  345. result.negate();
  346. errno = ERANGE;
  347. return;
  348. default:
  349. break;
  350. }
  351. if (s)
  352. {
  353. result = std::numeric_limits<number<T> >::quiet_NaN().backend();
  354. errno = EDOM;
  355. return;
  356. }
  357. exp_type e;
  358. T t;
  359. eval_frexp(t, arg, &e);
  360. bool alternate = false;
  361. if (t.compare(fp_type(2) / fp_type(3)) <= 0)
  362. {
  363. alternate = true;
  364. eval_ldexp(t, t, 1);
  365. --e;
  366. }
  367. eval_multiply(result, get_constant_ln2<T>(), canonical_exp_type(e));
  368. INSTRUMENT_BACKEND(result);
  369. eval_subtract(t, ui_type(1)); /* -0.3 <= t <= 0.3 */
  370. if (!alternate)
  371. t.negate(); /* 0 <= t <= 0.33333 */
  372. T pow = t;
  373. T lim;
  374. T t2;
  375. if (alternate)
  376. eval_add(result, t);
  377. else
  378. eval_subtract(result, t);
  379. BOOST_IF_CONSTEXPR(std::numeric_limits<number<T, et_on> >::is_specialized)
  380. eval_multiply(lim, result, std::numeric_limits<number<T, et_on> >::epsilon().backend());
  381. else
  382. eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
  383. if (eval_get_sign(lim) < 0)
  384. lim.negate();
  385. INSTRUMENT_BACKEND(lim);
  386. ui_type k = 1;
  387. do
  388. {
  389. ++k;
  390. eval_multiply(pow, t);
  391. eval_divide(t2, pow, k);
  392. INSTRUMENT_BACKEND(t2);
  393. if (alternate && ((k & 1) != 0))
  394. eval_add(result, t2);
  395. else
  396. eval_subtract(result, t2);
  397. INSTRUMENT_BACKEND(result);
  398. } while (lim.compare(t2) < 0);
  399. }
  400. template <class T>
  401. const T& get_constant_log10()
  402. {
  403. static BOOST_MP_THREAD_LOCAL T result;
  404. static BOOST_MP_THREAD_LOCAL long digits = 0;
  405. if ((digits != boost::multiprecision::detail::digits2<number<T> >::value()))
  406. {
  407. using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
  408. T ten;
  409. ten = ui_type(10u);
  410. eval_log(result, ten);
  411. digits = boost::multiprecision::detail::digits2<number<T> >::value();
  412. }
  413. return result;
  414. }
  415. template <class T>
  416. void eval_log10(T& result, const T& arg)
  417. {
  418. static_assert(number_category<T>::value == number_kind_floating_point, "The log10 function is only valid for floating point types.");
  419. eval_log(result, arg);
  420. eval_divide(result, get_constant_log10<T>());
  421. }
  422. template <class R, class T>
  423. inline void eval_log2(R& result, const T& a)
  424. {
  425. eval_log(result, a);
  426. eval_divide(result, get_constant_ln2<R>());
  427. }
  428. template <typename T>
  429. inline void eval_pow(T& result, const T& x, const T& a)
  430. {
  431. static_assert(number_category<T>::value == number_kind_floating_point, "The pow function is only valid for floating point types.");
  432. if ((&result == &x) || (&result == &a))
  433. {
  434. T t;
  435. eval_pow(t, x, a);
  436. result = t;
  437. return;
  438. }
  439. using si_type = typename boost::multiprecision::detail::canonical<int, T>::type;
  440. using fp_type = typename std::tuple_element<0, typename T::float_types>::type;
  441. if ((a.compare(si_type(1)) == 0) || (x.compare(si_type(1)) == 0))
  442. {
  443. result = x;
  444. return;
  445. }
  446. if (eval_is_zero(a))
  447. {
  448. result = si_type(1);
  449. return;
  450. }
  451. const int fpc_x { eval_fpclassify(x) };
  452. const int fpc_a { eval_fpclassify(a) };
  453. switch (fpc_x)
  454. {
  455. case FP_ZERO:
  456. switch (fpc_a)
  457. {
  458. case FP_NAN:
  459. result = a;
  460. break;
  461. case FP_NORMAL: {
  462. // Need to check for a an odd integer as a special case:
  463. BOOST_MP_TRY
  464. {
  465. typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type i;
  466. eval_convert_to(&i, a);
  467. if (a.compare(i) == 0)
  468. {
  469. if (eval_signbit(a))
  470. {
  471. if (i & 1)
  472. {
  473. result = std::numeric_limits<number<T> >::infinity().backend();
  474. if (eval_signbit(x))
  475. result.negate();
  476. errno = ERANGE;
  477. }
  478. else
  479. {
  480. result = std::numeric_limits<number<T> >::infinity().backend();
  481. errno = ERANGE;
  482. }
  483. }
  484. else if (i & 1)
  485. {
  486. result = x;
  487. }
  488. else
  489. result = si_type(0);
  490. return;
  491. }
  492. }
  493. BOOST_MP_CATCH(const std::exception&) // LCOV_EXCL_LINE
  494. {
  495. // fallthrough..
  496. }
  497. BOOST_MP_CATCH_END
  498. BOOST_FALLTHROUGH;
  499. }
  500. default:
  501. if (eval_signbit(a))
  502. {
  503. result = std::numeric_limits<number<T> >::infinity().backend();
  504. errno = ERANGE;
  505. }
  506. else
  507. result = x;
  508. break;
  509. }
  510. return;
  511. case FP_NAN:
  512. result = x;
  513. errno = ERANGE;
  514. return;
  515. default:;
  516. }
  517. const int s = eval_get_sign(a);
  518. if (s < 0)
  519. {
  520. T t, da;
  521. t = a;
  522. t.negate();
  523. eval_pow(da, x, t);
  524. eval_divide(result, si_type(1), da);
  525. return;
  526. }
  527. typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type an;
  528. typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type max_an =
  529. std::numeric_limits<typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type>::is_specialized ? (std::numeric_limits<typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type>::max)() : static_cast<typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type>(1) << (sizeof(typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type) * CHAR_BIT - 2);
  530. typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type min_an =
  531. std::numeric_limits<typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type>::is_specialized ? (std::numeric_limits<typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type>::min)() : -min_an;
  532. T fa;
  533. BOOST_MP_TRY
  534. {
  535. eval_convert_to(&an, a);
  536. if (a.compare(an) == 0)
  537. {
  538. detail::pow_imp(result, x, an, std::integral_constant<bool, true>());
  539. return;
  540. }
  541. }
  542. BOOST_MP_CATCH(const std::exception&)
  543. {
  544. // conversion failed, just fall through, value is not an integer.
  545. an = (std::numeric_limits<std::intmax_t>::max)();
  546. }
  547. BOOST_MP_CATCH_END
  548. if ((eval_get_sign(x) < 0))
  549. {
  550. typename boost::multiprecision::detail::canonical<std::uintmax_t, T>::type aun;
  551. BOOST_MP_TRY
  552. {
  553. eval_convert_to(&aun, a);
  554. if (a.compare(aun) == 0)
  555. {
  556. fa = x;
  557. fa.negate();
  558. eval_pow(result, fa, a);
  559. if (aun & 1u)
  560. result.negate();
  561. return;
  562. }
  563. }
  564. BOOST_MP_CATCH(const std::exception&)
  565. {
  566. // conversion failed, just fall through, value is not an integer.
  567. }
  568. BOOST_MP_CATCH_END
  569. eval_floor(result, a);
  570. // -1^INF is a special case in C99:
  571. if ((x.compare(si_type(-1)) == 0) && (fpc_a == FP_INFINITE))
  572. {
  573. result = si_type(1);
  574. }
  575. else if (a.compare(result) == 0)
  576. {
  577. // exponent is so large we have no fractional part:
  578. if (x.compare(si_type(-1)) < 0)
  579. {
  580. result = std::numeric_limits<number<T, et_on> >::infinity().backend();
  581. }
  582. else
  583. {
  584. result = si_type(0);
  585. }
  586. }
  587. else if (fpc_x == FP_INFINITE)
  588. {
  589. BOOST_IF_CONSTEXPR (std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
  590. {
  591. if (fpc_a == FP_NAN)
  592. {
  593. result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
  594. }
  595. else
  596. {
  597. result = std::numeric_limits<number<T, et_on> >::infinity().backend();
  598. }
  599. }
  600. else
  601. {
  602. result = std::numeric_limits<number<T, et_on> >::infinity().backend(); // LCOV_EXCL_LINE There is no NaN for this number type.
  603. }
  604. }
  605. else BOOST_IF_CONSTEXPR (std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
  606. {
  607. result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
  608. errno = EDOM;
  609. }
  610. else
  611. {
  612. BOOST_MP_THROW_EXCEPTION(std::domain_error("Result of pow is undefined or non-real and there is no NaN for this number type.")); // LCOV_EXCL_LINE
  613. }
  614. return;
  615. }
  616. T t, da;
  617. eval_subtract(da, a, an);
  618. if ((x.compare(fp_type(0.5)) >= 0) && (x.compare(fp_type(0.9)) < 0) && (an < max_an) && (an > min_an))
  619. {
  620. if (a.compare(fp_type(1e-5f)) <= 0)
  621. {
  622. // Series expansion for small a.
  623. eval_log(t, x);
  624. eval_multiply(t, a);
  625. hyp0F0(result, t);
  626. return;
  627. }
  628. else
  629. {
  630. // Series expansion for moderately sized x. Note that for large power of a,
  631. // the power of the integer part of a is calculated using the pown function.
  632. if (an)
  633. {
  634. da.negate();
  635. t = si_type(1);
  636. eval_subtract(t, x);
  637. hyp1F0(result, da, t);
  638. detail::pow_imp(t, x, an, std::integral_constant<bool, true>());
  639. eval_multiply(result, t);
  640. }
  641. else
  642. {
  643. da = a;
  644. da.negate();
  645. t = si_type(1);
  646. eval_subtract(t, x);
  647. hyp1F0(result, da, t);
  648. }
  649. }
  650. }
  651. else
  652. {
  653. // Series expansion for pow(x, a). Note that for large power of a, the power
  654. // of the integer part of a is calculated using the pown function.
  655. if (an)
  656. {
  657. eval_log(t, x);
  658. eval_multiply(t, da);
  659. eval_exp(result, t);
  660. detail::pow_imp(t, x, an, std::integral_constant<bool, true>());
  661. eval_multiply(result, t);
  662. }
  663. else
  664. {
  665. eval_log(t, x);
  666. eval_multiply(t, a);
  667. eval_exp(result, t);
  668. }
  669. }
  670. }
  671. template <class T, class A>
  672. #if BOOST_WORKAROUND(BOOST_MSVC, < 1800)
  673. inline typename std::enable_if<!boost::multiprecision::detail::is_integral<A>::value, void>::type
  674. #else
  675. inline typename std::enable_if<boost::multiprecision::is_compatible_arithmetic_type<A, boost::multiprecision::number<T> >::value && !boost::multiprecision::detail::is_integral<A>::value, void>::type
  676. #endif
  677. eval_pow(T& result, const T& x, const A& a)
  678. {
  679. // Note this one is restricted to float arguments since pow.hpp already has a version for
  680. // integer powers....
  681. using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
  682. using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
  683. cast_type c;
  684. c = a;
  685. eval_pow(result, x, c);
  686. }
  687. template <class T, class A>
  688. #if BOOST_WORKAROUND(BOOST_MSVC, < 1800)
  689. inline void
  690. #else
  691. inline typename std::enable_if<boost::multiprecision::is_compatible_arithmetic_type<A, boost::multiprecision::number<T> >::value, void>::type
  692. #endif
  693. eval_pow(T& result, const A& x, const T& a)
  694. {
  695. using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type ;
  696. using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
  697. cast_type c;
  698. c = x;
  699. eval_pow(result, c, a);
  700. }
  701. template <class T>
  702. void eval_exp2(T& result, const T& arg)
  703. {
  704. static_assert(number_category<T>::value == number_kind_floating_point, "The log function is only valid for floating point types.");
  705. // Check for pure-integer arguments which can be either signed or unsigned.
  706. typename boost::multiprecision::detail::canonical<typename T::exponent_type, T>::type i;
  707. T temp;
  708. BOOST_MP_TRY
  709. {
  710. eval_trunc(temp, arg);
  711. eval_convert_to(&i, temp);
  712. if (arg.compare(i) == 0)
  713. {
  714. temp = static_cast<typename std::tuple_element<0, typename T::unsigned_types>::type>(1u);
  715. eval_ldexp(result, temp, i);
  716. return;
  717. }
  718. }
  719. #ifdef BOOST_MP_MATH_AVAILABLE
  720. BOOST_MP_CATCH(const boost::math::rounding_error&)
  721. { /* Fallthrough */
  722. }
  723. #endif
  724. BOOST_MP_CATCH(const std::runtime_error&)
  725. { /* Fallthrough */
  726. }
  727. BOOST_MP_CATCH_END
  728. temp = static_cast<typename std::tuple_element<0, typename T::unsigned_types>::type>(2u);
  729. eval_pow(result, temp, arg);
  730. }
  731. namespace detail {
  732. template <class T>
  733. void small_sinh_series(T x, T& result)
  734. {
  735. using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
  736. bool neg = eval_get_sign(x) < 0;
  737. if (neg)
  738. x.negate();
  739. T p(x);
  740. T mult(x);
  741. eval_multiply(mult, x);
  742. result = x;
  743. ui_type k = 1;
  744. T lim(x);
  745. eval_ldexp(lim, lim, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
  746. do
  747. {
  748. eval_multiply(p, mult);
  749. eval_divide(p, ++k);
  750. eval_divide(p, ++k);
  751. eval_add(result, p);
  752. } while (p.compare(lim) >= 0);
  753. if (neg)
  754. result.negate();
  755. }
  756. template <class T>
  757. void sinhcosh(const T& x, T* p_sinh, T* p_cosh)
  758. {
  759. using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
  760. using fp_type = typename std::tuple_element<0, typename T::float_types>::type ;
  761. switch (eval_fpclassify(x))
  762. {
  763. case FP_NAN:
  764. errno = EDOM;
  765. // fallthrough...
  766. case FP_INFINITE:
  767. if (p_sinh)
  768. *p_sinh = x;
  769. if (p_cosh)
  770. {
  771. *p_cosh = x;
  772. if (eval_get_sign(x) < 0)
  773. p_cosh->negate();
  774. }
  775. return;
  776. case FP_ZERO:
  777. if (p_sinh)
  778. *p_sinh = x;
  779. if (p_cosh)
  780. *p_cosh = ui_type(1);
  781. return;
  782. default:;
  783. }
  784. bool small_sinh = eval_get_sign(x) < 0 ? x.compare(fp_type(-0.5)) > 0 : x.compare(fp_type(0.5)) < 0;
  785. if (p_cosh || !small_sinh)
  786. {
  787. T e_px, e_mx;
  788. eval_exp(e_px, x);
  789. eval_divide(e_mx, ui_type(1), e_px);
  790. if (eval_signbit(e_mx) != eval_signbit(e_px))
  791. e_mx.negate(); // Handles lack of signed zero in some types
  792. if (p_sinh)
  793. {
  794. if (small_sinh)
  795. {
  796. small_sinh_series(x, *p_sinh);
  797. }
  798. else
  799. {
  800. eval_subtract(*p_sinh, e_px, e_mx);
  801. eval_ldexp(*p_sinh, *p_sinh, -1);
  802. }
  803. }
  804. if (p_cosh)
  805. {
  806. eval_add(*p_cosh, e_px, e_mx);
  807. eval_ldexp(*p_cosh, *p_cosh, -1);
  808. }
  809. }
  810. else
  811. {
  812. small_sinh_series(x, *p_sinh);
  813. }
  814. }
  815. } // namespace detail
  816. template <class T>
  817. inline void eval_sinh(T& result, const T& x)
  818. {
  819. static_assert(number_category<T>::value == number_kind_floating_point, "The sinh function is only valid for floating point types.");
  820. detail::sinhcosh(x, &result, static_cast<T*>(0));
  821. }
  822. template <class T>
  823. inline void eval_cosh(T& result, const T& x)
  824. {
  825. static_assert(number_category<T>::value == number_kind_floating_point, "The cosh function is only valid for floating point types.");
  826. detail::sinhcosh(x, static_cast<T*>(0), &result);
  827. }
  828. template <class T>
  829. inline void eval_tanh(T& result, const T& x)
  830. {
  831. static_assert(number_category<T>::value == number_kind_floating_point, "The tanh function is only valid for floating point types.");
  832. T c;
  833. detail::sinhcosh(x, &result, &c);
  834. if ((eval_fpclassify(result) == FP_INFINITE) && (eval_fpclassify(c) == FP_INFINITE))
  835. {
  836. bool s = eval_signbit(result) != eval_signbit(c);
  837. result = static_cast<typename std::tuple_element<0, typename T::unsigned_types>::type>(1u);
  838. if (s)
  839. result.negate();
  840. return;
  841. }
  842. eval_divide(result, c);
  843. }
  844. #ifdef BOOST_MSVC
  845. #pragma warning(pop)
  846. #endif