Иногда в прикладной задаче возникает необходимость по уже известным точкам некоторой функции что-нибудь рассчитать, но при этом в расчете требуются промежуточные значения, которые по каким-то причинам не были приложены к исходным данным или же не были вычислены. В таком случае, можно попытаться получить значения функции в промежуточных точках с помощью процедур интерполяции, и в таком случае вас выручит этот несложный рецепт.
Если у вас возникла необходимость воспользоваться точечной интерполяцией, то в этом случае вам поможет небольшой класс, который реализует интерполяцию посредством полиномов Лагранжа:
class LagrangeInterpolator { private: float[] xi; float[] yi; float basePolynom(float x, size_t n) { float product = 1; for (size_t i = 0; i < xi.length; i++) { if (i != n) { product *= (x - xi[i]) / (xi[n] - xi[i]); } } return product; } public: this() { } void setX(float[] xi) { this.xi = xi; } void setY(float[] yi) { this.yi = yi; } float interpolate(float x) { float sum = 0.0f; for (size_t i = 0; i < yi.length; i++) { sum += yi[i] * basePolynom(x, i); } return sum; } } unittest { LagrangeInterpolator interpolator = new LagrangeInterpolator; interpolator.setX([0.0, 4.0, 6.0, 7.0, 8.0]); interpolator.setY([0.0, 2.0, 4.0, 6.0, 8.0]); assert(interpolator.interpolate(5.0) == 2.58929); assert(interpolator.interpolate(0.0) == 0.0); assert(interpolator.interpolate(6.0) == 4.0); }
Сам класс очень просто устроен, а единственным используемым алгоритмом класса является метод interpolate, который просто вычисляет промежуточное значение Y для некоторой точки с уже известной координатой X. Таким образом, LagrangeInterpolator лучше всего использовать с некоторыми массивами известных значений функции, которые предварительно загружаются в объект класса с помощью тривиальных методов setX и setY, после применения которых и следует вызвать метод interpolate.
Загрузить значения для X и Y функции в интерполятор можно не только из заранее подготовленных массивов, но и к примеру из обычного CSV-файла, для чего можно воспользоваться готовым загрузчиком - функцией readDataFromCSV, которая возвратит уже подготовленный к работе экземпляр LagrangeInterpolator:
auto readDataFromCSV(string filename, LagrangeInterpolator interpolator) { import std.algorithm; import std.array; import std.csv; import std.stdio; import std.typecons; float[] xi, yi; auto file = File(filename, "r"); void addPoint(float x, float y) { xi ~= x; yi ~= y; } file .byLine .joiner("\n") .csvReader!(Tuple!(float, float)) .each!(a => addPoint(a[0], a[1])); interpolator.setX(xi); interpolator.setY(yi); return interpolator; }
Естественно, помимо CSV-файлов возможно использование других форматов файла, но иногда бывает и так, что чего-то более хорошего, чем CSV-файла под рукой нет.
P.S: Более подробно про методы интерполяции вы можете узнать из курса математического анализа или же просто можете посмотреть сведения по ссылке, которая была указана выше.