-
Notifications
You must be signed in to change notification settings - Fork 0
/
richardson.cpp
66 lines (55 loc) · 1.77 KB
/
richardson.cpp
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
/*
* richardson.cpp
*
* Library functions for Richardson Extrapolation.
*/
#include "richardson.h"
#include <cstdlib>
#include <gmp.h>
namespace richardson {
void extrapolate(index_t num_samples, index_t start_index,
SequenceFunc f, mpf_t ans) {
// Calculate the desired samples, then pass to the other extrapolate
// function.
mpf_t *samples = (mpf_t*)malloc(sizeof(mpf_t) * num_samples);
mpf_t *lim = samples + num_samples;
mp_bitcnt_t precision = mpf_get_prec(ans);
for (mpf_t *ptr = samples; ptr < lim; ptr++, start_index <<= 1) {
mpf_init2(*ptr, precision);
f(start_index, *ptr);
}
extrapolate(num_samples, samples, ans);
// Clean
for (mpf_t *ptr = samples; ptr < lim; ptr++)
mpf_clear(*ptr);
free(samples);
}
void extrapolate(index_t num_samples, mpf_t *samples, mpf_t ans) {
// The Richardson extrapolation recursive formula is
//
// A_n+1(x) = (2^n A_n(2x) - A_n(x)) / (2^n - 1)
mpf_t mult; // mult = 2^n
mpf_init_set_d(mult, 1);
mpf_t denom; // denom = 1 / (mult - 1)
mp_bitcnt_t precision = mpf_get_prec(ans);
mpf_init2(denom, precision);
mpf_t *end = samples + num_samples;
for (mpf_t *lim = samples; lim < end; lim++) { // lim - samples = n
mpf_mul_ui(mult, mult, 2);
mpf_set(denom, mult);
mpf_sub_ui(denom, denom, 1);
mpf_ui_div(denom, 1, denom);
// evaluate all extrapolations
for (mpf_t *ptr = end; --ptr > lim; ) {
// A_n+1(x) = (mult A_n(2x) - A_n(x)) * denom
mpf_mul(*ptr, *ptr, mult);
mpf_sub(*ptr, *ptr, *(ptr - 1));
mpf_mul(*ptr, *ptr, denom);
}
}
mpf_set(ans, *(end - 1)); // move to ans
// Clean
mpf_clear(mult);
mpf_clear(denom);
}
}