Von n auf die nächst größere 2er Potenz



  • groovemaster schrieb:

    Ein Template Ersatz ist deine Lösung trotzdem nicht.

    Ein Template-Ersatz wird auch nicht benötigt. Wenn ich den Wert zur Compilezeit kenne, dann schreibe ich ihn direkt in den Quelltext und geheimse da nicht irgendwelches template<>::blabla-Gefrickel drumrum.



  • groovemaster schrieb:

    Die konstante Laufzeit hast du dir aber auch nur dadurch "erschummelt", dass du es auf 32 Bit begrenzt.

    ja, für z.b. 64 bit braucht man eine zeile mehr, für 128 bit eine weitere usw.
    zum glück sind die datenwortbreiten von computern nicht so sehr variabel, als dass man sowas mit 'ner schleife machen müsste 😉

    Daniel E. schrieb:

    Ein Template-Ersatz wird auch nicht benötigt. Wenn ich den Wert zur Compilezeit kenne, dann schreibe ich ihn direkt in den Quelltext und geheimse da nicht irgendwelches template<>::blabla-Gefrickel drumrum.

    das lässt die template-varianten aber ganz alt aussehen 😃



  • Daniel E. schrieb:

    Ein Template-Ersatz wird auch nicht benötigt. Wenn ich den Wert zur Compilezeit kenne, dann schreibe ich ihn direkt in den Quelltext und geheimse da nicht irgendwelches template<>::blabla-Gefrickel drumrum.

    Und was machste dann mit 'foo'. Das kann auch eine compile time Konstante sein. Klar, du kannst im entsprechenden Header nachschauen, um den Wert zu erfahren. Aber was ist, wenn den mal jemand ändert? Denkst du auch daran, die abhängigen Stellen anzupassen? Stichwort: Eliminierung von Redundanzen. 😉



  • groovemaster schrieb:

    Daniel E. schrieb:

    Ein Template-Ersatz wird auch nicht benötigt. Wenn ich den Wert zur Compilezeit kenne, dann schreibe ich ihn direkt in den Quelltext und geheimse da nicht irgendwelches template<>::blabla-Gefrickel drumrum.

    Und was machste dann mit 'foo'. Das kann auch eine compile time Konstante sein. Klar, du kannst im entsprechenden Header nachschauen, um den Wert zu erfahren. Aber was ist, wenn den mal jemand ändert?

    Dieses Problem in C bereits gelöst worden, #if&#error lassen grüßen. Zugegebenermaßen, besonders elegant war das noch nie, aber die Template-Lösung saugt auch ziemlich, die bringt uns wieder in die Zeiten zurück, wo man auf ein Compilat von mittelmäßig großen Programmen ein paar Stunden warten muß, von der augenkrebsverursachenden Syntax ganz abgesehen.



  • Undertaker schrieb:

    groovemaster schrieb:

    Die konstante Laufzeit hast du dir aber auch nur dadurch "erschummelt", dass du es auf 32 Bit begrenzt.

    ja, für z.b. 64 bit braucht man eine zeile mehr, für 128 bit eine weitere usw.
    zum glück sind die datenwortbreiten von computern nicht so sehr variabel, als dass man sowas mit 'ner schleife machen müsste 😉

    Aber variabel genug dass man das nicht so im Code stehen haben will. Es gibt schon viel zu viele sorglose Leute, die Datentypgrößen ignorieren.

    template <typename T, unsigned s, unsigned e>
    struct npo2_
    {
        static T& impl () (T& x)
        {
            x |= x >> e; 
            return npo2_<T, s - 1, e * 2>::impl (x);
        }
    };
    
    template <typename T, unsigned e>
    struct npo2_<T, 0, e>
    {
        static T& impl () (T& x) { return x |= x >> e; }
    };
    
    template <typename Int>
    Int next_pow_of_2 (Int x)
    {
        return npo2_<Int, sizeof(Int), 1>::impl (--x) + 1;
    }
    

    Das ergibt übrigens auf einem anständigen Compiler meines Erachtens exakt dasselbe wie deine Lösung (vorausgesetzt ich habe mich nicht vertan, hab wiederum keinen Compiler zur Hand ;))

    Daniel E. schrieb:

    die Template-Lösung saugt auch ziemlich, die bringt uns wieder in die Zeiten zurück, wo man auf ein Compilat von mittelmäßig großen Programmen ein paar Stunden warten muß

    Aber sicherlich nicht bei einem solchen Template. Ekelhaft wirds nur bei wirklich vielen Templateinstanziierungen (>> 20).



  • Daniel E. schrieb:

    Dieses Problem in C bereits gelöst worden, #if&#error lassen grüßen.

    Mit #if und #error? Zeig mal ein Beispiel, das interessiert mich jetzt. Ich hoffe nicht, dass es das ist, was ich jetzt glaube.



  • .filmor schrieb:

    Undertaker schrieb:

    groovemaster schrieb:

    Die konstante Laufzeit hast du dir aber auch nur dadurch "erschummelt", dass du es auf 32 Bit begrenzt.

    ja, für z.b. 64 bit braucht man eine zeile mehr, für 128 bit eine weitere usw.
    zum glück sind die datenwortbreiten von computern nicht so sehr variabel, als dass man sowas mit 'ner schleife machen müsste 😉

    Aber variabel genug dass man das nicht so im Code stehen haben will. Es gibt schon viel zu viele sorglose Leute, die Datentypgrößen ignorieren.

    template <typename T, unsigned s, unsigned e>
    struct npo2_
    {
        static T& impl () (T& x)
        {
            x |= x >> e; 
            return npo2_<T, s - 1, e * 2>::impl (x);
        }
    };
    
    template <typename T, unsigned e>
    struct npo2_<T, 0, e>
    {
        static T& impl () (T& x) { return x |= x >> e; }
    };
    
    template <typename Int>
    Int next_pow_of_2 (Int x)
    {
        return npo2_<Int, sizeof(Int), 1>::impl (--x) + 1;
    }
    

    Das ergibt übrigens auf einem anständigen Compiler meines Erachtens exakt dasselbe wie deine Lösung (vorausgesetzt ich habe mich nicht vertan, hab wiederum keinen Compiler zur Hand ;))

    sizeof? sehr hübsch, geht noch ein bisschen, |= ist keine so gute Idee mit constexpr

    template <typename T>
    struct npo2_
    {
        template<size_t N> static constexpr T impl(const T& x) { return impl< 2 * N >( x | x >> N ); }
        template<> static constexpr T impl< next_pow2< std::numeric_limits< T >::digits >::value > >(const T& x) { return x; }
    };
    
    template <typename Int>
    constexpr Int next_pow_of_2(const Int& x)
    {
        return npo2_< Int >::impl< 1 >( x - 1 ) + 1;
    }
    

    Ich geh mal davon aus, dass für eine Integer-Klasse, die binäre Operationen erlaubt, radix == 2 ist.



  • Hm. Ich denke mir gerade... sämtliche LISP Programmierer werden sich wohl krumm lachen wenn sie den Thread hier lesen 🙂



  • Hallo

    hustbaer schrieb:

    sämtliche LISP Programmierer werden sich wohl krumm lachen wenn sie den Thread hier lesen 🙂

    LISP'ler würden wohl die Lösung

    exp(log(2)*ceil(log(n)/log(2)))
    

    oder eher so etwas wie

    (exp (* (log (2)) (ceil (/ (log (n)) (log (2))))))
    

    bevorzugen - ein reines funktionalen Programm 🙂

    Gruß



  • Ich meinte eigentlich dass das ganze Template-Zeugs was in C++ nötig ist um es auf "funktionalem" Weg umd mit Integer Arithmetik zu lösen in LISP wahrscheinlich bloss 2 oder 3 Zeilen lang wäre. Ohne log und exp und ceil und anderen Abscheulichkeiten.


Anmelden zum Antworten