[TMP] Vollkommene Zahlen - Wo Fehler ?



  • Hi,

    versuche gerade mit Hilfe von TMP festzustellen, ob eine Zahl eine vollkommene Zahl ist.

    Hier der Code bis jetzt:

    template<unsigned long N, unsigned long T = 1, unsigned long S = 0>
    struct isVol
    {
        static const bool isTrue = (T < N) ? (!(N % T) ? isVol<N,T+1,S+T>::value : isVol<N,T+1,S>::value) : false;
    };
    
    int main()
    {
      cout << isVol<1>::isTrue << endl;
    }
    

    Wenn jetzt N = 1 ist dann schlägt der Test T < N fehl und isTrue sollte false sein. Jedoch rastet das Programm beim kompilieren aus.

    Wo liegt der Fehler ?

    Und nichts anderes schreiben, will das ja selber machen 😉
    Könnt ja später meine Lösung kritisieren ...



  • KasF schrieb:

    isTrue = (T < N) ? (!(N % T) ? isVol<N,T+1,S+T>::value : isVol<N,T+1,S>::value) : false;

    mit sowas könntest du jedenfalls am 'obfuscated C contest' teilnehmen. 😉
    schreib das mal schön, mehrzeilig und strukturiert auf. vielleicht siehst du dann einen fehler.
    🙂



  • Der Fehler dürfte darin liegen, daß du keine Anfangsbedingung für die Rekursion definiert hast. (und auch wenn sie eignetlich nicht gebraucht werden, muß der Compiler alle Spezialisierungen anlegen)



  • Ich hab's mit drei Compilern ausprobiert. Ist nett mit anzusehen - sie rasten wirklich aus 😉

    Das Problem liegt wohl darin, dass der Compiler in jedem Fall den ersten Ausdruck auch mit übersetzen will, auch wenn die Bedingung nicht erfüllt ist. Damit landet der Compiler dannn automatisch in einer Endlosschleife.
    Man müsste sich also irgendwie mit einer Spezialisierung eine solche Abbruchbedingung basteln ..

    Viel Spaß
    Werner



  • a ? b : false;
    // ist übrigens dasselbe wie:
    a and b;
    


  • Werner Salomon schrieb:

    Das Problem liegt wohl darin, dass der Compiler in jedem Fall den ersten Ausdruck auch mit übersetzen will, auch wenn die Bedingung nicht erfüllt ist. Damit landet der Compiler dannn automatisch in einer Endlosschleife.

    Achso, das könnte es sein 🙂

    Konrad Rudolph schrieb:

    a ? b : false;
    // ist übrigens dasselbe wie:
    a and b;
    

    Habe mir gedacht, dass das einer schreiben wird :). Hatte es auch so und habe solange umgeschrieben um den Fehler zu finden ...



  • KasF schrieb:

    Habe mir gedacht, dass das einer schreiben wird :). Hatte es auch so und habe solange umgeschrieben um den Fehler zu finden ...

    Ach mir wird jetzt klar, wieso ich das gemacht hatte. Es muss so sein, da !(N%T) nicht heißt das abgebrochen wird, aber bei T > N schon ...



  • KasF schrieb:

    KasF schrieb:

    Habe mir gedacht, dass das einer schreiben wird :). Hatte es auch so und habe solange umgeschrieben um den Fehler zu finden ...

    Ach mir wird jetzt klar, wieso ich das gemacht hatte. Es muss so sein, da !(N%T) nicht heißt das abgebrochen wird, aber bei T > N schon ...

    Doch, es heißt genauso, dass abgebrochen wird.

    Wenn ich schreibe „dasselbe“ dann meine ich das auch. Die beiden Ausdrücke sind strikt äquivalent, sowohl im Wert als auch im Nebeneffekt.



  • 🙄 Habe verstanden was du meinst ... ( liegt vllt am noch leeren Magen )



  • Hallo zusammen,

    Wenn in einer Templateklasse weitere Templates auftauchen, so werden diese aufgelöst.
    In unserer rekursiven Funktion würde der Compiler nicht aufhören neue Templates zu bearbeiten.
    Um diesem Problem zu entgehen muss die Abbruchbedingung als Templatespezialisierung ausgelagert werden. Vgl. folgendes.

    #include <cassert>
    
    // Unsere Funktionen arbeiten nur mit positiven Ganzzahlen
    typedef unsigned long u_long;
    
    /* Hier wird die Summe s aller Teiler von n (mit Ausnahme von n
     * selber) gebildet
     */
    template <u_long n, u_long i = n-1, u_long s = 0>
    struct sum_of_divisors {
    	static const u_long value =
    		n%i ? sum_of_divisors<n, i-1, s>::value :
    			sum_of_divisors<n, i-1, s+i>::value;
    };
    
    // abbrechen, wenn der Zaehler i bei 0 angekommen ist
    template <u_long n, u_long s>
    struct sum_of_divisors<n, 0, s> {
    	static const long value = s;
    };
    
    template <u_long n>
    struct is_deficient { // wenn Summe aller Teiler von n kleiner als n
    	static const bool value = sum_of_divisors<n>::value < n;
    };
    template <u_long n>
    struct is_perfect { // wenn Summe aller Teiler von n gleich n
    	static const bool value = sum_of_divisors<n>::value == n;
    };
    template <u_long n>
    struct is_abundant { // wenn Summe aller Teiler von n groesser n
    	static const bool value = sum_of_divisors<n>::value > n;
    };
    
    int main()
    {
    	assert((is_perfect<6>::value == true));
    	assert((is_perfect<28>::value == true));
    }
    

    Weitere Anmerkung: Die Negation lässt sich nach dem Prinzip von ausgeschlossenen Dritten (es liegt ein Boole'scher Wert vor) durch einfaches Vertauschen der Operanden vermeiden (aus (!c)?b:a wird c?a:b).
    🙂

    Grüße Martin

    --
    PS: mögliche Fragen kann ich vorerst nicht beantworten, da Urlaub



  • Danke lucky_tux ....
    Jetzt hast du mir den ganzen Spaß weggenommen.

    🙂


Anmelden zum Antworten