umask007
Lt. Junior Grade
- Registriert
- Dez. 2012
- Beiträge
- 370
Hallo,
ich schreibe gerade einen neuen Algorithmus, um die Nullstellen von Polynomen beliebigen Grades zu berechnen.
Der Algorithmus basiert auf dem Newtonverfahren (https://de.wikipedia.org/wiki/Newtonverfahren).
Mittels der Formel x=x-f(x)/f'(x) nähert sich das Newtonverfahren schrittweise einer Nullstelle.
Das Problem bei dem Verfahren ist, dass es scheitert, wenn f'(x) null ist, da man bekannterweise nicht durch null teilen kann. Meine Idee zur Verbesserung des Verfahrens ist simpel: Man teilt
die Funktion in Intervalle auf, in denen f'(x) != null ist, führt das Verfahren separat für jedes Intervall aus
und fügt die Ergebnisse zusammen. Man braucht um die Nullstellen zu berechnen also zuerst die Nullstellen
der Ableitung, weshalb zuerst die Nullstellen aller Ableitungen in aufsteigender Reihenfolge berechnet werden.
Hier der Beispielcode:
Mich würde mal Eure Meinung zum neuen Algorithmus interessieren. Am interessantesten ist für mich, ob der Algorithmus auch alle Nullstellen findet. Da ich kein Mathematiker bin, habe ich auch keine Ahnung, wie man einen formellen Beweis für einen solchen Algorithmus schreiben könnte. Habe den Algorithmus stattdessen intensiv mit Unit Tests geprüft. Der Algorithmus kann sogar das Wilkinson Polynom lösen (https://en.wikipedia.org/wiki/Wilkinson's_polynomial) von daher denke ich, dass der Algorithmus auf jeden Fall auf die ein oder andere Weise nützlich sein wird.
Hier ist der komplette Code:
https://github.com/P3N9U1N/superacid
Hier ist eine GUI zum Testen:
https://p3n9u1n.github.io/superacid/gui/index.html
Viele Grüße, Thomas
ich schreibe gerade einen neuen Algorithmus, um die Nullstellen von Polynomen beliebigen Grades zu berechnen.
Der Algorithmus basiert auf dem Newtonverfahren (https://de.wikipedia.org/wiki/Newtonverfahren).
Mittels der Formel x=x-f(x)/f'(x) nähert sich das Newtonverfahren schrittweise einer Nullstelle.
Das Problem bei dem Verfahren ist, dass es scheitert, wenn f'(x) null ist, da man bekannterweise nicht durch null teilen kann. Meine Idee zur Verbesserung des Verfahrens ist simpel: Man teilt
die Funktion in Intervalle auf, in denen f'(x) != null ist, führt das Verfahren separat für jedes Intervall aus
und fügt die Ergebnisse zusammen. Man braucht um die Nullstellen zu berechnen also zuerst die Nullstellen
der Ableitung, weshalb zuerst die Nullstellen aller Ableitungen in aufsteigender Reihenfolge berechnet werden.
Hier der Beispielcode:
Javascript:
export function superacid(polynom:Decimal[],accuracy:Decimal=new Decimal(0.01), newtonIterations:number=32):Decimal[]
{
/*
Simplify polynomial by dividing through the first coefficient.
Smaller coefficients mean less chance of overflowing.
*/
polynom=simplyfyPolynom(polynom);
var degree = polynom.length-1;
if (degree<=0) return null;
var polynoms=calculateDerivates(polynom); //calculate all derivatives
/*
Add polynomial to the list of polynomials, whose roots need to be calculated
*/
polynoms.unshift(polynom);
var c= degree;
var firstDegreeDerivation=polynoms[polynoms.length-2];
var derivateZeros:Decimal[]=[firstDegreeDerivation[1].neg().div(firstDegreeDerivation[0])];
var roots = derivateZeros;
/*
Calculate roots of polynomial and all its derivates, starting with lowest degree.
Roots are needed for calculating the roots of the polynom with the next degree.
*/
while (--c)
{
var fx= polynoms[c-1];
var fxx= polynoms[c];
roots=[];
/*
Intervals are located from -infinity to the first stationary point, in between neigbouring
stationary points, and from the last stationary point to +infinity. Because of that, the zeros
of the derivate are needed, calculated in the last loop iteration.
In each interval there is at most one zero, because the sign of the derivative is constant.
*/
var intervals= getIntervalsInPolynom(...derivateZeros);
for( var interval of intervals)
{ //Do Newton iterations seperately for each interval
var root=newtonIterate(fx,fxx,interval.left,interval.right,interval.start,newtonIterations,accuracy);
if (root==null) continue;
//skip next interval, because root will be the same as in the current interval
if (interval.right.minus(root).abs().lessThan(accuracy)) intervals.next();
roots.push(root); //Add root to the list of found roots
}
derivateZeros=roots; //Roots are needed for calculating the next intervals
}
return roots; // return found roots
}
Mich würde mal Eure Meinung zum neuen Algorithmus interessieren. Am interessantesten ist für mich, ob der Algorithmus auch alle Nullstellen findet. Da ich kein Mathematiker bin, habe ich auch keine Ahnung, wie man einen formellen Beweis für einen solchen Algorithmus schreiben könnte. Habe den Algorithmus stattdessen intensiv mit Unit Tests geprüft. Der Algorithmus kann sogar das Wilkinson Polynom lösen (https://en.wikipedia.org/wiki/Wilkinson's_polynomial) von daher denke ich, dass der Algorithmus auf jeden Fall auf die ein oder andere Weise nützlich sein wird.
Hier ist der komplette Code:
https://github.com/P3N9U1N/superacid
Hier ist eine GUI zum Testen:
https://p3n9u1n.github.io/superacid/gui/index.html
Viele Grüße, Thomas