mikrocontroller.net

Forum: PC-Programmierung Unendliche Reihe Berechnen


Autor: Stephan (Gast)
Datum:
Angehängte Dateien:
  • preview image for DV.jpg
    DV.jpg
    114 KB, 623 Downloads

Bewertung
0 lesenswert
nicht lesenswert
Hi Leute,
ich hoffe das ihr mir helfen könnt.
Es geht um die angehängte Aufgabe..
Es soll eine Reihe Programmiert werden um den natürlichen Logarithmus zu 
berechnen. Die Potenzfunktionen wie pow sind nicht erlaubt.

Leider komme ich nicht auf die richtige bzw erwartete Ausgabe des 
Programmes..

Mein Ansatz :

#include<stdio.h>

int main()
{

   double x, summand1=0, summand2=0; summe_neu=0, summe_alt;
   int k;

   printf("Bitte geben das Argument x eingeben\n");
   scanf("%lf",&x);

  if(x<=0)
  { printf("Ungueltiger Wert, Porgramm abbruch!\n");
    return 1;
  }

  do
  { k=1; k+=2;
    summand1+=1/(2*k+1);
    summand2+=(x-1)/(x+1)*(x-1)/(x+1)*(x-1)/(x+1);

    summe_neu=summand1*summand2;

    summe_neu=summe_alt;
   }

   while(summe_neu!=summe_alt);

   printf("ln(%lf)=%.9lf",x,2*summe_neu);

   return 0;

}

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
do {
  summe_neu=summe_alt;
}
while(summe_neu!=summe_alt);

damit macht das while keinen sinn mehr.

Autor: Nikolas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
dein Fehler scheint in der Summenbildung zu liegen.

Stephan schrieb:
> summand2+=(x-1)/(x+1)*(x-1)/(x+1)*(x-1)/(x+1);
Damit bildest du ja immer ((x+1)/(x-1))^3

Stattdessen müsste die Formel lauten:
int exp = 1;
summand2 = 1;

for(exp =1;exp<k+1;exp++) //Dies ist ((x+1)/(x-1))^(2*k+1)
{
  summand2 = summand2 * (x+1)/(x-1);
}

Und wie mein Vorposter schon sagte,
 summe_neu=summe_alt; 
 muss an den Anfang der Schleife

Autor: Jemand (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde dir empfehlen die ersten zwei Iterationen einfach mal ohne 
Schleife aufzuschreiben, dann siehst Du eventuell wo Werte inkrementiert 
und wo Werte verglichen werden müssen.

Und wenn pow() nicht erlaubt ist, dann würde ich mir ganz fix eine 
eigene Funktion schreiben um Potenzen zu berechnen. Oder ist das auch 
verboten?

Autor: Stephan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jemand schrieb:
> Und wenn pow() nicht erlaubt ist, dann würde ich mir ganz fix eine
> eigene Funktion schreiben um Potenzen zu berechnen. Oder ist das auch
> verboten?

Eine Funktion zu schreiben ist leider nur dann erlaubt wenn es in der 
Aufgabenstellung gefordert ist.

Danke für den Tipp, das probiere ich jetzt mal aus!

Autor: MikeH (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Deine Schleife stimmt hinten und vorne nicht, soweit ich das überblicke.
Du initialisierst k=1 jedesmal neu am Schleifenanfang.

Außerdem addierst du jeweils (x-1/x+1)^3  zu summand2. Wobei summand1 
und summand2 eigentlich Faktoren sind.


Die Aufgabe ist außerdem falsch gestellt, da die erste Reihe bei k=0 
anfängt und die Summenformel mit k=1.

Autor: Stephan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nikolas schrieb:
> Hallo,
> dein Fehler scheint in der Summenbildung zu liegen.


Vielen Dank für die Antwort, ich werde es direkt ausprobieren!

Autor: Peter M. (r2d3)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jemand schrieb:
> Und wenn pow() nicht erlaubt ist, dann würde ich mir ganz fix eine
> eigene Funktion schreiben um Potenzen zu berechnen. Oder ist das auch
> verboten?

Eine eigene Potenzfunktion zu schreiben ist Zeitverschwendung und 
beinhaltet eine zusätzliche Fehlerquelle.

Für ein gegebenes Argument x wächst die Potenzkomponente mit dem 
konstanten Faktor

[ (x-1)/(x+1) ]^2.

Den muss man nur einmal ausrechnen und dann immer mit dem laufenden 
Potenzglied multiplizieren.

Eine Potenzfunktion ist hier nicht erforderlich.

: Bearbeitet durch User
Autor: Der Andere (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jemand schrieb:
> Und wenn pow() nicht erlaubt ist, dann würde ich mir ganz fix eine
> eigene Funktion schreiben um Potenzen zu berechnen.

Was aus Sicht der Performance so ziemlich das schlechteste ist was man 
machen kann.
Dabei ist die Reihenentwicklung doch schon angegeben, und die Basis 
unter dem Exponent ist konstant und nicht von k abhängig.

Autor: Stephan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was mir bei der AUfgabe besonders schwer fällt, ist das der Exponent mit 
((x+1)/(x-1))^3, ((x+1)/(x-1))^5,((x+1)/(x-1))^7 usw wächst..

Also mit k=k+2, das habe ich nämlich auch falsch gemacht wie eich gerade 
sehe

Autor: Jemand (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Make it run first, before you make it run fast...

Persönlich finde ich es immer etwas einfacher, wenn ich Dinge 
schrittweise entwickle. Der Fragesteller hat ja offensichtlich 
Schwierigkeiten die Gleichung in Code zu gießen.

Und in solchen Fällen hilft es mir immer wenn ich irgendwo a^b lese, 
dann schreibe ich an der Stelle einfach pow(a,b). Sobald das Programm 
richtig rechnet kann ich Überlegungen anstellen, wie man den Code 
eventuell optimieren kann.

Autor: jb (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
>Eine Funktion zu schreiben ist leider nur dann erlaubt wenn es in der
>Aufgabenstellung gefordert ist.

>Danke für den Tipp, das probiere ich jetzt mal aus!

Was ein Unsinn. Man darf einer der wichtigsten Programmmiermethoden 
(Auslagerung und Aufteilung von Lösungen) nicht verwenden.
Und den Still eignet man sich dann an, schönen alles scriptmässig in 
einen block knallen.
manoman

Gruß J

Autor: Stephan (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
jb schrieb:
> Was ein Unsinn. Man darf einer der wichtigsten Programmmiermethoden
> (Auslagerung und Aufteilung von Lösungen) nicht verwenden.

Es gibt in der Klausur Aufgaben wo man dann Funktionen schreiben muss 
und Aufgaben wo es nicht erlaubt ist..

Autor: Der Andere (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
jb schrieb:
> Was ein Unsinn.

Kein Unsinn, sondern der Hinweis wie man sowas effizient programmiert.

Jemand schrieb:
> Make it run first, before you make it run fast...

Im Prinzip nicht verkehrt, führt hier aber zu einem völlig falschen 
Ansatz.

@Stephan:
Mach dir klar, dass jeder neu Summand der Reihe aus zwei Faktoren 
besteht.
Der erste ist von k abhängig 1/(1k+1) und muss immer berechnet werden.
Der Zweite Faktor lässt sich aber durch einfache Multiplikation vom 
vorigen Reihenelement berechnen. Du musst dir also nur das Ergebnis der 
vorherigen Iteration merken und kannst das dasmit dem konstanten Faktor 
((x-1)/(x+1))² multiplizieren.

Autor: Der Andere (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Andere schrieb:
> vom vorigen Reihenelement
Sorry falsch: sollte heissen "vom schon berechneten Faktor des 
vorherigen Reihenelements".

Autor: Georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stephan schrieb:
> Es geht um die angehängte Aufgabe..

Die Aufgabenstellung ist sowieso einfach nur falsch. Die Summe wird 
natürlich ab k=0 gebildet, sonst fehlt der erste Summand.

Sowas als Aufgabe zu definieren ist schon echt kriminell.

Georg

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein weiterer Fehler:

> 1/(2*k+1)

Dieser Ausdruck ist für k>0 immer 0, da hier zwei int-Werte dividiert
werden. Mindestens einer der Operanden muss double sein, damit auch die
Division in double ausgeführt wird.

Also:

1.0 / (2*k+1)

oder

1 / (double)(2*k+1)

oder

1.0 / (double)(2*k+1)

Autor: Erwin D. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yalu X. schrieb:
> Mindestens einer der Operanden muss double sein, damit auch die
> Division in double ausgeführt wird.

Steht doch auch in der Aufgabenstellung (Bild) drin.
> "Alle Gleitpunkt-Datentypen sollen vom Typ double sein"

Autor: Peter M. (r2d3)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Andere schrieb:
> Der Zweite Faktor lässt sich aber durch einfache Multiplikation vom
> vorigen Reihenelement berechnen. Du musst dir also nur das Ergebnis der
> vorherigen Iteration merken und kannst das dasmit dem konstanten Faktor
> ((x-1)/(x+1))² multiplizieren.

Was ich oben schon schrieb...

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erwin D. schrieb:
> Yalu X. schrieb:
>> Mindestens einer der Operanden muss double sein, damit auch die
>> Division in double ausgeführt wird.
>
> Steht doch auch in der Aufgabenstellung (Bild) drin.
>> "Alle Gleitpunkt-Datentypen sollen vom Typ double sein"

Ja. Dass man aber Nicht-Gleitpunkt-Datentypen ggf. explizit konvertieren
muss, steht da nicht drin (dafür aber in einem C-Buch).

Autor: Joe G. (feinmechaniker) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Stephan schrieb:
> Leider komme ich nicht auf die richtige bzw erwartete Ausgabe des
> Programmes..

Das kannst du auch nicht. Die Tayloreentwicklung ist fehlerhaft :-(
Richtig siehe Anhang. Es muss jeweils 2k-1 in der Gleichung stehen!

Autor: Erwin D. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yalu X. schrieb:
> Ja. Dass man aber Nicht-Gleitpunkt-Datentypen ggf. explizit konvertieren
> muss, steht da nicht drin (dafür aber in einem C-Buch).

Stimmt :-)

Autor: W.S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stephan schrieb:
> Leider komme ich nicht auf die richtige bzw erwartete Ausgabe des
> Programmes..
>
> Mein Ansatz :
>
> #include<stdio.h>
>
> int main()
> {

Ja. Glaub ich unbesehen. Zu allererst mal int main (void) { hinschreiben 
und sich dabei denken, nach der Gesachweiften wird mir schon was 
einfallen.

Also, du gehst schlichtweg völlig unmathematisch und unsystematisch an 
die Aufgabe heran.

Mein Rat:
1. Laß am Anfang das Formulieren in irgend einer Programmiersprache 
bleiben.
2. Denke darüber nach, wie sich die Sache in eine sequentiell 
abarbeitbare Reihe entwickeln läßt, also wie der Beitrag N sich aus dem 
vorherigen Beitrag N-1 entwickeln läßt.
3. Setze deine Startumgebung, also hier zum Beispiel (falls die Reihe 
richtig vorgegeben sein sollte)
  a = (x-1)/(x+1) und b = a * a und Ergebnis = 0
4. jetzt kannst du dir nen PAP malen oder ein Struktogramm und hast 
damit bereits die fertige Lösung
5. anschließend kannst du das in eine konkrete Programmiersprache 
fassen.

W.S.

Autor: Stephan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Leider bricht mein Programm bei Ausführen leider ab!
Mein korrigierter Ansatz wäre jetzt:

#include<stdio.h>

int main()

{
    double k, x, mult1, mult2=0, summe_alt, summe_neu=0,exp=0,i;

    printf("Bitte das Argument x eingeben!\n");
    scanf("%lf",x);

    if(x<=0)
    {
        printf("Fehlerhafte Eingabe\n");
        return 1;
    }

    do
    {  summe_alt=summe_neu;
        k=1; k=k+2;

        mult1+=1/(2*k+1);
        mult2=(x-1)/(x+2);

        for(i=1; i<=k+2; i=i+2)
        {
            exp*=(x-1)*(x+1);
        }
        mult2=mult2*exp;

        summe_neu=mult1*mult2;

    }

        while(summe_neu!=summe_alt);

        printf("ln(%.2lf)=%.9lf",x,2*summe_neu);


}

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joe G. schrieb:
> Es muss jeweils 2k-1 in der Gleichung stehen!

Oder die Summation bei 0 beginnen, siehe z.B.

https://de.wikipedia.org/wiki/Logarithmus#Potenzreihe

Autor: Helmut S. (helmuts)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> k=1; k=k+2;

Die Zeile sieht doch ziemlich sinnlos aus. Da muss nachgebessert werden.

Autor: Joe G. (feinmechaniker) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. schrieb:
> Oder die Summation bei 0 beginnen, siehe z.B

Wie man mag :-)

Falls jemand Interesse hat, wie man auf diese Summenfolmel kommt...

Autor: Jemand (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da Du weiterhin Probleme mit der Schleife hast, kannst Du ja erstmal ein 
programm schreiben, welches folgendes berechnet:

Das ist prinzipiell genau das gleiche wie deine Aufgabe, nur alles 
"komplizierte" wurde entfernt.

Und ein Hinweis wurde hier ja schon genannt:
schreibe statt 1/(2*k+1) lieber 1.0/(2.0*k+1.0).
So ist auf jeden Fall sichergestellt, dass Du keine Integerdivision 
durchführst.

Autor: Tasg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und wie kommst du auf die Summen für ln(1-z) oder ln(1+z)
Ausserdem enthält die Herleitung Fehler..

Autor: Joe G. (feinmechaniker) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tasg schrieb:
> Und wie kommst du auf die Summen für ln(1-z) oder ln(1+z)

durch Reihenentwicklung

> Ausserdem enthält die Herleitung Fehler..
wo?

Stimmt, bei der Quotientenbildung muss es ln(1+z)-ln(1-z) heißen :-(
Ist durch copy and paste entstanden

: Bearbeitet durch User
Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warnmeldungen des Compilers einschalten und die ausgegebenen Warnungen
nicht ignorieren, bspw. in

    scanf("%lf",x);

Interessanterweise war das in deiner ersten Version noch richtig.

Außerdem: Versuch dich zu konzentrieren, oder mach mal eine längere
Pause :)

        k=1; k=k+2;

Das wurde schon angemerkt. Wieso steht die Initialisierung von k in
der Schleife und nicht außerhalt? Und wieso wird k in jedem
Schleifendurchlauf um 2 erhöht und nicht um 1? Und wieso passiert das
gleich am Anfang der Schleife? Wie groß muss k zur Berechnung des ersten
Summanden sein? Bei dir ist es 3, was überhaupt nicht stimmen kann.

        mult1+=1/(2*k+1);

Der Compiler sagt (mit Recht), dass hier mult1 möglicherweise
uninitialisiert verwendet wird.

Aber wieso überhaupt += und nicht =? Addiert wird doch erst, nachdem
mult1 und mult2 miteinander multipliziert sind, was aber erst weiter
unten passiert. Und der Fehler mit der Integer-Division ist immer noch
da.

        mult2=(x-1)/(x+2);

Wo kommt das x+2 her?

        for(i=1; i<=k+2; i=i+2)

Wieviele Schleifendurchläufe erwartest du, und wie oft dreht die
For-Schleife tatsächlich?

            exp*=(x-1)*(x+1);

Die Variable exp wird oben mit 0 initialisiert. Wie oft musst du 0 mit
einer anderen Zahl multiplizieren, damit ein von 0 verschiedenes
Ergebnis herauskommt? Und wieso werden (x-1) und (x+1) hier plötzlich
multipliziert und nicht dividiert?

        summe_neu=mult1*mult2;

Und wo wird hier jetzt etwas aufsummiert? summe_neu wird in jedem
Schleifendurchlauf überschrieben, die bisherigen Berechnungen gehen
dabei verloren. Schade um die Rechenzeit :)

Meine dringendste Empfehlung: Schlaf mal eine Nacht darüber und
versuch's morgen in alter Frische noch einmal!

: Bearbeitet durch Moderator
Autor: Helmut S. (helmuts)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Hier mal eine Octave/Matlab-Version.

Achtung mein k weicht von der Definition von k in der Reihenentwicklung 
ab. Mein k zählt nur 1, 3, 5, 7, ...

% logx mit Reihenentwicklung
x=input('x:')
if(x>0)
  k=1;
  sum=0;
  sum_alt=0;
  delta=(x-1)/(x+1)
  sum=delta;
  while sum~=sum_alt
    sum_alt=sum;
    k=k+2;
    delta=delta*(x-1)*(x-1)/((x+1)*(x+1))
    sum=sum+delta/k;
  end
  sum=2*sum;
  %disp(sum);
  str=sprintf('Reihe : %16.9f', sum)
  str=sprintf('log() : %16.9f', log(x))
endif


>> logx
x:2
x =  2
delta =  0.33333
delta =  0.037037
delta =  0.0041152
delta =   4.5725e-004
delta =   5.0805e-005
delta =   5.6450e-006
delta =   6.2723e-007
delta =   6.9692e-008
delta =   7.7435e-009
delta =   8.6039e-010
delta =   9.5599e-011
delta =   1.0622e-011
delta =   1.1802e-012
delta =   1.3114e-013
delta =   1.4571e-014
delta =   1.6190e-015
delta =   1.7989e-016
str = Reihe :      0.693147181
str = log() :      0.693147181

Autor: Gruselfrosch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vorsicht auch mit
 while (sum_alt != sum) 
Da die Summanden sehr schnell recht klein werden können, kann es sein 
dass sich der PC einen Wolf rechnet ohne das der berechnete Wert 
nennenswert genauer wird. Wenn man Pech hat beendet der Compiler dann 
irgendwann das Spielchen, ohne dass das Programm zum Ende gekommen ist. 
Daher besser sowas:
 while (fabs(sum_alt - sum) > delta) 
Jetzt würde nur noch so lange gerechnet bis die Differenz kleiner einem 
bestimmten Wert ist.

Autor: Georg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gruselfrosch schrieb:
> Wenn man Pech hat beendet der Compiler dann
> irgendwann das Spielchen, ohne dass das Programm zum Ende gekommen ist.

Wieso Pech? Ist eine Endlosschleife des Programmierers höchstes Glück? 
So eine Art Software mit Ewigkeitsanspruch?

Georg

Autor: Gruselfrosch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Pech im Sinne von das Programm wird abgebrochen obwohl man ja keine 
Endlosschleife programmiert hat.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.