array mit vorberechneten werten füllen





  • fib.h:

    #ifndef FIB_H
    #define FIB_H
    
    template <int i, int a, int b>
    struct FibH
    {
      int x;
      FibH<i-1, b, a+b> rest;
    
      FibH() : x(a) {}
    };
    
    template<int a, int b>
    struct FibH<0,a,b>
    {
      int x;
      FibH() : x(a) {}
    };
    
    #endif
    

    main.cpp:

    #include "fib.h"
    #include <iostream>
    
    int main()
    {
      const int n = 45;
      FibH<n,0,1> f;
    
      for(int i = 0; i < n; ++i)
      {
        std::cout << i << ":  " << reinterpret_cast<int*>(&f)[i] << "\n";
      }
    }
    


  • knivil schrieb:

    ...
    

    lol.
    Nett gemacht. 👍



  • Prinzipiell von Stackoverflow kopiert: hier. Natuerlich ist der Konstruktor noch haesslich, da vielleicht die Arbeit nur dorthin verschoben wurde. C++11 erlaubt ja:

    template <int n, int a, int b>
    class FibH
    {
      int x = a;
      ...
    };
    

    So kann auf den Konstruktor verzichtet werden. Obs besser ist und FibH dadurch ein POD wird, keine Ahnung. Ab der n=92 wird es fuer einen 64 Bit Integer kritisch.



  • Assembleroutput mit VS2010 bei mir:

    mov	DWORD PTR _f$[esp+192], 0
    	mov	DWORD PTR _f$[esp+196], 1
    	mov	DWORD PTR _f$[esp+200], 1
    	mov	DWORD PTR _f$[esp+204], 2
    	mov	DWORD PTR _f$[esp+208], 3
    	mov	DWORD PTR _f$[esp+212], 5
    	mov	DWORD PTR _f$[esp+216], 8
    	mov	DWORD PTR _f$[esp+220], 13		; 0000000dH
    	mov	DWORD PTR _f$[esp+224], 21		; 00000015H
    	mov	DWORD PTR _f$[esp+228], 34		; 00000022H
    	mov	DWORD PTR _f$[esp+232], 55		; 00000037H
    	mov	DWORD PTR _f$[esp+236], 89		; 00000059H
    	mov	DWORD PTR _f$[esp+240], 144		; 00000090H
    	mov	DWORD PTR _f$[esp+244], 233		; 000000e9H
    	mov	DWORD PTR _f$[esp+248], 377		; 00000179H
    	mov	DWORD PTR _f$[esp+252], 610		; 00000262H
    	mov	DWORD PTR _f$[esp+256], 987		; 000003dbH
    	call	??0?$FibH@$0BM@$0GDN@$0KBI@@@QAE@XZ	; FibH<28,1597,2584>::FibH<28,1597,2584>
    
    ??0?$FibH@$0BM@$0GDN@$0KBI@@@QAE@XZ PROC		; FibH<28,1597,2584>::FibH<28,1597,2584>, COMDAT
    ; _this$ = esi
    
    ; 9    :   FibH() : x(a) {}
    
    	mov	DWORD PTR [esi], 1597			; 0000063dH
    	mov	DWORD PTR [esi+4], 2584			; 00000a18H
    	mov	DWORD PTR [esi+8], 4181			; 00001055H
    	mov	DWORD PTR [esi+12], 6765		; 00001a6dH
    	mov	DWORD PTR [esi+16], 10946		; 00002ac2H
    	mov	DWORD PTR [esi+20], 17711		; 0000452fH
    	mov	DWORD PTR [esi+24], 28657		; 00006ff1H
    	mov	DWORD PTR [esi+28], 46368		; 0000b520H
    	mov	DWORD PTR [esi+32], 75025		; 00012511H
    	mov	DWORD PTR [esi+36], 121393		; 0001da31H
    	mov	DWORD PTR [esi+40], 196418		; 0002ff42H
    	mov	DWORD PTR [esi+44], 317811		; 0004d973H
    	lea	eax, DWORD PTR [esi+52]
    	mov	DWORD PTR [esi+48], 514229		; 0007d8b5H
    	call	??0?$FibH@$0P@$0MLCCI@$0BEIKNN@@@QAE@XZ	; FibH<15,832040,1346269>::FibH<15,832040,1346269>
    	mov	eax, esi
    	ret	0
    
    ??0?$FibH@$0P@$0MLCCI@$0BEIKNN@@@QAE@XZ PROC		; FibH<15,832040,1346269>::FibH<15,832040,1346269>, COMDAT
    ; _this$ = eax
    
    ; 9    :   FibH() : x(a) {}
    
    	mov	DWORD PTR [eax], 832040			; 000cb228H
    	mov	DWORD PTR [eax+4], 1346269		; 00148addH
    	mov	DWORD PTR [eax+8], 2178309		; 00213d05H
    	mov	DWORD PTR [eax+12], 3524578		; 0035c7e2H
    	mov	DWORD PTR [eax+16], 5702887		; 005704e7H
    	mov	DWORD PTR [eax+20], 9227465		; 008cccc9H
    	mov	DWORD PTR [eax+24], 14930352		; 00e3d1b0H
    	mov	DWORD PTR [eax+28], 24157817		; 01709e79H
    	mov	DWORD PTR [eax+32], 39088169		; 02547029H
    	mov	DWORD PTR [eax+36], 63245986		; 03c50ea2H
    	mov	DWORD PTR [eax+40], 102334155		; 06197ecbH
    	mov	DWORD PTR [eax+44], 165580141		; 09de8d6dH
    	mov	DWORD PTR [eax+48], 267914296		; 0ff80c38H
    	mov	DWORD PTR [eax+52], 433494437		; 19d699a5H
    	mov	DWORD PTR [eax+56], 701408733		; 29cea5ddH
    	mov	DWORD PTR [eax+60], 1134903170		; 43a53f82H
    	ret	0
    


  • mh also ich hab anfangs die falschen dinge bei google eignegeben und deswegen nix gefunden.

    aber jetzt mit dem link von stackoverflow hat das gut geklappt 🙂
    und wenn ich das richtig sehe, funktioniert es, dass man für alles berechenbare ein array erstellen kann ?!
    man muss nur die "formel" im konstruktor anpassen...



  • Also 🙂

    mir war eben langweilig und da hab ich mich mal rangesetzt und das implementiert,
    also dass ein richtiges array generiert wird 🙂

    Der Code ist etwas länger, aber ich hoffe, man kannes trotzdem lesen und verstehen 🙂

    Es werden ein paar C++11 Features verwendet (Variadic Templates & auto).

    Ab Zeile 120 kommt der zur Laufzeit relevante Teil, davor ist alles TMP.

    Hier der Code:

    #include <iostream>
    using std::cout;
    using std::endl;
    
    #include <exception>
    using std::exception;
    
    #include <stdexcept>
    using std::range_error;
    
    #include <boost/lexical_cast.hpp>
    using boost::lexical_cast;
    
    // maximum fibonacci number
    // must be defined to the compiler using -DMAX_FIB=xxx
    #ifndef MAX_FIB
    #warning "MAX_FIB undefined! Defaulting to 50."
    #define MAX_FIB 50
    #endif
    
    // simple fibonacci function
    template <unsigned long long Number>
    struct fib
    {
        static unsigned long long const value = fib<Number - 2>::value + fib<Number - 1>::value;
    };
    
    template <>
    struct fib<0>
    {
        static unsigned long long const value = 0;
    };
    
    template <>
    struct fib<1>
    {
        static unsigned long long const value = 1;
    };
    
    // determine the length of an integer pack
    template <unsigned long long... Numbers>
    struct length;
    
    template <unsigned long long Head, unsigned long long... Tail>
    struct length<Head, Tail...>
    {
        static unsigned long long const value = 1 + length<Tail...>::value;
    };
    
    template <>
    struct length<>
    {
        static unsigned long long const value = 0;
    };
    
    // a variadic integer pack to integer array converter
    template <unsigned long long... Numbers>
    struct to_array
    {
        static unsigned long long const value[length<Numbers...>::value];
    };
    
    template <unsigned long long... Numbers>
    unsigned long long const to_array<Numbers...>::value[] = { Numbers... };
    
    // a number list
    template <unsigned long long... Numbers>
    struct list;
    
    template <unsigned long long Head, unsigned long long... Tail>
    struct list<Head, Tail...>
    {
        static unsigned long long const head = Head;
        typedef list<Tail...> tail;
    };
    
    template <>
    struct list<>
    {
    };
    
    // append to a number list
    template <typename List, unsigned long long Value>
    struct append;
    
    template <unsigned long long Value>
    struct append<list<>, Value>
    {
        typedef list<Value> type;
    };
    
    template <unsigned long long... Numbers, unsigned long long Value>
    struct append<list<Numbers...>, Value>
    {
        typedef list<Numbers..., Value> type;
    };
    
    // generate number list using fib function
    template <unsigned long long Maximum>
    struct fib_list
    {
        typedef typename append<typename fib_list<Maximum - 1>::type, fib<Maximum>::value>::type type;
    };
    
    template <>
    struct fib_list<0>
    {
        typedef list<fib<0>::value> type;
    };
    
    // generate an array from a list
    template <typename List>
    struct array_from_list;
    
    template <unsigned long long... Numbers>
    struct array_from_list<list<Numbers...>>
    {
        typedef to_array<Numbers...> type;
    };
    
    // our precalculated fibonacci numbers
    typedef typename array_from_list<typename fib_list<MAX_FIB>::type>::type fibonacci_array;
    unsigned long long const * const fibonacci = fibonacci_array::value;
    
    inline void show_usage(char const * const program)
    {
        cout << "Usage: " << program << " [number]" << endl;
    }
    
    int main(int argc, char ** argv)
    {
        if (argc != 2)
        {
            cout << "Wrong number of parameters!\n";
            show_usage(*argv);
        }
    
        try
        {
            auto number = lexical_cast<unsigned long long>(argv[1]);
            if (number > MAX_FIB)
                throw range_error("The given number is too big!");
    
            cout << fibonacci[number] << endl;
        }
        catch (exception const & ex)
        {
            cout << "An exception occured: " << ex.what() << "\n";
            show_usage(*argv);
        }
    
        return 0;
    }
    

  • Mod

    Das Ganze lässt sich auch ohne reinterpret_cast schreiben. Dann ist auch keine dynamische Initialisierung erforderlich.

    #include <type_traits>
    template <std::size_t i> struct fib : std::integral_constant<unsigned long long, fib<i-1>::value + fib<i-2>::value> {};
    template <> struct fib<0> : std::integral_constant<unsigned long long, 0> {};
    template <> struct fib<1> : std::integral_constant<unsigned long long, 1> {};
    
    template <typename T> struct identity { typedef T type; };
    template <std::size_t... i> struct indexes : identity<indexes<i...>> {};
    template <typename T> struct append;
    template <std::size_t... i> struct append<indexes<i...>> : identity<indexes<0, ( i + 1 )...>> {};
    template <std::size_t N> struct make_indexes : append<typename make_indexes<N-1>::type> {};
    template <> struct make_indexes<0> : identity<indexes<>> {};
    
    template <template <std::size_t> class func, std::size_t a, std::size_t b, typename = typename make_indexes<b-a+1>::type>
    struct func_data;
    template <template <std::size_t> class func, std::size_t a, std::size_t b, std::size_t... i>
    struct func_data<func, a, b, indexes<i...>>
    {
        static const decltype(func<a>::value) data[b-a+1];
    };
    
    template <template <std::size_t> class func, std::size_t a, std::size_t b, std::size_t... i>
    const decltype(func<a>::value) func_data<func, a, b, indexes<i...>>::data[b-a+1] = { func<a+i>::value... };
    /*
    template <template <std::size_t> class func, std::size_t a, std::size_t b, std::size_t... i>
    struct func_data<func, a, b, indexes<i...>>
    {
        static constexpr decltype(func<a>::value) data[] = { func<a+i>::value... };
    };
    */
    #include <iostream>
    
    int main()
    {
      const int n = 45;
      func_data<fib, 0, 44> f;
    
      for(int i = 0; i < n; ++i)
      {
        std::cout << i << ":  " << f.data[i] << "\n";  }
    }
    

    Edit: ok, Drako war etwas schneller.



  • @camper:

    wenn ich mir deinen Code so anschaue, muss ich sagen,
    dass ich ein paar Sachen bei mir hätte besser machen können :p

    Vor allem die Arrayerstellung mit dem Pattern "func<a+i>::value..." war mir vorhin irgendwie entfallen :S

    Aber eine Frage zu deinem Code habe ich noch^^

    const decltype(func<a>::value) func_data<func, a, b, indexes<i...>>::data[b-a+1] = { func<a+i>::value... };
    

    Ist das const am Anfang wirklich nötig?
    Ich bin mir eben nicht sicher, ob nicht decltype das schon enthalten müsste.


  • Mod

    DrakoXP schrieb:

    const decltype(func<a>::value) func_data<func, a, b, indexes<i...>>::data[b-a+1] = { func<a+i>::value... };
    

    Ist das const am Anfang wirklich nötig?

    Erforderlich ist es sicher nicht (sofern man konsequent bleibt). Das ist hier einfach Gewohnheit. Eigentlich sollte es ja ohnehin constexpr sein, aber g++ unterstützt die Aggregatinitialisierung innerhalb der Klassendefinition noch nicht.


  • Mod

    Man kann das ganze auch ohne Verwendung eine fibonacci-Metafunktion schreiben:

    #include <type_traits>
    
    // index-Erstellung mit logarithmischer Komplexität
    template <typename T> struct identity { typedef T type; };
    template <std::size_t... i> struct indexes
        : identity<indexes<i...>> {};
    template <typename... T> struct concat
        : concat<typename T::type...> {};
    template <std::size_t... i, std::size_t... j, typename... T> struct concat<indexes<i...>, indexes<j...>, T...>
        : concat<indexes<i..., (sizeof... i + j)...>, T...> {};
    template <typename T> struct concat<T>
        : T {};
    template <typename T> struct twice
        : concat<T, T> {};
    template <std::size_t N> struct make_indexes
        : concat<twice<make_indexes<N/2>>, make_indexes<N%2>> {};
    template <> struct make_indexes<0>
        : indexes<> {};
    template <> struct make_indexes<1>
        : indexes<0> {};
    
    template <std::size_t N, typename = typename make_indexes<N-2>::type>
    struct fib_data;
    template <std::size_t N, std::size_t... i>
    struct fib_data<N, indexes<i...>>
    {
        static const unsigned long long data[N];
    };
    
    template <std::size_t N, std::size_t... i>
    const unsigned long long fib_data<N, indexes<i...>>::data[N] = { 0, 1, ( data[i] + data[i+1] )... };
    
    #include <iostream>
    
    int main()
    {
      const int n = 94;
      fib_data<n> f;
    
      for(int i = 0; i < n; ++i)
      {
        std::cout << i << ":  " << f.data[i] << "\n";
      }
    }
    

    Sieht man von dem Teil davor ab, dürfte diese Form der Initialisierung auch für relative Anfänger ohne TMP-Kentnisse lesbar sein. Allerdings führt das zumindest im Moment bei g++ zu dynamischer Initialisierung, weil die Verwendung von bereits initialisierten Subobjekten in konstanten Ausdrücken bisher nicht implementiert ist (das gleiche Problem hat man auch, wenn man einen constexpr Konstruktor schreiben will).



  • Mir faellt gerade auf, dass dieser Code mit den ganze ... eigentlich wie Scheme-Makros ausschaut.



  • Ich hatte da eigentlich an eine Funktion gedacht, wo drin das Array per static deklariert wird. Aber sonst sieht das auch fast genauso aus, wie bei Euch:

    #include <type_traits>
    
    template<class T> struct identity {typedef T type;};
    
    template<class...T> struct pack {};
    
    template<int Beg, int End, int...Tail>
    struct index_pack_type
      : index_pack_type<Beg,End-1,End-1,Tail...> {};
    template<int BE, int...Tail>
    struct index_pack_type<BE,BE,Tail...>
      : identity<pack<std::integral_constant<int,Tail>...> > {};
    
    template<int B, int E>
    typename index_pack_type<B,E>::type make_index_pack() {
      return typename index_pack_type<B,E>::type();
    }
    
    template<class ValueType, template<class> class MetaFunc, class...MetaArgs>
    inline ValueType const* lookuptable(pack<MetaArgs...>) {
      static const ValueType data[] = {MetaFunc<MetaArgs>::value...};
      return data;
    }
    
    #include <iostream>
    
    template<int I> struct fib_c : std::integral_constant<int,
      fib_c<I-1>::value + fib_c<I-2>::value
    >{};
    template<> struct fib_c<0> : std::integral_constant<int,0>{};
    template<> struct fib_c<1> : std::integral_constant<int,1>{};
    
    template<class MetaArg> struct fib : fib_c<MetaArg::value>{};
    
    int main() {
      const int N = 10;
      const int* fibtab = lookuptable<int,fib>(make_index_pack<0,N>());
      for (int i=0; i<N; ++i) {
        std::cout << fibtab[i] << std::endl;
      }
    }
    

Anmelden zum Antworten