Как рассчитать коэффициенты полинома с помощью интерполяции Лагранжа - PullRequest
13 голосов
/ 25 марта 2012

Мне нужно вычислить коэффициенты полинома, используя лагранжевый интерполяционный полином , в качестве домашней работы я решаю сделать это в Javascript.

вот определение полинома Лагранжа (L (x))

enter image description here

Лагранжевы базисные полиномы определены следующим образом

enter image description here

Вычислить значение y для конкретной функции X (W (x)) просто, но мне нужно вычислить коэффициенты полинома (массив [a0, a1, ..., an]). Мне нужно сделать это для n <= 10, но было бы хорошо иметь произвольное n, тогда я могу поместить эту функцию в функцию хорнера и нарисовать этот полином. </p>

enter image description here

У меня есть функция, которая вычисляет знаменатель в первом уравнении

function denominator(i, points) {
   var result = 1;
   var x_i = points[i].x;
   for (var j=points.length; j--;) {
      if (i != j) {
        result *= x_i - points[j].x;
      }
   }
   return result;
}

и функция, возвращающая y методом Хорнера (у меня также есть функция рисования с использованием canvas)

function horner(array, x_scale, y_scale) {
   function recur(x, i, array) {
      if (i == 0) {
         return x*array[0];
      } else {
         return array[i] + x*recur(x, --i, array);
      }
   }
   return function(x) {
      return recur(x*x_scale, array.length-1, array)*y_scale;
   };
}

кто-нибудь знает алгоритм, чтобы сделать это, или идею, как рассчитать эти коэффициенты

Ответы [ 2 ]

8 голосов
/ 25 марта 2012

Ну, вы можете сделать это наивным способом. Представляем полином массивом его коэффициентов, массивом

[a_0,a_1,...,a_n]

соответствует a_0 + a_1*X + ... + a_n*X^n. Я плохо разбираюсь в JavaScript, поэтому псевдокод должен будет сделать:

interpolation_polynomial(i,points)
    coefficients = [1/denominator(i,points)]
    for k = 0 to points.length-1
        if k == i
            next k
        new_coefficients = [0,0,...,0] // length k+2 if k < i, k+1 if k > i
        if k < i
            m = k
        else
            m = k-1
        for j = m downto 0
            new_coefficients[j+1] += coefficients[j]
            new_coefficients[j] -= points[k]*coefficients[j]
        coefficients = new_coefficients
    return coefficients

Начните с постоянного многочлена 1/((x_1-x_0)* ... *(x_i-x_{i-1})*(x_i-x_{i+1})*...*(x_i-x_n)) и умножьте на X - x_k для всех k != i. Таким образом, это дает коэффициенты для L i , тогда вы просто умножаете их на y i (вы можете сделать это, инициализируя coefficients в y_i/denominator(i,points), если вы передадите значения y в качестве параметров) и добавьте все коэффициенты вместе, наконец.

polynomial = [0,0,...,0] // points.length entries
for i = 0 to points.length-1
    coefficients = interpolation_polynomial(i,points)
    for k = 0 to points.length-1
        polynomial[k] += y[i]*coefficients[k]

Расчет каждого L i равен O (n²), поэтому общий расчет равен O (n³).

Обновление: В вашем jsFiddle у вас была ошибка в цикле умножения полиномов, в дополнение к (теперь исправленной) ошибке с начальным индексом, который я сделал, должно быть

for (var j= (k < i) ? (k+1) : k; j--;) {
     new_coefficients[j+1] += coefficients[j];
     new_coefficients[j] -= points[k].x*coefficients[j];
}

Так как при тестировании вы уменьшаете j, нужно начинать на 1 выше.

Это пока не дает правильной интерполяции, но, по крайней мере, более разумно, чем раньше.

Кроме того, в вашей функции horner,

function horner(array, x_scale, y_scale) {
   function recur(x, i, array) {
      if (i == 0) {
         return x*array[0];
      } else {
         return array[i] + x*recur(x, --i, array);
      }
   }
   return function(x) {
      return recur(x*x_scale, array.length-1, array)*y_scale;
   };
}

Вы умножаете самый высокий коэффициент в два раза на x, это должно быть

if (i == 0) {
    return array[0];
}

вместо этого. Тем не менее, хорошего результата нет.

Обновление2: Окончательные исправления опечаток, следующие работы:

function horner(array, x_scale, y_scale) {
   function recur(x, i, array) {
      if (i == 0) {
         return array[0];
      } else {
         return array[i] + x*recur(x, --i, array);
      }
   }
   return function(x) {
      return recur(x*x_scale, array.length-1, array)*y_scale;
   };
}

// initialize array
function zeros(n) {
   var array = new Array(n);
   for (var i=n; i--;) {
     array[i] = 0;
   }
   return array;
}

function denominator(i, points) {
   var result = 1;
   var x_i = points[i].x;
   for (var j=points.length; j--;) {
      if (i != j) {
        result *= x_i - points[j].x;
      }
   }
    console.log(result);
   return result;
}

// calculate coefficients for Li polynomial
function interpolation_polynomial(i, points) {
   var coefficients = zeros(points.length);
    // alert("Denominator " + i + ": " + denominator(i,points));
   coefficients[0] = 1/denominator(i,points);
    console.log(coefficients[0]);
    //new Array(points.length);
   /*for (var s=points.length; s--;) {
      coefficients[s] = 1/denominator(i,points);
   }*/
   var new_coefficients;

   for (var k = 0; k<points.length; k++) {
      if (k == i) {
        continue;
      }
      new_coefficients = zeros(points.length);
       for (var j= (k < i) ? k+1 : k; j--;) {
         new_coefficients[j+1] += coefficients[j];
         new_coefficients[j] -= points[k].x*coefficients[j];
      }   
      coefficients = new_coefficients;
   }
   console.log(coefficients);
   return coefficients;
}

// calculate coefficients of polynomial
function Lagrange(points) {
   var polynomial = zeros(points.length);
   var coefficients;
   for (var i=0; i<points.length; ++i) {
     coefficients = interpolation_polynomial(i, points);
     //console.log(coefficients);
     for (var k=0; k<points.length; ++k) {
       // console.log(points[k].y*coefficients[k]);
        polynomial[k] += points[i].y*coefficients[k];
     }
   }
   return polynomial;
}
1 голос
/ 31 мая 2019

Вы можете найти коэффициенты интерполяционного полинома Лагранжа относительно легко, если вы используете матричную форму интерполяции Лагранжа, представленную в " Руководстве для начинающих по отображению симплексов аффинно ", раздел« Лагранжева интерполяция ». Боюсь, я не знаю JavaScript, чтобы предоставить вам соответствующий код, но я немного поработал с Python, возможно, может помочь следующее (извините за плохой стиль кода - Я математик, а не программист)

import numpy as np
# input
x = [0, 2, 4, 5]  # <- x's
y = [2, 5, 7, 7]  # <- y's
# calculating coefficients
M = [[_x**i*(-1)**(i*len(x)) for _x in x] for i in range(len(x))]
C = [np.linalg.det((M+[y]+M)[d:d+len(x)]) for d in range(len(x)+1)]
C = (C / C[0] * (-1)**(len(x)+1) )[1:]
# polynomial lambda-function
poly = lambda _x: sum([C[i] * _x**i for i in range(len(x))])
# output and tests
print("Coefficients:\n", C)
print("TESTING:")
for _x, _y in zip(x, y):
    result = "[OK]" if np.allclose(_y, poly(_x)) else "[ERROR]"
    print(_x, " mapped to: ", poly(_x), " ; expected: ", _y, result)

Этот код вычисляет коэффициенты интерполяционного полинома Лагранжа, печатает их и проверяет, что данные x сопоставлены с ожидаемыми y. Вы можете проверить этот код с помощью Google colab , поэтому вам не нужно ничего устанавливать. Возможно, вы сможете перевести его на JS.

...