Den Cosinus approximieren

hummel3210

Mitglied
Hallo zusammen,
ich habe probiert den Cosinus durch die Taylorentwicklung zu approximieren. Ich habe hierfür folgendes Programm geschrieben:

Java:
public class Cosinus{

    public static void main(String[] args) {

            double x = Double.parseDouble(args[0]);

            double cos;

            double wert = 0;

            int a;

            int e = 1;

            for (a=0; a <= 20; a++){

            e = e*a;  //Soll die Fakultät simulieren

            if (a%4 == 0){

                wert = (Math.pow(x, a)/e) ;}

            else if (a%2==0) {

                wert = (Math.pow(x, a)/e)*(-1);}


            cos = 1 - wert;

            System.out.print(cos);

            }

    }

}


Leider gibt mir die Ausgabe für jegliche Werte nur Infinity aus. Ich wäre für Tipps zur Verbesserung sehr dankbar.
 

Marinek

Bekanntes Mitglied
Die Hilfe von @below100 ist leider nutzlos. Es sei an der Stelle erstmal gesagt, dass es sich bei dem User um einen Forentroll handelt, der maximal Pseudoantworten gibt.

Obwohl einer der Fehler gewesen ist, dass die Schleife mit 0 dazu geführt hat, das fast alle Produkte 0 sind, sind weitere Fehler da.

Für 0.75 ergibt deine Rechnung 1.0000000000015086

Tatsächlich ist cos(0.75) = 0.7316888688738209

Mit der richtigen Aproximation mit 20 Termen müsste es 0.7316888688738209

Unter anderen liegt das daran, dass deine Implementierung nicht die korrekte Taylorreihe implementiert.
 
Zuletzt bearbeitet:

KonradN

Super-Moderator
Mitarbeiter
Also ein kleiner Fehler ist das die Fakultäten 0 sind, da du mit a multiplizierst und a 0 ist am Anfang. (Ganz wichtiger Tipp: Benenne Variablen vernünftig!)

Dann ist aber auch keine Taylorreihe zu erkennen. Da ginge es ja um eine Summenbildung, aber Du addierst da ja nichts sondern Du gibst immer nur die Zwischenwerte aus. Also evtl. willst Du da etwas haben wie wert += .... (oder dann statt dem *(-1) kannst DU da dann auch einfach ein wert -= ... nehmen.

Und wieso da ein 1-cos? cos(x) ist die Summe von dem, was Du da als Wert berechnest. Aber auch wieder sehr schwer zu lesen, da Du das umgewandelt hast weil Du offensichtlich das (2n) durchgehst und dann immer die Fakultät von diesem 2n berechnest und dann die Zwischenwerte nur bei jedem zweitem Wert nimmst. Das macht es nicht einfacher!

Und wie immer (auch wenn der Forentroll da anderer Meinung ist): Die Berechnung der Fakultät kann man über eine Methode abwickeln, die die letzte Berechnung cached. Dann hast Du z.B. die fakultät von x dir gemerkt und wenn dann die Fakultät von x+2 angefordert wird, dann kannst Du darauf aufbauen. Dadurch kapselst Du die Problematik und das macht das ganze Problem deutlich einfacher. Durch solche einfachen Umstrukturierungen hast Du dann tatsächlich eine Taylorreihe, die vom Code so aussieht wie auch die Formel. Sowas macht die Fehlersuche dann deutlich einfacher.
 

KonradN

Super-Moderator
Mitarbeiter
Ach ja - bezüglich diesem Punkt:
Und wieso da ein 1-cos?
Da hast Du vermutlich einfach den Wert für n=0 (bzw. a = 0 bei Dir) genommen. Der ist halt 1, da x hoch 0 = 1 und 0! ist auch 1 und damit hast Du 1 / 1 = 1. Aber da kannst Du nicht einfach - dem errechneten Wert rechnen, denn Du würdest damit ja die ganzen Berechnungen umdrehen. Wenn Du ab 1 rechnen würdest und den Wert für 0 direkt als 1 vorgibst, dann wäre es dennoch die Summe und damit 1 + berechneter Wert. Und das würde man dann nicht am Ende machen sondern wert am Anfang auf 1 initialisieren.

So das dein Gedankengang war so ist das erneut ein gutes Beispiel um eben zu zeigen, dass man so Algorithmen eben nicht aufblähen sollte. Bleib wirklich bei dem vorgegebenen Algorithmus und das ist die Summe von ..... Und da dann die Problematik aufteilen und Teilprobleme lösen (also z.B. die performante Berechnung der Fakultät.)

ABER: Das mit der Fakultät ist eine Optimierung! Deine Schleife geht bis 20. Die Anzahl der Fakultäten und deren Größe ist also sehr überschaubar. Da würde ich also auch erst einmal nichts optimieren. Denn durch Optimierungen wird Code unleserlich und es können sich Fehler einschleichen. (Super Beispiel von Dir!)
 

hummel3210

Mitglied
Vielen Dank für die Hinweise. Ich habe den Code jetzt verändert und probiert zu kürzen. Leider funktioniert er immer noch nicht, so wie er soll. Ich glaube, der Fehler liegt bei der Fakultät, weiß es aber nicht. Vielen Dank im Voraus für die Hilfe!
Code:
public class Cosinus{
    public static void main(String[] args) {
            double x = Double.parseDouble(args[0]);
            double cos;
            double wert = 0;
            int n;
            int e = 1;
            for (n=1; n <= 10; n++){
            e = e*n;

            wert += (Math.pow(x,2*n)/2*e) *(Math.pow((-1),n)) ;

            System.out.println(wert);

            }




    }
}
 

Marinek

Bekanntes Mitglied
Innerhalb der for Schleife müsste es so aussehen:

Java:
double wert, term = 1.0; 
for (int i = 1; i < 10; i++) {
           term *= (-x * x) / (2 * i * (2 * i - 1));
            wert += term;        }

Und wert muss auf 1.
 

KonradN

Super-Moderator
Mitarbeiter
Also die Frage ist doch erst einmal, was denn die Formel ist, die Dir vorliegt. Das kann dann diese Formel sein:
Taylorreihe – Wikipedia
Bildschirmfoto 2023-11-06 um 09.42.18.png
Und das kann man dann doch einfach 1:1 umsetzen. Dann ist sicher, dass man keinen Fehler hat. Bei Dir ist das Problem aus meiner Sicht, dass Du 2*n! und nicht (2n)! nutzt.

Und das ist doch 1:1 umsetzbar:
Java:
double wert = 0;
for (n=0; n<= 10; n++) {
    wert += Math.pow(-1, n) * Math.pow(x, 2*n) / factorial(2*n)
}

Und dann fehlt nur noch die Methode für factorial. Da kann man dann sowas nehmen:

Java:
public static double factorial(final int x) {
    double result = 1;
    for (int factor = 2; factor < x; factor++) {
        result *= factor;
    }
}

Damit hat man eine erste Lösung ohne irgendwas drumherum. Einfach 1:1 erstellt.

Es gibt aber auch noch weitere Berechnungsformeln. So kann man tatsächlich den n.ten Wert über den (n-1).ten Wert darstellen. Das müsste das sein, was @Apple's Jünger in #13 genutzt hatte. Das ist ok, so dies vorliegt. Aber das scheint bei Dir nicht der Fall zu sein.

Mir scheint also, dass Du die gleiche Formel hast, die ich hier gezeigt habe und du willst genau diese umsetzen. Dann mach es wirklich von Grund auf! Und das ohne jede Optimierung! Das ist hier auch ein gutes Beispiel: Wenn Du die Berechnung optimieren willst, dann wird es nicht bei dem factorial gemacht sondern dann geht man hin, analysiert die Anforderung, macht ein paar mathematischen Überlegungen und schon hat man die angepasste Formel, die diese Problematik besser lösen müsste.
 

KonradN

Super-Moderator
Mitarbeiter
Edit: Ja, es scheint an factor < x gelegen zu haben.
Richtig, der Code ist im Forum entstanden und war ungetestet. Natürlich muss die Schleife bis factor <= x gehen.

Da solche Fehler beim testen immer wieder schnell passieren können (und dies dann ja massiv Zeit in Anspruch nehmen kann, wenn man dann z.B. nur cos Berechnungen prüft und man da dann alles durchgeht) kann ich nur empfehlen, wirklich Unit Tests zu nutzen. Die Methode ist nun wirklich schnell getestet - das kostet kaum Zeit da die IDE fast alles generiert. Da braucht man also nur paar assertEquals für diverse Aufrufe. (Dabei wäre es mir sogar egal, ob man da einfach eine Testmethode mit mehreren assertEquals(...) Aufrufen hat oder ob man das sauber macht per ParametrizedTest und kleinem CsvSource.)

Und es zeigt den Vorteil, der eben bei der Untergliederung in Methoden passiert - ich kann die Teilbereiche eigenständig testen.
 

Ähnliche Java Themen

Neue Themen


Oben