Polynomdivision, weiß nich was ich falschmache



  • knivil schrieb:

    Über IR ist jedes Polynom vom Grade 3 oder höher faktorisierbar.

    Ich nehme mal an, dass mit IR die komplexen Zahlen gemeint sind.

    Du hast mit Mathematik nicht so viel am Hut, oder? IR steht für den Körper der reellen Zahlen.

    Vermutlich, weil sie ziemlich umständlich ist.

    Die Loesungsformeln sind schon so einfach wie moeglich.

    Aber vielleicht nicht einfach genug.



  • Bashar schrieb:

    Du hast mit Mathematik nicht so viel am Hut, oder?

    Doch schon, aber du hast geschrieben:

    Grade 3 oder höher

    Und ich ueberlege mir ein Polynom 4-ten Grades, das nicht faktorisierbar ist ... 🙂 Ich habe komplexe Zahlen nur vermutet, weil es bestimmt ein Polynom 4-ten Grades gibt, dass keine reeelen Nullstellen hat.



  • Gibt es denn im binarsystem eine exakte Zahl, die kleiner als eins ist und duch multiplikation zu eins ergänzt werden kann?



  • 2 und alle Potenzen (...-2,1,0,1,2 ...).



  • also geht mein Ansatz nur für ganze Zahlen, weil bei dem Computer z.b. 0.1*10 nicht exakt 1 ist?



  • knivil schrieb:

    Und ich ueberlege mir ein Polynom 4-ten Grades, das nicht faktorisierbar ist ... 🙂

    Ja, x^4 + x^2 + 1 ist nicht in Linearfaktoren zerlegbar, gähn. Das hab ich aber auch nicht behauptet, also spar dir deine Energie und schlag lieber den Satz nach, der besagt, dass irreduzible Polynome über IR den Höchstgrad 2 haben.



  • also geht mein Ansatz nur für ganze Zahlen, weil bei dem Computer z.b. 0.1*10 nicht exakt 1 ist?
    aber dann müsste doch folgendes funktionieren:

    if( aa*pol*pol*pol + bb*pol*pol + cc*pol + dd > -0.01 && aa*pol*pol*pol + bb*pol*pol + cc*pol + dd< 0.01)
    

    leider funktioniet das auch nicht.
    Das kann auch nicht daran liegen, dass die Abweichung höher als 0.01 ist weil das folgende funktioniert auch nicht:

    if( aa*pol*pol*pol + bb*pol*pol + cc*pol + dd > -1 && aa*pol*pol*pol + bb*pol*pol + cc*pol + dd< 1)
    

    zudem habe ich auch mal folgendes eingefügt:

    pol = loop_pol;							
     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)
    

    in der Ausgabe werden dann aber auch ganze Zahlen angezeigt. Somit müssten auch ganze Zahlen als nullstellen erkannt werden.

    Ist das jetzt doch nen andreres problen?



  • 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.


Anmelden zum Antworten