Klasse für Bruchzahlen gesucht



  • Probiers doch aus. 😉



  • Shlo schrieb:

    #include <iostream>
    	template<class E, class T, class A>
    	std::basic_string<E,T,A> to_string() const
    	{
    		typedef typename std::basic_string<E,T,A>::value_type value_type;
    		typedef typename std::basic_string<E,T,A>::traits_type traits_type;
    		typedef typename std::basic_string<E,T,A>::allocator_type allocator_type;
    
    		typedef std::basic_ostringstream<value_type,
    			traits_type,allocator_type> ostringstream;
    
    		ostringstream oss;
    		oss << *this;
    
    		return oss.str();
    	}
    

    wie verwendet man diese funktion? mach mal ein beispiel.

    fraction operator-() const
    {
    	return fraction(-num_,-den_);
    }
    

    einmal - wäre ok.



  • es werden hier erstaunlich viele oo-prinzipien bemüht.
    aber warum nur?
    was ist dagegen zu sagen, die attribute aufzumachen, wenn eh der vollständige satz von getters/setters da ist? ok, der getter/setter sollten gar nicht alle da sein. warum, wenn man eh immer statt a.nom(5) ein a=rational(5,a.denom()) schreiben kann? ah, ich weiß schon, um ne invariante garantieren zu können. hier sollte man aber gucken, ob man eine hat, und nicht ob man unter umständen eine haben könnte. es gehört zum wesen der klasse, ob die brüche zum beispiel immer normiert vorliegen oder nicht. kann man zu schlecht nachrüsten, weil sich die anderen leutchen duchaus drauf verlassen.

    das erhebt eh mal die frage, warum der op== normalerweise als return a.nom==b.nom && a.denom==b.denom und nicht als return a.nom*b.denom==b.nom*a.denom implementiert ist. eigentlich sollten doch 2/4 und -3/-6 gleich sein.
    zu teuer? dann bleibt wohl nur übrig, die brüche normiert darzustellen. es bietet sich an, nur gekürzte brüche zu speichern, also nach jedem += oder so gleich zu kürzen. auch hier erhebt sich wieder eine frage, und zwar, warum fast alle hier noch vergessen, daß -2/-3 und 2/3 zwei darstellungen des gleichen wertes sind, also zur normierung noch gehört, den zähler nichtnegativ zu halten.



  • fraction a(2);
    string str = a.to_string<char,char_traits<char>,allocator<char> >();
    

    zwar etwas unübersichtlich, aber in den meisten Fällen würde man eh die Stream Funktionen benutzen. Das zweite habe ich geändert.



  • @volkard: Zu dem -2/-3:

    Ich empfehle, keine setter für die Datenelemente anzubieten. Wozu denn? Soll sich derjenige halt einen neuen Bruch erstellen mit den gewünschten Werten.
    Außerdem empfiehlt es sich IMHO (jetzt, wo wir die Kontrolle wieder haben ;/), dafür zu Sorgen, dass der Nenner stets positiv ist. Sollte der Nenner negativ sein, werden jeweils Zähler und Nenner mit -1 multipliziert. Und schon gibt es auch keine zwei Darstellungen mehr für die selbe Zahl.



  • Optimizer schrieb:

    @volkard: Zu dem -2/-3:

    Ich empfehle, keine setter für die Datenelemente anzubieten. Wozu denn? Soll sich derjenige halt einen neuen Bruch erstellen mit den gewünschten Werten.
    Außerdem empfiehlt es sich IMHO (jetzt, wo wir die Kontrolle wieder haben ;/), dafür zu Sorgen, dass der Nenner stets positiv ist. Sollte der Nenner negativ sein, werden jeweils Zähler und Nenner mit -1 multipliziert. Und schon gibt es auch keine zwei Darstellungen mehr für die selbe Zahl.

    hast in beiden fällen recht. ich würde auch keine setter anbieten. aber nicht wegen berufung auf ein oo-prinzip. und genausoleicht, wie ich sie hier weglasse, baue ich sie woanders wieder hin.
    und nenner positiv ist besser als mein dummvorschlag mit zähler nichtnegativ.



  • Shlo schrieb:

    fraction a(2);
    string str = a.to_string<char,char_traits<char>,allocator<char> >();
    

    zwar etwas unübersichtlich, aber ...

    es ist unfug. weg damit.



  • Welche Gründe gab/gibt es, dem Standard keine Bruchklasse zu verpassen?



  • Gute Frage. Vor allem, weil es für komplexe Zahlen nämlich schon etwas gibt.



  • Brüche braucht man in der Praxis nicht, komplexe Zahlen schon.



  • @optimizer: erklärst du deine Anmerkungen zu deinem Posting nochmal für mich?



  • meine Anmerkungen zu meinem Posting? Ich verstehe jetzt nicht was du meinst. Ich wollte nur zum Ausdruck bringen, dass mich das ebenso ein wenig wundert, weil sich mathematische Klassen mit den Möglichkeiten von C++ meiner Meinung nach besonders anbieten.
    Ich vermisse nicht nur Brüche sondern auch beliebig große Integer und beliebig genaue floating-Point Zahlen.



  • Das war mein Fehler. Ich meinte dein Posting auf meine Klasse.



  • Optimizer schrieb:

    Hilfe! m_ 😞
    Ein klein geschriebener Klassenname.
    Wieso ist ggT nicht statisch, wenn es doch die beiden Zahlen kriegt?
    Wieso kriegt kuerzen() die beiden Zahlen, wenn es nicht statisch ist?

    Du meinst wohl das. 🙂

    Also erstens finde ich es hässlich und unnötig, Member mit m_ zu kennzeichnen. Es ist eine ziemliche Unsitte, im Variablennamen zu kennzeichnen, was für ein Typ etwas ist, anstatt zu kennzeichnen, wofür das Ding da ist und welche Aufgabe es erfüllt.
    Ein einfaches num und denom (als Beispiel) würde völlig reichen.

    Desweiteren sollte man Klassennamen IMHO groß schreiben. Ich kann mir jetzt natürlich herausnehmen, zu sagen, meine Konvention sei die einzig wahre, aber in diesem Punkt sind die meisten Leute der Meinung, dass Klassennamen groß geschrieben werden sollten.

    Die Funktion ggT() kriegt zähler und nenner geliefert, also kann sie gleich statisch sein, weil sie sich überhaupt nicht auf den eigenen Bruch (this) bezieht.

    Das selbe gilt für kürzen(). Wobei ich persönlich beide nicht statisch machen würde, aber dafür auch keine Parameter übernehmen würde. Die Werte können sie dann selber auslesen. Auf jeden Fall ist nicht-statisch und Parameter doppelt gemoppelt.

    Außerdem bin ich der Meinung, dass beide Methoden private sein sollten. Ein Bruch kann sich selber kürzen, das muss von außen keiner anschaffen.



  • Wie findet ihr eigentlich boost::rational ? (so gut wie Standard)



  • Du magst in allen Punkten Recht haben. Hier einige Anmerkungen von mir dazu:

    Die Sitte, Member mit m_ zu kennzeichnen, habe ich dem Buch des Seitenbetreibers hier entnommen. Ich finde das nicht schlecht, weil ich damit selbst einen besseren Überblick über private- und public-Variablen habe.

    Ich habe den Klassennamen klein geschrieben, weil die Klassen string und vector etc. auch klein geschrieben sind. In das Buch des Seitenbetreibers will ich an dieser Stelle wegen der fortgeschrittenen Stunde nicht gucken, mag aber gut sein, dass er es anders hält 😉

    Das mit dem statisch hab ich nicht so ganz geschnallt (Achtung, für dummies langsam sprechen).

    ggt und kürzen sind doch private. Oder seh ich den Wald vor lauter Bäumen nicht mehr ...?

    Gez geh ich schlafen, gute N8. 👍



  • 1. public-Variablen dürftest du eigentlich ÜBERHAUPT keine haben o.O
    2. wenn du Funktionen in einer Klasse mit static auszeichest, dann bedeutet das, dass diese Funktion nicht mehr auf den Werten eines bestimmten Objektes operiert. Das heißt, du hast keinen this-Zeiger mehr zur verfügung, weil statische Funktionen an kein Objekt gebunden sind. Guckst du einfach mal in ein Buch, dass kann das bestimtm besser erklären, als ich.



  • Das läuft wie folgt:
    Member mit m_ kommt von MFC. :p
    MFC ist schlechtes C++. 🙄
    m_ ist schlecht für C++. 😮

    Zur Zeit ist dataelement_ (nachgestellter Underscore) in.
    Argument Herb Sutter: "Since I'm no longer allowed to use leading underscores as my "member variable" tag, I'll now use trailing underscores!" (s.u.)
    Auch nicht gerade überzeugend, wie er argumentiert. 😉

    Meine Meinung:
    Alles ist irgendwie brauchbar und gleichzeitig beknackt. 🤡
    (Ausnahme: voran gestellter Underscore)
    siehe: http://www.gotw.ca/gotw/004.htm

    11. Style: Try to avoid names with leading underscores. Yes, I've habitually used them, and yes, popular books like "Design Patterns" (Gamma et al) do use it... but the standard reserves some leading-underscore identifiers for the implementation and the rules are hard enough to remember (for you and for compiler writers!) that you might as well avoid this in new code. (Since I'm no longer allowed to use leading underscores as my "member variable" tag, I'll now use trailing underscores!)



  • Es will mir nicht in den Kopf, warum private Member überhaupt gekennzeichnet werden müssen?!



  • Man möchte oft den gleichen Namen für die Membervariable wie auch eine als Parameter übergebene Variable benutzen (z.B. in einer Initialisierungsliste). Man kann zur Unterscheidung den Zeiger this vorstellen, aber elegant ist das wirklich nicht.

    Hier ein kleiner Ausschnitt aus einer Klasse MyString:

    class MyString
    {
    public:
      MyString(char* pText=NULL);                  // ctor 
      MyString(const MyString& str);               // Copy-Konstruktor
      MyString& operator=(const MyString& str);    // Zuweisungsoperator
      ~MyString();                                 // dtor 
    //...
    
    private:
      char* pText_;
    };
    
    MyString::MyString(char* pText)
    {
      if (pText)
      {
        pText_ = new char[ strlen(pText+1) ];
        strcpy(pText_, pText);
      }
      else
      {
        pText_ = new char[1];
        *pText_='\0';
      }
    }
    

    Man hat die Membervariable pText_ und einen Parameter pText. Man kann sich hier streiten, ob m_pText und pText nicht eine klarer erkennbarere Unterscheidung bringen. Geschmacksache.


Anmelden zum Antworten