谢谢戴文和罗曼。我用了拉格朗日,现在效果很好。例如,如果给定 3 个点 (1,1)、(2,3)、(3,27),则该类将使用拉格朗日来计算多项式逼近。现在你可以调用 $system->f(4) 来计算这个多项式上 x=4 的 y 值。
<?php
$system = new EQ();
$system->add(1, 1);
$system->add(2, 3);
$system->add(3, 27);
echo $system->f(4);
class EQ {
private $points = array();
private $formula = NULL;
public function add($x, $y) {
$this->points[] = array($x, $y);
}
public function lz($z) {
$point = $this->points[$z];
// Get the x and y value of this point
$x = $point[0];
$y = $point[1];
// Now get all points except these and build the formula
$index = 0;
$above = '';
$below = 1;
foreach ($this->points as $point) {
if ($index != $z) {
$xp = $point[0];
$yp = $point[1];
$above .= '(x-' . $xp . ')';
$below *= ($x - $xp);
}
$index++;
}
$factor = $y / $below;
$above = ungroup($above);
foreach ($above as $degree=>$subfactor) {
$above[$degree] = $subfactor * $factor;
}
return $above;
}
public function f($x) {
if ($this->formula === NULL) $this->L();
$formula = $this->formula;
$val = 0;
foreach ($formula as $degree=>$factor) {
$subval = $factor * pow($x, $degree);
$val += $subval;
}
return $val;
}
public function L() {
$n = count($this->points);
$formula = array();
for ($z = 0; $z < $n; $z++) {
$l = $this->lz($z);
foreach ($l as $degree=>$factor) {
$formula[$degree] += $factor;
}
}
$this->formula = $formula;
return $formula;
}
}
// Transform a group-formula to a list with terms
// @example (x-1)*(x-2)
function ungroup($formula) {
preg_match_all('/\(([^)]{1,})\)/', $formula, $matches);
$groups = $matches[1];
$factorTerms = getTerms(reset($groups));
while (key($groups) < count($groups) - 1) {
next($groups);
$terms = getTerms(current($groups));
$newTerms = array();
foreach ($terms as $term) {
foreach ($factorTerms as $factorTerm) {
$degree = getDegree($term) + getDegree($factorTerm);
$factor = getFactor($term) * getFactor($factorTerm);
$newTerm = '';
if ($factor != 1) $newTerm = ($factor == -1?'-':$factor);
if ($degree != 0) $newTerm .= 'x' . ($degree == 1?'':'^' . $degree);
if (strlen($newTerm) == 0) $newTerm = '0';
$newTerms[] = $newTerm;
}
}
$factorTerms = $newTerms;
}
$terms = array();
foreach ($factorTerms as $term) {
$degree = getDegree($term);
$factor = getFactor($term);
$terms[$degree] += $factor;
}
return $terms;
}
function getFactor($term) {
if (strpos($term, 'x') !== false) {
$pattern = '/([0-9\-]{1,})[\*]?x/';
preg_match($pattern, $term, $matches);
if (count($matches) == 2) {
$n = $matches[1];
if ($n === '-') return -1;
return $n;
}
return 1;
}
return $term;
}
function getDegree($term) {
if (strpos($term, 'x') !== false) {
$pattern = '/x\^([0-9\-]{1,})/';
preg_match($pattern, $term, $matches);
if (count($matches) == 2) {
return $matches[1];
}
return 1;
}
return 0;
}
function getTerms($group) {
$group = str_replace('-', '+-', $group);
$group = preg_replace('/\+{1,}/', '+', $group);
$terms = explode('+', $group);
return $terms;
}
?>