Kleine Frage zu PI und M_PI



  • Hi.

    Ich schreibe gerade ein altes VC6 Projekt in CBuilder um. In VC6 ist die PI-Konstante mit PI vergeben was in BCB5 M_PI ist.

    Ich möchte jetzt eigentlich mal nicht den Text in allen Modulen ersetzen, sondern eine globale Konstante einfach erstellen die M_PI beinhaltet.

    const double PI = M_PI;
    

    Wäre das so richtig? Sehr doofe Frage, aber ich stelle sie trotzdem, da nirgends der Datentyp von M_PI gelistet wird. Aber was ausser ein double sollte es schon sein. :p



  • M_PI ist ein Makro in math.h:

    #define M_PI        3.14159265358979323846
    

    Du könntest Dir daher auch ein Makro definieren oder so lassen, wie Du es schon hast.

    Gruß

    Alexander



  • Bis heute Vormittag hatte ich es als

    #define PI M_PI
    

    Dann meinte jemand das man #define doch nur in C benutze und ich dies über const machen solle. 😉

    Ist nun die Frage was sinvoller wäre, da double und float in CBuilder wohl "verbugt" ist? Anders kann ichs mir nicht erklären. Habe in VC6 ne Schleife die aufsummiert. Nehm ich den Code und den Datensatz und baue das in BCB ein erhalte ich gänzlich andere Ergebnisse. Ich nehme an das VC6 mit dem "Anhang" von Fliesskommazahlen wesentlich besser umgeht. ein FloatToStr() gibt mir ja nach der x-ten Kommastelle irgenwelchen schmuh aus und ich denke das dies sich mit der Schleife die sehr oft durchgegangen wird und gerechnet einfach bös aufsummiert.

    Gibts vielleicht ne Compiler Einstellung diesbezüglich?



  • Hallo

    Unsinn weder float noch double sind im Builder buggy. Sondern basieren wie üblich auf den Prozessor-internen Datentypen.
    Was verstehst du unter "gänzlich andere Ergebnisse"? Falls du Unterschiede in den Nachkommastellen meinst : Die kommen von den im Gleitkomma-Prinzip enthaltenen Ungenauigkeiten. Und darum wird auch FloatToStr immer gerundete, nicht 100% exakte Ausgaben machen.

    bis bald
    akari



  • mather schrieb:

    Dann meinte jemand das man #define doch nur in C benutze und ich dies über const machen solle.

    Halte ich auch für richtig und halte ich in meinen Programmen so.
    M_PI ist aber als Makro definiert und daran kannst Du recht wenig ändern.

    Gruß

    Alexander



  • @Alexander Kempf
    Dann lasse ich es #define. 😉

    @akari
    Ich weiss nicht welche Mathematik dahinter steckt (ist aber irgendeine art Aufsummierung bei einer Stabilitätsrechnung), der Code zu 100% identisch mit dem von VC6 und es kommen nunmal andere Ergebnisse raus. Ich weiss nur das ne Schleife paar tausend mal durchgegangen wird und in ihr diverse Rechnungen vorgenommen werden. Die Ergebnisse werden etwas gleicher wenn man eine Variable für eine der Funktionen von float auf double ändert. Möglich das in VC6 etwas als float steht, aber höher interpretiert wird falls benötigt und daher dort nicht auffält.

    Beispielsweise

    float x = 4.01;
        char text[100];
        sprintf(text,"%f",x);
        Edit1->Text = text;
    //Ergebnis: 4.010000
        Edit1->Text = FloatToStr(x);
    //Ergebnis: 4,01000022888184
    

    Sowas sieht doch nicht schön aus was da FloatToStr() einem da zurück gibt.

    Und noch was .. ich kann die Schleife natürlich unterbrechen und mir Zwischenergebnisse anschauen und von Anfangs gleich kann man zuschauen wie sich die Werte rasch abweichen. Mag auch daran liegen das diverse "if" abfragen enthalten sind und auf <=0.0 ==0.0 prüfen und wenn in VC6 dieser "Schmutz" wie oben FloatToStr verzapft nicht exisitert (korrekt macht), aber in BCB eben nicht 0.0 sondern bei ihm 0.0000000343556 ist, dann wird das Ergebnis natürlich im laufe der Rechnung extremst anders, genau wie es hier passiert.



  • mather schrieb:

    float x = 4.01;
        char text[100];
        sprintf(text,"%f",x);
        Edit1->Text = text;
    //Ergebnis: 4.010000
        Edit1->Text = FloatToStr(x);
    //Ergebnis: 4,01000022888184
    

    Sowas sieht doch nicht schön aus was da FloatToStr() einem da zurück gibt.

    Wenn du schöne Anzeigen haben willst must du die Ausgabe entsprechend auf eine feste Anzahl von Stellen formatieren (FloatToStrF...).
    Ansonsten kann ich dich nur nochmal auf die Prinzipbedingte Exaktheitsproblematik von Gleitkomma-Zahlen aufmerksam machen. Wenn du lieber mit "schönen" Werten rechnen willst must du mit Festkomma-Datentypen rechen (int oder eine externe Klasse)

    Und noch was .. ich kann die Schleife natürlich unterbrechen und mir Zwischenergebnisse anschauen und von Anfangs gleich kann man zuschauen wie sich die Werte rasch abweichen. Mag auch daran liegen das diverse "if" abfragen enthalten sind und auf <=0.0 ==0.0 prüfen und wenn in VC6 dieser "Schmutz" wie oben FloatToStr verzapft nicht exisitert (korrekt macht), aber in BCB eben nicht 0.0 sondern bei ihm 0.0000000343556 ist, dann wird das Ergebnis natürlich im laufe der Rechnung extremst anders, genau wie es hier passiert.

    Gleitkomma-Zahlen auf Gleichheit zu testen ist eh sinnlos (wieder siehe Problematik von Gleitkomma-Zahlen). Gleitkommazahlen dürfen nur auf Bereiche gestestet werden, also größer/kleiner als. Willst du wissen ob eine Gleitkommazahl einem bestimmten Wert entspricht must du eine sogenannte Epsilon-Betrachtung machen

    float x = ...;
    const float ep = 0.0001f; // Hier die Genauigkeit die du haben willst
    if (fabs(x - 4.0) < ep)
    {
      // x ist ausreichend nahe an 4
    }
    

    bis bald
    akari



  • float x = ...;
    const float ep = 0.0001f; // Hier die Genauigkeit die du haben willst
    if (fabs(x - 4.0) < ep)
    {
      // x ist ausreichend nahe an 4
    }
    

    Wäre wohl eine Möglichkeit mal durchzugehen und zu ersetzen. Werd ich mal baldigst testen. VC6 scheint aber die Prüfung dann "anders" spezieller zu machen als BCB. Denn dort kommen die kalkulierten Ergebnisse eben raus und in BCB nicht bedingt. 😉

    Danke für den Tipp! 👍



  • Zusatzfrage

    Alexander Kempf schrieb:

    mather schrieb:

    Dann meinte jemand das man #define doch nur in C benutze und ich dies über const machen solle.

    Halte ich auch für richtig und halte ich in meinen Programmen so.

    Warum "richtig"(er)? Welche Nachteile soll denn #define haben?



  • Hallo

    Ein define ist nur ein simpler Textersatz, ohne Rücksicht auf Datentypen oder Namespaces. define sollte nur dann benutzt werden wenn es wirklich keine Alternative gibt.

    bis bald
    akari



  • Prinzipiell pflichte ich akari vollkommen bei. Der Umgang mit Fließkommazahlen bedeutet
    grundsätzliche Ungenauigkeiten in Kauf zu nehmen - das hat nichts mit IDEs oder Sprachen
    zu tun.

    mather schrieb:

    und es kommen nunmal andere Ergebnisse raus.

    Was heißt andere Werte? Bedeutet das anstatt 7,456 kommt 123123,90 an, oder was?

    mather schrieb:

    wenn in VC6 dieser "Schmutz" wie oben FloatToStr verzapft nicht exisitert (korrekt macht)

    Was hat FloatToStr() mit der Berechnung zu tun?

    mather schrieb:

    Warum "richtig"(er)? Welche Nachteile soll denn #define haben?

    Einen Nachteil hast Du doch indirekt schon selbst genannt.
    Welchen Typ hat denn nun M_PI?

    Makros werden vom Präprozessor verarbeitet, Konstantendeklarationen vom Compiler.
    Konstanten sind deshalb auch als Symbole vorhanden (können z.B. auch beim Debuggen
    angezeigt werden).

    Dazu lässt sich auch einiges in der Literatur finden (z.B. "The elements of C++ Style").

    Gruß

    Alexander

    [edit]Hat akari ja zwischenzeitlich schon erklärt.[/edit]


Log in to reply