-
Notifications
You must be signed in to change notification settings - Fork 5
/
gausslegendre.h
92 lines (71 loc) · 2.73 KB
/
gausslegendre.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#ifndef GAUSSLEGENDRE_H
#define GAUSSLEGENDRE_H
#include <functional>
#include <vector>
#include <cmath>
class LegendrePolynomial {
public:
LegendrePolynomial(double lowerBound, double upperBound, size_t numberOfIterations)
: mLowerBound(lowerBound), mUpperBound(upperBound), mNumberOfIterations(numberOfIterations), mWeight(numberOfIterations+1), mRoot(numberOfIterations+1) {
calculateWeightAndRoot();
}
const std::vector<double> & getWeight() const {
return mWeight;
}
const std::vector<double> & getRoot() const {
return mRoot;
}
private:
const static double EPSILON;
struct Result {
double value;
double derivative;
Result() : value(0), derivative(0) {}
Result(double val, double deriv) : value(val), derivative(deriv) {}
};
void calculateWeightAndRoot() {
for(int step = 0; step <= mNumberOfIterations; step++) {
double root = cos(M_PI * (step-0.25)/(mNumberOfIterations+0.5));
Result result = calculatePolynomialValueAndDerivative(root);
double newtonRaphsonRatio;
do {
newtonRaphsonRatio = result.value/result.derivative;
root -= newtonRaphsonRatio;
result = calculatePolynomialValueAndDerivative(root);
} while (fabs(newtonRaphsonRatio) > EPSILON);
mRoot[step] = root;
mWeight[step] = 2.0/((1-root*root)*result.derivative*result.derivative);
}
}
Result calculatePolynomialValueAndDerivative(double x) {
Result result(x, 0);
double value_minus_1 = 1;
const double f = 1/(x*x-1);
for(int step = 2; step <= mNumberOfIterations; step++) {
const double value = ((2*step-1)*x*result.value-(step-1)*value_minus_1)/step;
result.derivative = step*f*(x*value - result.value);
value_minus_1 = result.value;
result.value = value;
}
return result;
}
const double mLowerBound;
const double mUpperBound;
const int mNumberOfIterations;
std::vector<double> mWeight;
std::vector<double> mRoot;
};
const double LegendrePolynomial::EPSILON = 1e-15;
double gaussLegendreIntegral(double a, double b, int n, const std::function<double (double)> &f) {
const LegendrePolynomial legendrePolynomial(a, b, n);
const std::vector<double> & weight = legendrePolynomial.getWeight();
const std::vector<double> & root = legendrePolynomial.getRoot();
const double width = 0.5*(b-a);
const double mean = 0.5*(a+b);
double gaussLegendre = 0;
for(int step = 1; step <= n; step++) {
gaussLegendre += weight[step]*f(width * root[step] + mean);
}
return gaussLegendre * width;
}
#endif