mikrocontroller.net

Forum: PC-Programmierung Unendliche Reihe Berechnen


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Stephan (Gast)


Angehängte Dateien:
  • preview image for DV.jpg
    DV.jpg
    114 KB, 1188 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;

}

: Gesperrt durch Moderator
von Peter II (Gast)


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

damit macht das while keinen sinn mehr.

von Nikolas (Gast)


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

von Jemand (Gast)


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?

von Stephan (Gast)


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!

von MikeH (Gast)


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.

von Stephan (Gast)


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!

von Peter M. (r2d3)


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
von Der Andere (Gast)


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.

von Stephan (Gast)


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

von Jemand (Gast)


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.

von jb (Gast)


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

von Stephan (Gast)


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

von Der Andere (Gast)


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.

von Der Andere (Gast)


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

von Georg (Gast)


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

von Yalu X. (yalu) (Moderator)


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)

von Erwin D. (Gast)


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"

von Peter M. (r2d3)


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

von Yalu X. (yalu) (Moderator)


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

von Joe G. (feinmechaniker) Benutzerseite


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!

von Erwin D. (Gast)


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 :-)

von W.S. (Gast)


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.

von Stephan (Gast)


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);


}

von Johann L. (gjlayde) Benutzerseite


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

von Helmut S. (helmuts)


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

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

von Joe G. (feinmechaniker) Benutzerseite


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

von Jemand (Gast)


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.

von Tasg (Gast)


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

von Joe G. (feinmechaniker) Benutzerseite


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
von Yalu X. (yalu) (Moderator)


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
von Helmut S. (helmuts)


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

von Gruselfrosch (Gast)


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.

von Georg (Gast)


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

von Gruselfrosch (Gast)


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

Beitrag #6070059 wurde von einem Moderator gelöscht.
von Julian Lindemeyer (Gast)


Angehängte Dateien:

Bewertung
-4 lesenswert
nicht lesenswert
Hallo
Habe. Probleme bei dieser Aufgabe und bräuchte einen Ansatz der mir 
fehlt

von Joggel E. (jetztnicht)


Bewertung
0 lesenswert
nicht lesenswert
Aha. Und deine bisherige Vorleistung, ausser dass du schon seit Tagen im 
Internet suchst ?

Muss Mamma mitkommen und Haendchen halten ?

: Bearbeitet durch User
von Sebastian R. (sebastian_r569)


Bewertung
2 lesenswert
nicht lesenswert
Sie sollen diese Projektaufgaben selbstständig bearbeiten und lösen. Alle Lösungen, die aus der Betrachtung des Quellcodes und dem Vergleich mit anderen abgegeben Lösungen vermuten lassen, dass die Bearbeitung nicht eigenständig durch Sie selbst erfolgte, werden mit 0 Punkten bewertet oder zumindest stark abgewertet. Diese Abwertung betrifft auch diejenigen Lösungen, die als Quelle für andere abgegebene Lösungen vermutet werden
können.


Beitrag "Re: ln(x) ohne math.h"

von M.A. S. (mse2)


Bewertung
1 lesenswert
nicht lesenswert
Julian Lindemeyer schrieb:
> Hallo
> Habe. Probleme bei dieser Aufgabe und bräuchte einen Ansatz der mir
> fehlt

Das kommt mir irgendwie bekannt vor.
Und irgendwie ist auch schon alles dazu schon gesagt.

: Bearbeitet durch User
von Julian Lindemeyer (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
hi
ich bins nochmal
hab mal versucht was zu machen aber die Ergebnisse stimmen nicht ganz
und ich hab noch das Problem das ich iterationsschritte mitzählen soll
Brauch ich dafür noch eine schleife?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Bewertung
3 lesenswert
nicht lesenswert
Wie viele Threadleichen möchtest du noch ausgraben dafür?

Das allermindeste, was du tun solltest, ist dir wenigstens mal den von 
dir gekaperten Thread durchlesen - daraus kannst du schon noch was 
lernen. Und nein, eine Potenzreihe entwickelt man ganz gewiss nicht, 
indem man das erste bis N-te Glied linear in eine einzige Formel 
schreibt, sondern man entwickelt die einzelnen Summanden Stück für 
Stück. Das solltest du allerdings spätestens nach dem Lesen des 
Threads verstanden haben.

Danach kannst du dann noch an deinem Verständnis für Aufgabenstellungen 
arbeiten, denn darin sind relativ strikte Regeln festgelegt, in welcher 
Form du was machen sollst (bspw. keine impliziten Initialisierungen von 
Variablen direkt in der Definition).

Damit darf dieser Thread wieder in die Threadleichenkiste.

Dieser Beitrag ist gesperrt und kann nicht beantwortet werden.