Loading...
Searching...
No Matches
factorial.h
Go to the documentation of this file.
1#ifndef _BBM_FACTORIAL_H_
2#define _BBM_FACTORIAL_H_
3
4#include <limits>
5#include <functional>
6#include "core/error.h"
7
8/************************************************************************/
9/*! \file factorial.h
10
11 \brief Compute the factorial (uses precomputation to speed up run time
12 querries).
13
14************************************************************************/
15
16namespace bbm {
17
18 /*** Implementation detail for determing the largest value v for which: (v--)++ = v ***/
19 namespace detail {
20
21 template<typename T> requires std::integral<T>
22 constexpr T max_int(void)
23 {
24 return std::numeric_limits<T>::max();
25 }
26
27 template<typename T> requires std::floating_point<T>
28 constexpr T max_int(void)
29 {
30 return (1ull << (std::numeric_limits<T>::digits));
31 }
32
33 };
34
35 /**********************************************************************/
36 /*! \brief Returns the largest possible factorial index for a given type
37 that does not result in an overflow.
38
39 \tparam T = type to compute factorial in (default = unsigned long long int)
40 \returns max factorial index
41 **********************************************************************/
42 template<typename T=unsigned long long int> requires std::integral<T> || std::floating_point<T>
43 consteval size_t max_factorial(void)
44 {
45 size_t n=1;
46 T fac = bbm::detail::max_int<T>();
47 while(fac > n) fac /= n++;
48 return n;
49 }
50
51
52 /*** Precompute at compile time a table of factorials ***/
53 namespace precomputed {
54
55 static constexpr auto factorials = []<size_t... N>(std::index_sequence<N...>)
56 {
57 unsigned long long int acc=1;
58 return std::array<unsigned long long int, max_factorial<unsigned long long int>()+2>{ 1, (acc*=(N+1))...}; // 0! is hardcoded as 1; also include max_factorial (thus length = +2)
59 }(std::make_index_sequence<max_factorial<unsigned long long int>()+1>{});
60
61 }
62
63 /********************************************************************/
64 /*! \brief Compute n!
65
66 \tparam T = type to return (default = unsigned long long int)
67 \returns n!
68
69 Throws an exception if n > max_factorial<T>.
70
71 *********************************************************************/
72 template<typename T=unsigned long long int>
73 constexpr T factorial(size_t n)
74 {
75 // check range
76 if (n > max_factorial<T>()) throw bbm_out_of_range;
77
78 // return precomputed value from array
79 return T(precomputed::factorials[n]);
80 }
81
82} // end bbm namespace
83
84#endif /* _BBM_FACTORIAL_H_ */
Predefined exceptions for common errors.
#define bbm_out_of_range
Definition: error.h:44
static constexpr auto factorials
Definition: factorial.h:55
Definition: aggregatebsdf.h:29
consteval size_t max_factorial(void)
Returns the largest possible factorial index for a given type that does not result in an overflow.
Definition: factorial.h:43
constexpr T factorial(size_t n)
Compute n!
Definition: factorial.h:73