Polynomdivision, weiß nich was ich falschmache
-
Bashar schrieb:
irreduzible Polynome über IR den Höchstgrad 2 haben.
Ok, hab es nachgelesen.
@Uederli: Habe grad keinen Compiler zur Hand um zu Testen.
-
also ich habs ja getestet und es funktioniert, wie beschrieben, leider nicht.
dann kann es ja eigentlich nicht an diesen Ungenauigkeiten im Dualsystem liegen
-
Ich habe das jetzt folgendermaßen umfgeformt:
double pol = -1000.0; double addpol = 0.1; for ( double loop_pol = -1005; loop_pol < 1000; loop_pol += 0.1) { pol += addpol; cout << " " << pol; if( aa*pol*pol*pol + bb*pol*pol + cc*pol + dd > -1 && aa*pol*pol*pol + bb*pol*pol + cc*pol + dd< 1) { x1 = pol; double p = (bb+x1*aa)/aa; double q = (cc+x1*bb+x1*x1*aa)/aa; x2 = -(p/2)+ sqrt(((p*p)/4)-q); x3 = -(p/2)- sqrt(((p*p)/4)-q); cout << "\n x1 = " << x1; cout << "\n x2 = " << x2; cout << "\n x3 = " << x3; getch(); break; } }
demnach müsste es bei einer Abweichung auch klappen, aber es funktioniert trotzdem nicht.
Die Zeile
cout << " " << pol;
gibt dann ja aus, was pol gerade ist. Und da werden immer die exaten Zahlen angezeigt, also keine Abweichung.
Hat einer eine Idee warum es immernochnicht klappt?
-
double pol = -1000.0; double addpol = 0.01; for ( double loop_pol = -1005; loop_pol < 1000; loop_pol += 0.01) { pol += addpol; if( aa*pol*pol*pol + bb*pol*pol + cc*pol + dd > -0.1 && aa*pol*pol*pol + bb*pol*pol + cc*pol + dd< 0.1) { x1 = pol; double p = (bb+x1*aa)/aa; double q = (cc+x1*bb+x1*x1*aa)/aa; x2 = -(p/2)+ sqrt(((p*p)/4)-q); x3 = -(p/2)- sqrt(((p*p)/4)-q); cout << "\n x1 = " << x1; cout << "\n x2 = " << x2; cout << "\n x3 = " << x3; getch(); break; } }
Es klappt!!!
Vielen Dank für eure Hilfe!!
Es war letzten endes also doch die Abweichung, die entsteht, wenn man 0,1 addiert
-
Das ist trotzdem numerisch noch sehr ungeschickt.
Alternativvorschlag: Teste, ob ein Vorzeichenwechsel stattfindet. Wenn Du also in kleinen Schritten "von links nach rechts" läufst und einen solchen Vorzeichenwechsel entdeckst, kannst Du dieses Intervall, was durch die zwei letzten Stellen gegeben ist die Nullstelle enthalten muss und, gesondert betrachten (zB mit dem Sekantenverfahren).
-
Ich versehe jetzt nicht ganz was du meinst.
Teste, ob ein Vorzeichenwechsel stattfindet.
ich dachte das mache ich mit:
if( aa*pol*pol*pol + bb*pol*pol + cc*pol + dd > -0.00001 && aa*pol*pol*pol + bb*pol*pol + cc*pol + dd< 0.00001)
was meinst du mit:
gesondert betrachten
?
-
Dein Problem ist, dass dein Verfahren zu ungenau ist. Wenn du in 0.01-er Schritten suchst, kriegst du eben auch keine besser Genauigkeit als 0.01. Es gibt aber Verfahren, mit denen man beliebig exakte Näherungen von Nullstellen erhalten kann, darunter ist z.B. das Sekantenverfahren.
-
Uederli schrieb:
Ich versehe jetzt nicht ganz was du meinst.
Teste, ob ein Vorzeichenwechsel stattfindet.
ich dachte das mache ich mit:
if( aa*pol*pol*pol + bb*pol*pol + cc*pol + dd > -0.00001 && aa*pol*pol*pol + bb*pol*pol + cc*pol + dd< 0.00001)
Nee nee nee, ich dachte da eher an so etwas wie
#include <iostream> struct poly3 { double a,b,c,d; explicit poly3(double a=0, double b=0, double c=0, double d=0) : a(a),b(b),c(c),d(d) {} double operator()(double x) const { return d+x*(c+x*(b+x*a)); } }; poly3 ableiten(poly3 const& p) { return poly3(0, 3*p.a, 2*p.b, p.c); } double newton(poly3 const& p, double x, int wieoft) { poly3 const d = ableiten(p); for (int k=0; k<wieoft; ++k) { double y = p(x); double m = d(x); x -= y/m; } return x; } int main() { poly3 p (1.00, 1.72, -6.36, -7.20); double oldx = 0; double oldy = 0; for (int i=-100; i<=100; ++i) { double x = i * 0.1; double y = p(x); if (i>-100) { if (y*oldy<=0) { // Irgendwo zwischen oldx und x muss eine Nullstelle sein // Initiale Schaetzung durch Sekante: double n = oldx + -oldy/(y-oldy)*(x-oldx); n = newton(p,n,5); std::cout << "Nullstelle bei x=" << n << ", p(x)=" << p(n) << '\n'; } } oldx = x; oldy = y; } }
-
nix
-
-
ich bin noch ein Anfänger in C++. Ich verstehe das programm nicht ganz. Das ist jetzt vermutlich nach dem Newton-Verfahren oder Bairstow-Verfahren?.
Wäre das programm so komplett?
#include <iostream> #include <conio.h> using namespace std; struct poly3 { double a,b,c,d; explicit poly3(double a=0, double b=0, double c=0, double d=0) : a(a),b(b),c(c),d(d) {} double operator()(double x) const { return d+x*(c+x*(b+x*a)); } }; poly3 ableiten(poly3 const& p) { return poly3(0, 3*p.a, 2*p.b, p.c); } double newton(poly3 const& p, double x, int wieoft) { poly3 const d = ableiten(p); for (int k=0; k<wieoft; ++k) { double y = p(x); double m = d(x); x -= y/m; } return x; } int main() { double a, b, c, d; cout << "\n\tKubische Gleichungen loesen"; cout << "\n\n Grungstrucktur : a*x^3 + b*x^2 + c*x + d = 0"; cout << "\n\n a eingeben: "; cin >> a; cout << "\n b eingeben: "; cin >> b; cout << "\n c eingeben: "; cin >> c; cout << "\n d eingeben: "; cin >> d; poly3 p (a, b, c, d); double oldx = 0; double oldy = 0; for (int i=-100; i<=100; ++i) { double x = i * 0.1; double y = p(x); if (i>-100) { if (y*oldy<=0) { // Irgendwo zwischen oldx und x muss eine Nullstelle sein // Initiale Schaetzung durch Sekante: double n = oldx + -oldy/(y-oldy)*(x-oldx); n = newton(p,n,5); std::cout << "Nullstelle bei x=" << n << ", p(x)=" << p(n) << '\n'; } } oldx = x; oldy = y; } getch(); return 0; }
Das Ergebnis wird allerdings noch doppelt angezeigt
Aber reicht nicht das folgende von der genauigkeit aus:
double pol = -1000.0; double addpol = 0.000001; for ( double loop_pol = -1005; loop_pol < 1000; loop_pol += 0.000001) { pol += addpol; if ( loop_pol == -1005) cout << "\nBitte warten, es wird gerechnet..." << endl; if( aa*pol*pol*pol + bb*pol*pol + cc*pol + dd > -0.00001 && aa*pol*pol*pol + bb*pol*pol + cc*pol + dd< 0.00001) { x1 = pol; double p = (bb+x1*aa)/aa; double q = (cc+x1*bb+x1*x1*aa)/aa; x2 = -(p/2)+ sqrt(((p*p)/4)-q); x3 = -(p/2)- sqrt(((p*p)/4)-q); cout << "\n x1 = " << x1; cout << "\n x2 = " << x2; cout << "\n x3 = " << x3; getch(); break; } }
Ich will das vor allem bei der Kurvendiskussoin von funktionen polynomialer Strucktur verwenden.
Da müsste die Ganauigkeit doch ausreichen, nur die berechnung dauert sehr lange
-
Uederli schrieb:
ich bin noch ein Anfänger in C++. Ich verstehe das programm nicht ganz.
Zunächst wird die Funktion von -10 bis 10 in 0.1 Schritten abgetastet. Ist das Produkt von benachbarten Funktionswerten kleiner oder gleich 0, hat ein Vorzeichenwechsel stattgefunden. Daher muss in dem Intervall, was durch diese zwei Stellen gegeben ist, eine Nullstelle sein. Es wird nun eine "Sekante" durch die benachbarten Punkte gelegt und der Schnittpunkt mit der x-Achse als initiale Schätzung der Nullstelle bestimmt. Danach wird die Newton-Iteration 5mal durchgeführt. Das ist sicherlich nicht das robusteste, was man machen kann, aber immerhin ein Ansatz.
Uederli schrieb:
Das Ergebnis wird allerdings noch doppelt angezeigt
Kann gut sein. Das Verfahren funktioniert nur einigermaßen, falls höchstens eine Nullstelle zwischen den Abtastpunkten liegt. Wenn bei Dir eine Nullstelle einem Abtastpunkt entpricht, kann es sein, dass diese 2mal ausgegeben wird, einmal von der linken und einmal von der rechten Seite ausgehend (benachbarte Intervalle).
Wirklich super duper robuste "black box" Algorithmen sind wahrscheinlich komplizierter.