fibonacci.hpp 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // Copyright 2020, Madhur Chauhan
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_MATH_SPECIAL_FIBO_HPP
  7. #define BOOST_MATH_SPECIAL_FIBO_HPP
  8. #include <boost/math/constants/constants.hpp>
  9. #include <boost/math/policies/error_handling.hpp>
  10. #include <cmath>
  11. #include <limits>
  12. #ifdef _MSC_VER
  13. #pragma once
  14. #endif
  15. namespace boost {
  16. namespace math {
  17. namespace detail {
  18. constexpr double fib_bits_phi = 0.69424191363061730173879026;
  19. constexpr double fib_bits_deno = 1.1609640474436811739351597;
  20. } // namespace detail
  21. template <typename T>
  22. inline BOOST_MATH_CXX14_CONSTEXPR T unchecked_fibonacci(unsigned long long n) noexcept(std::is_fundamental<T>::value) {
  23. // This function is called by the rest and computes the actual nth fibonacci number
  24. // First few fibonacci numbers: 0 (0th), 1 (1st), 1 (2nd), 2 (3rd), ...
  25. if (n <= 2) return n == 0 ? 0 : 1;
  26. /*
  27. * This is based on the following identities by Dijkstra:
  28. * F(2*n-1) = F(n-1)^2 + F(n)^2
  29. * F(2*n) = (2*F(n-1) + F(n)) * F(n)
  30. * The implementation is iterative and is unrolled version of trivial recursive implementation.
  31. */
  32. unsigned long long mask = 1;
  33. for (int ct = 1; ct != std::numeric_limits<unsigned long long>::digits && (mask << 1) <= n; ++ct, mask <<= 1)
  34. ;
  35. T a{1}, b{1};
  36. for (mask >>= 1; mask; mask >>= 1) {
  37. T t1 = a * a;
  38. a = 2 * a * b - t1, b = b * b + t1;
  39. if (mask & n)
  40. t1 = b, b = b + a, a = t1; // equivalent to: swap(a,b), b += a;
  41. }
  42. return a;
  43. }
  44. template <typename T, class Policy>
  45. T inline BOOST_MATH_CXX14_CONSTEXPR fibonacci(unsigned long long n, const Policy &pol) {
  46. // check for overflow using approximation to binet's formula: F_n ~ phi^n / sqrt(5)
  47. if (n > 20 && n * detail::fib_bits_phi - detail::fib_bits_deno > std::numeric_limits<T>::digits)
  48. return policies::raise_overflow_error<T>("boost::math::fibonacci<%1%>(unsigned long long)", "Possible overflow detected.", pol);
  49. return unchecked_fibonacci<T>(n);
  50. }
  51. template <typename T>
  52. T inline BOOST_MATH_CXX14_CONSTEXPR fibonacci(unsigned long long n) {
  53. return fibonacci<T>(n, policies::policy<>());
  54. }
  55. // generator for next fibonacci number (see examples/reciprocal_fibonacci_constant.hpp)
  56. template <typename T>
  57. class fibonacci_generator {
  58. public:
  59. // return next fibonacci number
  60. T operator()() noexcept(std::is_fundamental<T>::value) {
  61. T ret = a;
  62. a = b, b = b + ret; // could've simply: swap(a, b), b += a;
  63. return ret;
  64. }
  65. // after set(nth), subsequent calls to the generator returns consecutive
  66. // fibonacci numbers starting with the nth fibonacci number
  67. void set(unsigned long long nth) noexcept(std::is_fundamental<T>::value) {
  68. n = nth;
  69. a = unchecked_fibonacci<T>(n);
  70. b = unchecked_fibonacci<T>(n + 1);
  71. }
  72. private:
  73. unsigned long long n = 0;
  74. T a = 0, b = 1;
  75. };
  76. } // namespace math
  77. } // namespace boost
  78. #endif