Forum: PC-Programmierung C Programm springt mir nicht aus meiner for-Schleife raus


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 Flo D. (floflovaldo)


Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich bin gerade dabei nach einer Aufgabenstellung ein Programm zu 
schreiben, durch das ich raus bekomme wie viele Zahlenreihen ich 
benötige um auf 3.41 zu kommen.

π = 4/1 -  4/3 +  4/5 -  4/7 + ...

Das bekomme ich aktuell schon raus, allerdings mit einem manuellen 
rausspringen aus der Schleife mit dem Break und anschließenden 
durchschauen der Ausgabe.

--> mit 119 Zeichenketten komme ich auf 3.149996.

Ist es irgendwie möglich das ich beim Wert 3.41 aus der for-Schleife 
springe?
Meine Vermutung ist das es hier einfach nicht nur die 3.41 
berücksichtigt sondern auch die hinteren Stellen abgleicht. Hab auch 
schon von 3.139999 bis 3.410000 abgefragt, hier springt er mir aber auch 
nicht raus.

Kann mir jemand vielleicht einen Tipp geben wie das Programm nur die 
3.41 beachtet? Ich hätte eben gerne noch das es so lange durchläuft bis 
zur ersten 3.41 und dann eben stehen bleibt.
#include <stdio.h>

int main(void) {
  double pi = 0;  
  int count = 1;
  double n1 = 5.0; 
  double n2 = 7.0; 

  pi = (4 / 1.0) - (4 / 3.0);

  for (count = 3; pi >= 3.139 || pi <= 3.141; count++) {
    if (count % 2 == 1 ) {                
      pi = pi + (4.0 / n1);
      n1 = n1 + 4.0;
    }
    else {
      pi = pi - (4.0 / n2);
      n2 = n2 + 4.0;
    }
    printf("%f, %d\n", pi, count);
    if (count == 200) break; 
  }
}

von Nop (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Flo F. schrieb:

> schreiben, durch das ich raus bekomme wie viele Zahlenreihen ich
> benötige um auf 3.41 zu kommen.

3.14 meinst Du, aber Du solltest zunächst einmal verstehen, wie 
Fließkommazahlen überhaupt funktionieren. Das sind im Prinzip Brüche zur 
Basis zwei, und viele dezimal gesehen "glatte" Brüche haben keine exakte 
Repräsentation als binäre FLießkommazahlen. So wie z.B. 1/3 auch keine 
exakte dezimale Repräsentation mit endlich vielen Ziffern hat.

Davon ausgenommen sind nur Brüche, die sich als 1/(2^n) darstellen 
lassen, also etwa 0.5, 0.25, 0.125. Und damit auch deren Summen wie etwa 
0.75 oder 0.875.

Da 0.01 keine exakte Repräsentation als Fließkommazahl hat, hat 3.41 
auch keine.

Deswegen testest Du bei Fließkommazahlen niemals auf Gleichheit, sondern 
nur auf größer/größergleich und kleiner/kleinergleich, oder auf 
Intervalle.

von Karl (Gast)


Bewertung
2 lesenswert
nicht lesenswert
(pi >= 3.139) || (pi <= 3.141)

von karadur (Gast)


Bewertung
2 lesenswert
nicht lesenswert
Weil dein Oder immer wahr liefert.

von Irgend W. (Firma: egal) (irgendwer)


Bewertung
0 lesenswert
nicht lesenswert
Flo F. schrieb:
> --> mit 119 Zeichenketten komme ich auf 3.149996.
> schon von 3.139999 bis 3.1410000 abgefragt...

Gibt es bei deiner Rechnerrei überhaupt einen Wert der innerhalb dieses 
Bereichs liegt, nicht das der "Übersprungen" wird.

pi >= 3.139 || pi <= 3.141
Das sieht auch etwas komisch aus. Dass gibt doch immer ein True, oder?

von Heiner (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Flo F. schrieb:
> Ich hätte eben gerne noch das es so lange durchläuft bis
> zur ersten 3.41 und dann eben stehen bleibt.

Dann veränderst du die Abbruchbedingung deiner Schleife:

Flo F. schrieb:
> for (count = 3; pi >= 3.139 || pi <= 3.141; count++)

Die Vergleiche müssen genau umgekehrt sein: Du willst die Iteration 
fortsetzen, bis zu im gewünschten Intervall angekommen bist. Die 
logische Verknüpfung ist dann auch anders ...


Außerdem willst du auch den Schleifenrumpf überdenken. Das geht ohne 
if/else erheblich kürzer, einfacher und logischer.

von Sebastian S. (amateur)


Bewertung
1 lesenswert
nicht lesenswert
Würde ich auch nicht machen!
Dank ODER ist es da so schön drinnen.

von Theor (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Mit allem Respekt: Das ist ja ein furchtbar unverständliches 
Geschreibsel.

Natürlich kann man erkennen, dass es um eine Variante der Leibnizschen 
Näherung von Pi geht.
Offenbar geht es auch darum, eine Abbruchbedingung für die Schleife 
festzulegen.

OK. Aber nun schreibe mal bitte die Aufgabenstellung hin. Dann wird 
vielleicht klar, wo es hingehen soll.
Vermutlich ist der Kern der Aufgabe die Abbruchbedingung festzulegen und 
zu begründen. Sagt Dir das Wort "Konvergenz" aus dem Matheunterricht 
noch was? Was ist das?

von Flo (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Die Aufgabe ist nur ein Programm zur Berechnung der Kreiszahl pi mit der 
Leibnizschen Nährung zu erstellen.
Die Frage lautet wie viele Reihenglieder werden benötigt, hier komme ich 
eben auf die 119.

von Theor (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Na schön, Flo. Die Aufgabe ist leider fehlerhaft beschrieben, Deine 
Annahme unbegründet, aber lassen wir das mal.


Ich rate Dir dazu, ganz genau zu überlegen, für welche Zahlenbereich die 
Bedingung in Deiner for-Schleife wahr oder falsch ist.

Weiter rate ich Dir noch einmal im C-Buch nachzuschauen, was diese 
Bedingung genau bewirkt.

Dann rate ich Dir, noch genau zu überlegen, welche zwei Zahlen, gemäß 
der Aufgabenstellung die Zahl Pi "umgeben". Welche Rolle genau spielt 
dabei die Anzahl der Stellen.

Abschliessend rate ich Dir, Dich mit der Darstellung von 
Fliesskommazahlen im Computer noch einmal gründlich zu befassen. Welche 
Zahlen kann man genau und welche nur mit einem gewissen Fehler 
darstellen?

von Trick aus dem Netz (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
ich habe im Netz einen Trick gesehen wie man Fließkommazahlen auf x 
Stellen rundet:
gerundete_zahl=(int)(fliesskommazahl*100+0.5)/100.0; //runden auf 2 Stellen
Mit diesem Ansatz komme ich auf 153 Durchläufe:
   double pi_double = 0.0;
   int pi_int = 0;

   double num = 4.0; // numerator
   int den; // denominator

   int i;
   for (i = 1, den = 1; pi_int != 314; i++, den += 2) {
      pi_double += num / den;
      pi_int = (int)(pi_double * 100 + 0.5);

      printf("round(%f)=%f\n", pi_double, pi_int / 100.0);

      num *= -1;
   }
   printf("\nIterationen: i=%d\n", i);

von Trick aus dem Netz (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Aber es gibt ja auch noch die round()-Funktion....

von Trick (Gast)


Bewertung
0 lesenswert
nicht lesenswert
mit round():
...
pi_int = (int)round(pi_double * 100);
...

von Trick (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Trick aus dem Netz schrieb:
> Mit diesem Ansatz komme ich auf 153 Durchläufe

152 ;-) Die letzte Inkrementierung sollte man ja  nicht dazuzählen.

von ohne Tricks (Gast)


Bewertung
0 lesenswert
nicht lesenswert
ganze ohne Tricks. Auch 152 Durchläufe.
   double my_pi = 0.0;
   double num = 4.0; // numerator

   // num= denominator
   for (int i = 1, den = 1; my_pi < 3.135 || my_pi > 3.144;
        i++, den += 2) {
      my_pi += num / den;
      printf("%d: %f\n", i, my_pi);
      num *= -1;
   }

von musst du nicht runden? (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Flo F. schrieb:
> --> mit 119 Zeichenketten komme ich auf 3.149996.

Und das ist doch 3.15 aufgerundet.

von Dirk K. (merciless)


Bewertung
0 lesenswert
nicht lesenswert
IMHO ist es besser, die Abweichung zu berechnen
und abzubrechen, wenn diese klein genug ist.
for (count = 3; fabs(pi - 3.14) > 0.001; count++) {

merciless

von Mark B. (markbrandis)


Bewertung
1 lesenswert
nicht lesenswert
Flo F. schrieb:
>   for (count = 3; pi >= 3.139 || pi <= 3.141; count++)

Das ist eine Endlosschleife. Egal welchen Wert pi hat, die Bedingung "pi 
ist größer gleich 3.139 ODER pi ist kleiner gleich 3.141" ist immer 
erfüllt.

Natürlich kann man auch aus einer Endlosschleife herausspringen. Die 
elegantere Lösung wäre freilich, sich die Abbruchbedingung für die 
Schleife so zu überlegen, dass sie eben nicht endlos läuft.

: Bearbeitet durch User
von Planlos (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Mark B. schrieb:
> pi ist kleiner gleich 3.141

Pi ist weder kleiner noch gleich 3.141, da Pi, wenn ich mich recht 
entsinne, 3.14159..... ist. Sollte man da nicht eher einen Wert nehmen, 
der tatsächlich größer als Pi ist, damit Pi dann auch ne Chance hat, 
überhaupt kleiner zu sein als der Vergleichswert?

von Mark B. (markbrandis)


Bewertung
0 lesenswert
nicht lesenswert
Planlos schrieb:
> Pi ist weder kleiner noch gleich 3.141

Das ist mir schon klar. Ich bezog mich auch nicht auf die transzendente 
Zahl Pi, sondern auf die Verwendung der Variable pi im Code des 
Themenerstellers. Dessen Vergleich so halt keinen Sinn ergibt. ;-)

: Bearbeitet durch User
von Robert K. (Firma: Zombieland) (rko)


Bewertung
0 lesenswert
nicht lesenswert
schau mal hier:
https://www.ict4us.com/r.kuijt/de_pi.htm
also:
const float pi = 3.14;

und warum ist bei Dir:
pi = (4 / 1.0) - (4 / 3.0);

Ist bei Dir pi am Ende eine ganz andere Konstante als die Kreiszahl pi 
gemeint ?
Könnte ja sein!

Woher hast Du nur das copy&paste Programm :-))

: Bearbeitet durch User
von sid (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Robert K. schrieb:
> und warum ist bei Dir:
> pi = (4 / 1.0) - (4 / 3.0);
>
> Ist bei Dir pi am Ende eine ganz andere Konstante als die Kreiszahl

na komm, dass er das als Startwert nutzt um sich hoffentlich immer 
weiter Pi anzunähern ist ja schon doch sehr offensichtlich, oder nicht?

'sid

von S. R. (svenska)


Bewertung
0 lesenswert
nicht lesenswert
Wie wäre es mit:
if (fabs(pi - 3.14) < 0.01)
  break;

?

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert

von Pi-ter (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Unabhängig von deiner Lösung frage ich mich warum man iteriert wenn man 
das Endergebnis schon kennt. Ich würde erwarten, dass man bei 
Unterschreiten eines Schwellwertes für die Änderung abbricht.

von Pandur S. (jetztnicht)


Bewertung
-1 lesenswert
nicht lesenswert
Die Aenderung als Abbruchkriterium ? Dann kann mich sich das gleich 
alles schenken :

Aenderung = 4/N

N= 4/Aenderung !

Fertig

von irgendwelche Reihen (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Pi-ter schrieb:
> Unabhängig von deiner Lösung frage ich mich warum man iteriert wenn man
> das Endergebnis schon kennt.

Gibt es in jedem Buch als Übungsaufgabe.

von Joachim B. (jar)


Bewertung
2 lesenswert
nicht lesenswert
Flo D. schrieb:
> Hallo zusammen,

Flo schrieb:
> Die Aufgabe ist nur ein Programm

1. 2 Namen schon mal ungünstig!

Theor schrieb:
> Na schön, Flo. Die Aufgabe ist leider fehlerhaft beschrieben, Deine
> Annahme unbegründet, aber lassen wir das mal.

warum lassen?

es muss doch mal deutlich gesagt werden das man normalerweise nicht aus 
Schleifen springt, die sollen beendet werden wenn die Bedingung erfüllt 
ist!

der Titel ist schon denkbar unglücklich!
C-Buch und lernen ist die erste Pflicht vor sinnlosem C&P

abgesehen davon sehe ich nur 2 Posting vom TO, der hat sich 
offensichtlich längst verabschiedet, manche wollen solche Antworten halt 
nicht hören oder lesen, sie wollen "nur" Lösungen.

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.

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