Taking inspiration from: Defining a piecewise function (e.g. polynomial)
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
struct Point {
double x;
double y;
};
class LinearFunction {
public:
// Pre-calculate slope `m` and intercept `c`
LinearFunction(const Point &A, const Point &B){
double den = A.x-B.x;
m = (A.y-B.y)/den;
c = (A.x*B.y-A.y*B.x)/den;
}
// Evaluate at x
double operator()(double x){
return m*x+c;
}
private:
double m = 0;
double c = 0;
};
class PiecewiseFunction {
public:
// Initialize (m and c) for all segments of the piecewise
// function as a map of <lb,ub> -> function pointer
explicit PiecewiseFunction(std::vector<Point> &points){
for (int i = 0; i < points.size()-1; i++){
auto f = LinearFunction(points[i], points[i+1]);
fns.insert(std::make_pair(std::make_pair(points[i].x, points[i+1].x), &f));
}
}
double operator()( double x ) {
// Match segment lb <= x < ub and evaluate
auto iter = std::find_if(fns.cbegin(), fns.cend(),
[=](const auto &fn) {return x>=fn.first.first && x<fn.first.second;});
if (iter == fns.end()){
return 0;
} else {
return iter->second->operator()(x);
}
}
private:
std::map< std::pair<double,double>, LinearFunction*> fns;
};
int main() {
std::vector<Point> points {{0,0},{0.5,1},{1,0}};
PiecewiseFunction f{points};
std::cout << "x = 0.5; f(x) = " << f(0.5) << std::endl;
return 0;
}
which produces undefined behaviour:
x = 0.5; f(x) = 1.04297e-309
as the auto f = LinearFunction(points[i], points[i+1]);
created in the loop goes out of scope.
I have been trying to find a solution that would let me create a piecewise function with e.g. 20 points