Effizienz von Rekursion

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Effizienz von Rekursion

    Hallo,

    mein Programm funktioniert sehr gut aber nur solange ich kleine m und n angebe. Wenn ich große Zahlen für m und n wähle, rechnet es ein paar Tage. Kann mir jemand helfen, um diese Rekursion effizienter zu machen??? Ich wollte die Daten in eine Tabelle schreiben aber das hat irgendwie nicht geklappt. Danke für jeden Hinweis.

    Quellcode

    1. #include<stdio.h>
    2. float zeta_0(int m, int n)
    3. {float epsilon=1;
    4. float delta=6
    5. if(m==0) return 0;
    6. if(n==0) return 0;
    7. else return 1+((delta*n*zeta_0(m,n-1)+epsilon*m*n*zeta_0(m-1,n+1))/(delta*n+epsilon*m*n));
    8. }
    9. float zeta_1(int m, int n)
    10. {
    11. float M=6;
    12. float rho=6;
    13. if(m==0) return 0;
    14. if(n==0) return 0;
    15. else
    16. return ((M/rho)+M*n+m*n+M*zeta_0(m+1,n)+M*n*zeta_1(m,n-1)+m*n*zeta_1(m-1,n+1)-M*zeta_0(m,n))/(M*n+m*n);
    17. }
    18. main()
    19. {int m;
    20. int n;
    21. m=20;n=20;
    22. printf("%f\n",zeta_0(m,n));
    23. printf("%f\n",zeta_1(m,n));
    24. }
    Alles anzeigen


    Maria
  • Hallo!

    Wie du vielleicht bemerkt hast, werden die selben Werte irrsinnig oft berechnet wie z.B. zeta0(1,1) etc.
    Wenn man sich die Zwischenergebnisse cached, geht das ganze super schnell.
    Ich habe einen simplen Cache eingeführt bei dessen Anwendung sogar 100/100 ganz flott geht.

    Der Caches ist eine map die für jedes "m" eine Map enthält, die jedem "n" einen Wert zuweist. Mehr oder weniger ein dynamisches 3 dimensionales Array mit log(N) Zugriff pro Dimension :)

    Quellcode

    1. #include <stdio.h>
    2. #include <float.h>
    3. #include <map>
    4. #include <set>
    5. using namespace std;
    6. const float INVALID_CACHE_VALUE = FLT_MAX;
    7. class Cache : private map <int, map <int, float>* >
    8. {
    9. private:
    10. typedef map<int, float> innercont_t;
    11. public:
    12. virtual ~Cache ()
    13. {
    14. // free memory
    15. const_iterator cit = begin ();
    16. for (; cit != end (); ++cit)
    17. delete (*cit).second;
    18. }
    19. // returns INVALID_CACHE_VALUE if not found
    20. float getCachedValue (const int m, const int n)
    21. {
    22. // is m contained?
    23. const_iterator cit = find (m);
    24. if (cit != end ())
    25. {
    26. // yes -> is n contained?
    27. innercont_t* pCont = (*cit).second;
    28. innercont_t::const_iterator cit2 = pCont->find (n);
    29. if (cit2 != pCont->end ())
    30. return (*cit2).second;
    31. }
    32. return INVALID_CACHE_VALUE;
    33. }
    34. void addToCache (const int m, const int n, const float aValue)
    35. {
    36. // get container mapping of m
    37. innercont_t* pCont;
    38. const_iterator cit = find (m);
    39. if (cit != end ())
    40. pCont = (*cit).second;
    41. else
    42. {
    43. pCont = new map<int, float> ();
    44. insert (make_pair (m, pCont));
    45. }
    46. // add to inner cont
    47. pCont->insert (make_pair (n, aValue));
    48. }
    49. };
    50. // global variables for the cache
    51. Cache g_aCacheZeta0, g_aCacheZeta1;
    52. float zeta_0(const int m, const int n)
    53. {
    54. // check at the beginning - faster than cache lookup
    55. if (m == 0 || n == 0)
    56. return 0;
    57. // query cache
    58. float ret = g_aCacheZeta0.getCachedValue (m, n);
    59. if (ret == INVALID_CACHE_VALUE)
    60. {
    61. // calculate
    62. const float epsilon=1;
    63. const float delta=6;
    64. ret = 1+((delta*n*zeta_0(m,n-1)+epsilon*m*n*zeta_0(m-1,n+1))/(delta*n+epsilon*m*n));
    65. // add to cache
    66. g_aCacheZeta0.addToCache (m, n, ret);
    67. }
    68. return ret;
    69. }
    70. float zeta_1 (const int m, const int n)
    71. {
    72. // check at the beginning - faster than cache lookup
    73. if(m == 0 || n == 0)
    74. return 0;
    75. // query cache
    76. float ret = g_aCacheZeta1.getCachedValue (m, n);
    77. if (ret == INVALID_CACHE_VALUE)
    78. {
    79. // calculate
    80. const float M=6;
    81. const float rho=6;
    82. ret = ((M/rho)+M*n+m*n+M*zeta_0(m+1,n)+M*n*zeta_1(m,n-1)+m*n*zeta_1(m-1,n+1)-M*zeta_0(m,n))/(M*n+m*n);
    83. // add to cache
    84. g_aCacheZeta1.addToCache (m, n, ret);
    85. }
    86. return ret;
    87. }
    88. int main()
    89. {
    90. int m = 100;
    91. int n = 100;
    92. printf("%f\n",zeta_0(m,n));
    93. printf("%f\n",zeta_1(m,n));
    94. return 0;
    95. }
    Alles anzeigen


    hth
  • Und das ganze kann für mehrere Durchläufe insofern noch optimiert werden, als das der Inhalt des Caches in eine Datei gespeichert wird, bzw. von dort gelesen wird.
    Edit: Außerdem habe ich einige Berechnungen die doppelt durchgeführt wurden gespeichert (M*n, m*n, ...)
    Das ganze schaut dann so aus:

    Quellcode

    1. // compile with:
    2. // cl -EHsc -Ox zeta.cxx
    3. #if _MSC_VER >= 1400
    4. #define _CRT_SECURE_NO_DEPRECATE
    5. #endif
    6. #include <stdio.h>
    7. #include <float.h>
    8. #include <map>
    9. #include <set>
    10. using namespace std;
    11. const float INVALID_CACHE_VALUE = FLT_MAX;
    12. class Cache : private map <int, map <int, float>* >
    13. {
    14. private:
    15. typedef map<int, float> innercont_t;
    16. unsigned long m_nHits;
    17. unsigned long m_nMisses;
    18. bool m_bAltered;
    19. public:
    20. Cache ()
    21. : m_nHits (0),
    22. m_nMisses (0),
    23. m_bAltered (false)
    24. {}
    25. virtual ~Cache ()
    26. {
    27. // free memory
    28. const_iterator cit = begin ();
    29. for (; cit != end (); ++cit)
    30. delete (*cit).second;
    31. }
    32. // read cache file
    33. void read (const char *pFilename)
    34. {
    35. FILE* f = fopen (pFilename, "rb");
    36. if (f)
    37. {
    38. int m, n;
    39. unsigned long nSize;
    40. float v;
    41. innercont_t* pCont;
    42. while (fread (&m, sizeof (int), 1, f) == 1)
    43. {
    44. // read number of mappings
    45. fread (&nSize, sizeof (unsigned long), 1, f);
    46. // create new map for current m
    47. pCont = new innercont_t ();
    48. insert (make_pair (m, pCont));
    49. // read all mappings
    50. for (unsigned long i = 0; i < nSize; ++i)
    51. {
    52. fread (&n, sizeof (int), 1, f);
    53. fread (&v, sizeof (float), 1, f);
    54. // add mapping
    55. pCont->insert (make_pair (n, v));
    56. }
    57. }
    58. fclose (f);
    59. }
    60. }
    61. // write cache file
    62. void write (const char *pFilename)
    63. {
    64. // save cache only if something was changed
    65. if (m_bAltered)
    66. {
    67. FILE* f = fopen (pFilename, "wb");
    68. if (f == NULL)
    69. {
    70. fprintf (stderr, "Failed to open cache file %s for writing\n", pFilename);
    71. return;
    72. }
    73. for (const_iterator cit = begin (); cit != end (); ++cit)
    74. {
    75. const int m = (*cit).first;
    76. innercont_t* pCont = (*cit).second;
    77. const unsigned long nSize = pCont->size ();
    78. fwrite (&m, sizeof (int), 1, f);
    79. fwrite (&nSize, sizeof (unsigned long), 1, f);
    80. for (innercont_t::const_iterator cit2 = pCont->begin (); cit2 != pCont->end (); ++cit2)
    81. {
    82. const int n = (*cit2).first;
    83. const float v = (*cit2).second;
    84. fwrite (&n, sizeof (int), 1, f);
    85. fwrite (&v, sizeof (float), 1, f);
    86. }
    87. }
    88. fclose (f);
    89. }
    90. }
    91. // returns INVALID_CACHE_VALUE if not found
    92. float getCachedValue (const int m, const int n)
    93. {
    94. // is m contained?
    95. const_iterator cit = find (m);
    96. if (cit != end ())
    97. {
    98. // yes -> is n contained?
    99. innercont_t* pCont = (*cit).second;
    100. innercont_t::const_iterator cit2 = pCont->find (n);
    101. if (cit2 != pCont->end ())
    102. {
    103. ++m_nHits;
    104. return (*cit2).second;
    105. }
    106. }
    107. ++m_nMisses;
    108. return INVALID_CACHE_VALUE;
    109. }
    110. void addToCache (const int m, const int n, const float aValue)
    111. {
    112. // get container mapping of m
    113. innercont_t* pCont;
    114. const_iterator cit = find (m);
    115. if (cit != end ())
    116. pCont = (*cit).second;
    117. else
    118. {
    119. pCont = new innercont_t ();
    120. insert (make_pair (m, pCont));
    121. }
    122. // add to inner cont
    123. pCont->insert (make_pair (n, aValue));
    124. m_bAltered = true;
    125. }
    126. unsigned long getHits () const
    127. {
    128. return m_nHits;
    129. }
    130. unsigned long getMisses () const
    131. {
    132. return m_nMisses;
    133. }
    134. };
    135. // global variables for the cache
    136. Cache g_aCacheZeta0, g_aCacheZeta1;
    137. float zeta_0(const int m, const int n)
    138. {
    139. // check at the beginning - faster than cache lookup
    140. if (m == 0 || n == 0)
    141. return 0;
    142. // query cache
    143. float ret = g_aCacheZeta0.getCachedValue (m, n);
    144. if (ret == INVALID_CACHE_VALUE)
    145. {
    146. // calculate
    147. const float epsilon=1;
    148. const float delta=6;
    149. const float epsilonmn = epsilon * m * n;
    150. const float deltan = delta * n;
    151. ret = 1+((deltan*zeta_0(m,n-1)+epsilonmn*zeta_0(m-1,n+1))/(deltan+epsilonmn));
    152. // add to cache
    153. g_aCacheZeta0.addToCache (m, n, ret);
    154. }
    155. return ret;
    156. }
    157. float zeta_1 (const int m, const int n)
    158. {
    159. // check at the beginning - faster than cache lookup
    160. if(m == 0 || n == 0)
    161. return 0;
    162. // query cache
    163. float ret = g_aCacheZeta1.getCachedValue (m, n);
    164. if (ret == INVALID_CACHE_VALUE)
    165. {
    166. // calculate
    167. const float M=6;
    168. const float rho=6;
    169. const float Mn = M * n;
    170. const float mn = m * n;
    171. ret = ((M/rho)+Mn+mn+M*zeta_0(m+1,n)+Mn*zeta_1(m,n-1)+mn*zeta_1(m-1,n+1)-M*zeta_0(m,n))/(Mn+mn);
    172. // add to cache
    173. g_aCacheZeta1.addToCache (m, n, ret);
    174. }
    175. return ret;
    176. }
    177. int main()
    178. {
    179. printf ("Reading cache\n");
    180. g_aCacheZeta0.read ("zeta0");
    181. g_aCacheZeta1.read ("zeta1");
    182. printf ("Calculating\n");
    183. int m = 1000;
    184. int n = 1000;
    185. printf("%f\n",zeta_0(m,n));
    186. printf("%f\n",zeta_1(m,n));
    187. // print cache stats
    188. printf ("Cache hits zeta_0: %lu\n", g_aCacheZeta0.getHits ());
    189. printf ("Cache misses zeta_0: %lu\n", g_aCacheZeta0.getMisses ());
    190. printf ("Cache hits zeta_1: %lu\n", g_aCacheZeta1.getHits ());
    191. printf ("Cache misses zeta_1: %lu\n", g_aCacheZeta1.getMisses ());
    192. printf ("Writing cache\n");
    193. g_aCacheZeta0.write ("zeta0");
    194. g_aCacheZeta1.write ("zeta1");
    195. printf ("Cleaning up\n");
    196. return 0;
    197. }
    Alles anzeigen


    Mehr fällt mir diesbzgl. nicht ein.
    Viel Spaß :)