Klasse für Bruchzahlen gesucht



  • template <typename IntType>
    class rational :
        less_than_comparable < rational<IntType>,
        equality_comparable < rational<IntType>,
        less_than_comparable2 < rational<IntType>, IntType,
        equality_comparable2 < rational<IntType>, IntType,
        addable < rational<IntType>,
        subtractable < rational<IntType>,
        multipliable < rational<IntType>,
        dividable < rational<IntType>,
        addable2 < rational<IntType>, IntType,
        subtractable2 < rational<IntType>, IntType,
        subtractable2_left < rational<IntType>, IntType,
        multipliable2 < rational<IntType>, IntType,
        dividable2 < rational<IntType>, IntType,
        dividable2_left < rational<IntType>, IntType,
        incrementable < rational<IntType>,
        decrementable < rational<IntType>
        > > > > > > > > > > > > > > > >
    

    Sieht zumindest witzig aus... 🙄



  • fehlt da nicht public oder ein andres keyword? 😕



  • http://www.boost.org/libs/rational/rational.html#Interface

    Bei boost gibt es eben (fast) alles. 🙂

    #include <iostream>
    #include <conio.h>
    #include <boost/rational.hpp>
    using namespace std;
    using namespace boost;
    
    int main()
    {
      rational<int> a,b,c;
      cout << "Bruch 1:  "; cin >> a;
      cout << "Bruch 2:  "; cin >> b;
      c = a*b;
      cout << "Resultat: " << c << " = " << rational_cast<double>(c);
      getch();
    }
    

    Ausgabe:
    Bruch 1: 2/33
    Bruch 2: 5/55
    Resultat: 2/363 = 0.00550964

    Der Nachteil bei boost ist allerdings, dass man nicht auf einfache Weise selbst die Klasse verändern kann.



  • otze schrieb:

    fehlt da nicht public oder ein andres keyword? 😕

    Wenn es eine private-Ableitung ist, warum sollte es?



  • fehlt da nicht public oder ein andres keyword?
    Wenn es eine private-Ableitung ist, warum sollte es?

    //...
    template <typename IntType>
    class rational :
      //...
    {
        typedef IntType int_type;
        typedef typename boost::call_traits<IntType>::param_type param_type;
    
    public:
        rational() : num(0), den(1) {}
        rational(param_type n) : num(n), den(1) {}
        rational(param_type n, param_type d) : num(n), den(d) { normalize(); }
    
        // Default copy constructor and assignment are fine
    
        // Add assignment from IntType
        rational& operator=(param_type n) { return assign(n, 1); }
    
        // Assign in place
        rational& assign(param_type n, param_type d);
    
        // Access to representation
        IntType numerator() const { return num; }
        IntType denominator() const { return den; }
    
        //...
    

    Wenn der Konstruktor private wäre, könnten wir wenig damit anfangen. 😉



  • "Hilfe! m_
    Ein klein geschriebener Klassenname."

    Was meinst du damit?



  • Erhard Henkes schrieb:

    Wenn der Konstruktor private wäre, könnten wir wenig damit anfangen. 😉

    Ehrlich gesagt verstehe ich den Zusammenhang nicht. Was hat das eine, mit dem anderen zu tun?



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


Anmelden zum Antworten