forked from 1chipML/1chipML
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfinite_difference.c
66 lines (59 loc) · 2.06 KB
/
finite_difference.c
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
#include "finite_difference.h"
#include <stdio.h>
#include <string.h>
/// @brief Approximates the gradient of a function using the first order finite
/// difference method.
/// @param func The function for which to approximate the gradient
/// @param point The point at which to appriximate the gradient
/// @param grad Return parameter containing the approximated gradient
/// @param n Number of dimensions of the function
/// @param eps Size of the step taken away from point for the approximation.
/// Lower eps should lead to better approximations. Should not be smaller than
/// the machine floating point precision.
/// @param type Type of finite difference approximation (Forward, Backward or
/// Central)
void gradientApproximation(function func, real point[], real grad[], int n,
real eps, approximationType type) {
// It is imperative to choose h so that x and x + h differ by an exactly
// representable number
// see:
// http://www.it.uom.gr/teaching/linearalgebra/NumericalRecipiesInC/c5-7.pdf
real h_next[n];
real h_prev[n];
volatile real temp;
for (int i = 0; i < n; i++) {
temp = point[i] + eps;
h_next[i] = temp - point[i];
temp = point[i] - eps;
h_prev[i] = point[i] - temp;
}
if (type == Forward) {
real next[n];
memcpy(next, point, n * sizeof(real));
for (int i = 0; i < n; i++) {
next[i] += h_next[i];
grad[i] = (func(next) - func(point)) / h_next[i];
next[i] -= h_next[i];
}
} else if (type == Backward) {
real prev[n];
memcpy(prev, point, n * sizeof(real));
for (int i = 0; i < n; i++) {
prev[i] -= h_prev[i];
grad[i] = (func(point) - func(prev)) / h_prev[i];
prev[i] += h_prev[i];
}
} else {
real next[n];
real prev[n];
memcpy(next, point, n * sizeof(real));
memcpy(prev, point, n * sizeof(real));
for (int i = 0; i < n; i++) {
next[i] += h_next[i];
prev[i] -= h_prev[i];
grad[i] = (func(next) - func(prev)) / (h_prev[i] + h_next[i]);
prev[i] += h_prev[i];
next[i] -= h_next[i];
}
}
}