Unendliche Reihe Berechnen

Gast #4712764
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;

}
Angehängte Dateien:
Gast #4712772
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:
1
int exp = 1;
2
summand2 = 1;
3

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

Und wie mein Vorposter schon sagte,
1
 summe_neu=summe_alt;
 muss an den Anfang der Schleife
Gast #4712773
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?
Gast #4712775
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!
Gast #4712783
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.
#4712790
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.
Gast #4712798
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.
Gast #4712803
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
Gast #4712808
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.
Gast #4712819
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
Gast #4712832
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..
Gast #4712833
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.
Moderator #4712861
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)
Moderator #4712974
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).
Gast #4713426
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.
Gast #4713434
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);


}
Gast #4713484
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.
Moderator #4713511
Lesenswert?

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

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

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

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

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

Wo kommt das x+2 her?

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

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

1
            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?

1
        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!
#4713561
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
Gast #4713720
Lesenswert?

Vorsicht auch mit
1
 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:
1
 while (fabs(sum_alt - sum) > delta)
Jetzt würde nur noch so lange gerechnet bis die Differenz kleiner einem 
bestimmten Wert ist.
Beitrag #6070059 wurde von einem Moderator gelöscht.
#6071303
Lesenswert?

1
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
2
können.


Beitrag "Re: ln(x) ohne math.h"
Moderator Persönliche Seite #6071677
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.