Skip to content
Snippets Groups Projects
Commit c35a6fa5 authored by Van Herck, Walter's avatar Van Herck, Walter
Browse files

Remove FactorialList

parent 3a80b1c5
No related branches found
No related tags found
No related merge requests found
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
namespace { namespace {
const complex_t I = {0.,1.}; const complex_t I = {0.,1.};
const double eps = 2e-16; const double eps = 2e-16;
constexpr auto ReciprocalFactorialArray = Precomputed::GenerateReciprocalFactorialArray<171>();
} }
double PolyhedralFace::qpa_limit_series = 3e-2; double PolyhedralFace::qpa_limit_series = 3e-2;
...@@ -64,20 +65,20 @@ complex_t PolyhedralEdge::contrib(int M, cvector_t qpa, complex_t qrperp) const ...@@ -64,20 +65,20 @@ complex_t PolyhedralEdge::contrib(int M, cvector_t qpa, complex_t qrperp) const
if( M&1 ) // M is odd if( M&1 ) // M is odd
return 0.; return 0.;
else else
return Precomputed::ReciprocalFactorialArray[M] * ( pow(u, M)/(M+1.) - pow(v1, M) ); return ReciprocalFactorialArray[M] * ( pow(u, M)/(M+1.) - pow(v1, M) );
} }
complex_t ret = 0; complex_t ret = 0;
// the l=0 term, minus (qperp.R)^M, which cancels under the sum over E*contrib() // the l=0 term, minus (qperp.R)^M, which cancels under the sum over E*contrib()
if ( v1==0. ) { if ( v1==0. ) {
ret = Precomputed::ReciprocalFactorialArray[M] * pow(v2, M); ret = ReciprocalFactorialArray[M] * pow(v2, M);
} else if ( v2==0. ) { } else if ( v2==0. ) {
; // leave ret=0 ; // leave ret=0
} else { } else {
// binomial expansion // binomial expansion
for( int mm=1; mm<=M; ++mm ) { for( int mm=1; mm<=M; ++mm ) {
complex_t term = complex_t term =
Precomputed::ReciprocalFactorialArray[mm] * ReciprocalFactorialArray[mm] *
Precomputed::ReciprocalFactorialArray[M-mm] * ReciprocalFactorialArray[M-mm] *
pow(v2, mm) * pow(v1, M-mm); pow(v2, mm) * pow(v1, M-mm);
ret += term; ret += term;
#ifdef POLYHEDRAL_DIAGNOSTIC #ifdef POLYHEDRAL_DIAGNOSTIC
...@@ -90,8 +91,8 @@ complex_t PolyhedralEdge::contrib(int M, cvector_t qpa, complex_t qrperp) const ...@@ -90,8 +91,8 @@ complex_t PolyhedralEdge::contrib(int M, cvector_t qpa, complex_t qrperp) const
return ret; return ret;
for( int l=1; l<=M/2; ++l ) { for( int l=1; l<=M/2; ++l ) {
complex_t term = complex_t term =
Precomputed::ReciprocalFactorialArray[M-2*l] * ReciprocalFactorialArray[M-2*l] *
Precomputed::ReciprocalFactorialArray[2*l+1] * ReciprocalFactorialArray[2*l+1] *
pow(u, 2*l) * pow(v, M-2*l); pow(u, 2*l) * pow(v, M-2*l);
ret += term; ret += term;
#ifdef POLYHEDRAL_DIAGNOSTIC #ifdef POLYHEDRAL_DIAGNOSTIC
...@@ -250,7 +251,7 @@ complex_t PolyhedralFace::ff_n( int n, cvector_t q ) const ...@@ -250,7 +251,7 @@ complex_t PolyhedralFace::ff_n( int n, cvector_t q ) const
decompose_q( q, qperp, qpa ); decompose_q( q, qperp, qpa );
double qpa_mag2 = qpa.mag2(); double qpa_mag2 = qpa.mag2();
if ( qpa_mag2==0. ) { if ( qpa_mag2==0. ) {
return qn * pow(qperp*m_rperp, n) * m_area / Precomputed::FactorialArray[n]; return qn * pow(qperp*m_rperp, n) * m_area * ReciprocalFactorialArray[n];
} else if ( sym_S2 ) { } else if ( sym_S2 ) {
return qn * ( ff_n_core( n, qpa, qperp ) + ff_n_core( n, -qpa, qperp ) ) / qpa_mag2; return qn * ( ff_n_core( n, qpa, qperp ) + ff_n_core( n, -qpa, qperp ) ) / qpa_mag2;
} else { } else {
......
...@@ -22,48 +22,32 @@ ...@@ -22,48 +22,32 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
//! Compile-time generated std::arrays of factorials and their reciprocals //! Compile-time generated std::array of reciprocal factorials
namespace Precomputed namespace Precomputed
{ {
template<size_t N> template<size_t N>
struct Factorial struct ReciprocalFactorial
{ {
static constexpr double value = N*Factorial<N - 1>::value; static constexpr double value = ReciprocalFactorial<N-1>::value/N;
}; };
template<> template<>
struct Factorial<0> struct ReciprocalFactorial<0>
{ {
static constexpr double value = 1.0; static constexpr double value = 1.0;
}; };
template<size_t N>
struct ReciprocalFactorial
{
static constexpr double value = 1.0/Factorial<N>::value;
};
template<template<size_t> class F, size_t... I> template<template<size_t> class F, size_t... I>
constexpr std::array<double, sizeof...(I)> GenerateArrayHelper(std::index_sequence<I...>) constexpr std::array<double, sizeof...(I)> GenerateArrayHelper(std::index_sequence<I...>)
{ {
return { F<I>::value... }; return { F<I>::value... };
}; };
template<size_t N, typename Indices = std::make_index_sequence<N>>
constexpr std::array<double, N> GenerateFactorialArray()
{
return GenerateArrayHelper<Factorial>(Indices{});
};
template<size_t N, typename Indices = std::make_index_sequence<N>> template<size_t N, typename Indices = std::make_index_sequence<N>>
constexpr std::array<double, N> GenerateReciprocalFactorialArray() constexpr std::array<double, N> GenerateReciprocalFactorialArray()
{ {
return GenerateArrayHelper<ReciprocalFactorial>(Indices{}); return GenerateArrayHelper<ReciprocalFactorial>(Indices{});
}; };
static constexpr auto FactorialArray = GenerateFactorialArray<171>();
static constexpr auto ReciprocalFactorialArray = GenerateReciprocalFactorialArray<171>();
} // namespace Precomputed } // namespace Precomputed
#endif // PRECOMPUTED_H #endif // PRECOMPUTED_H
#include "Precomputed.h" #include "Precomputed.h"
#include <memory> #include <memory>
namespace {
constexpr auto ReciprocalFactorialArray = Precomputed::GenerateReciprocalFactorialArray<171>();
}
class PrecomputedTest : public ::testing::Test class PrecomputedTest : public ::testing::Test
{ {
public: public:
}; };
TEST_F(PrecomputedTest, Factorial) TEST_F(PrecomputedTest, ReciprocalFactorial)
{ {
const double eps = 2.3e-16; // about the machine precision const double eps = 2.3e-16; // about the machine precision
EXPECT_TRUE(Precomputed::FactorialArray.size()>150); EXPECT_TRUE(ReciprocalFactorialArray.size()>150);
EXPECT_DOUBLE_EQ(Precomputed::FactorialArray[0], 1.); EXPECT_DOUBLE_EQ(ReciprocalFactorialArray[0], 1.);
EXPECT_DOUBLE_EQ(Precomputed::FactorialArray[1], 1.); EXPECT_DOUBLE_EQ(ReciprocalFactorialArray[1], 1.);
EXPECT_DOUBLE_EQ(Precomputed::FactorialArray[2], 2.); EXPECT_DOUBLE_EQ(ReciprocalFactorialArray[2], 0.5);
EXPECT_DOUBLE_EQ(Precomputed::FactorialArray[3], 6.); EXPECT_DOUBLE_EQ(ReciprocalFactorialArray[3], 1.0/6);
/* the following disabled because tgamma is too unprecise under /* the following disabled because tgamma is too unprecise under
old versions of glibc (at leat up to 2.12, but less than 2.22) old versions of glibc (at leat up to 2.12, but less than 2.22)
for( size_t k=4; k<precomputed.factorial.size(); ++k ) for( size_t k=4; k<precomputed.factorial.size(); ++k )
EXPECT_NEAR(precomputed.factorial[k], tgamma(k+1.), 12*eps*tgamma(k+1.) ); EXPECT_NEAR(precomputed.factorial[k], tgamma(k+1.), 12*eps*tgamma(k+1.) );
*/ */
EXPECT_NEAR(Precomputed::FactorialArray[150], 5.71338395644585459e262, 4*eps*Precomputed::FactorialArray[150]); EXPECT_NEAR(ReciprocalFactorialArray[150], 1.75027620692601519e-263,
4*eps*ReciprocalFactorialArray[150]);
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment