Part Eight - Euler 44 Nested Recursion: Classes

Nested C++ Recursion - Introduction (Main Article Page)

Part Seven - Euler 44 Nested Recursion: Vectors described a vector-based nested C++ recursive solution to the Euler 44 Pentagonal Numbers problem. Part Eight here will explain how C++ classes can increase recursion engineering efficiency.

We might want to break out the gen_pentnum() and is_pentnum() functions into one class, in a separate file. This would increase the solution file flexibility, and make the engineering more modular. The next example shows how to do it. File pentnum_functions.cpp, available in this resource, builds a class called pentnum_functions:


 1.   #include "stdafx.h"
 2.   #include "pentnum_functions.h"
 3.   #include <chrono>
 4.   #include <ctime>
 5.   #include <iostream>
 6.   #include <functional>
 7.   #include <math.h>
 8.   #include <vector>
 9.   
10.   pentnum_functions::pentnum_functions()
11.   {
12.   }
13.
14.   bool pentnum_functions::is_pentnum(int x) {
15.
16.      float testval = (float)(sqrt(24.0f*(float)(x)+1.0f) + 1.0f) / 6.0f;
17.      return (((testval - trunc(testval)) == 0.0) ? true : false);
18.   };
19.
20.   int pentnum_functions::gen_pentnum(int n) {
21.      return (int)(((3 * pow((float)n, 2)) - (float)n) / 2);
22.   }


The Euler_44_lambdas.cpp file hosts the main() function:

 1.   #include "stdafx.h"
 2.   #include "pentnum_functions.h"
 3.   #include <chrono>
 4.   #include <ctime>
 5.   #include <iostream>
 6.   #include <functional>
 7.   #include <math.h>
 8.   #include <vector>
 9.   
10.   int main() {
11.
12.      pentnum_functions pfObj;
13.      
14.      std::function<bool (int[])> innerRecLambda;
15.      innerRecLambda = [&innerRecLambda, &pfObj](int x[]) {
16.      
17.         bool inner_is_sum_pentnum = pfObj.is_pentnum(pfObj.gen_pentnum(x[1]) + pfObj.gen_pentnum(x[0]));
18.         bool inner_is_diff_pentnum = pfObj.is_pentnum(pfObj.gen_pentnum(x[1]) - pfObj.gen_pentnum(x[0]));
19.      
20.         if ((x[0] > 1) && !(inner_is_sum_pentnum && inner_is_diff_pentnum)) {
21.      
22.            x[0]--;
23.      
24.            return innerRecLambda(x);
25.         } else if ((x[0] == 1) && !(inner_is_sum_pentnum && inner_is_diff_pentnum)) {
26.      
27.            return false;
28.         } else {
29.      
30.            return true;
31.         }
32.      };
33.      
34.      std::function<int* (int[])> outerRecLambda;
35.      outerRecLambda = [&outerRecLambda, &innerRecLambda, &pfObj](int x[]) {
36.      

37.         bool outer_is_sum_pentnum = pfObj.is_pentnum(pfObj.gen_pentnum(x[1]) + pfObj.gen_pentnum(x[0]));

38.         bool outer_is_diff_pentnum = pfObj.is_pentnum(pfObj.gen_pentnum(x[1]) - pfObj.gen_pentnum(x[0]));

39.      
40.         if (!(outer_is_sum_pentnum) || !(outer_is_diff_pentnum)) {
41.      
42.            x[0] = x[1] - 1;
43.      
44.            if (!(innerRecLambda(x))) {
45.      
46.               x[0] = x[1];
47.               x[1]++;
48.      
49.               return outerRecLambda(x);
50.            } else {
51.      
52.               return (x);
53.            }
54.         } else {
55.      
56.            return (x);
57.         }
58.      };
59.      
60.      int startValues[2] = { 1, 2 };
61.      int* finishedValues;
62.      
63.      auto startTime = std::chrono::high_resolution_clock::now();
64.      
65.      finishedValues = outerRecLambda(startValues);
66.      
67.      auto endTime = std::chrono::high_resolution_clock::now();
68.      std::chrono::duration timeDifference = endTime - startTime;
69.      
70.      std::cout << "\n\tThe calculated x[] array values --> pentagonal numbers: " << "\n\n";

71.      std::cout << "\tx[1] = " << finishedValues[1] << " --> gen_pentnum(x[1]) = gen_pentnum(" << finishedValues[1] << ") = " << pfObj.gen_pentnum(finishedValues[1]) << "\n";

72.      std::cout << "\tx[0] = " << finishedValues[0] << " --> gen_pentnum(x[0]) = gen_pentnum(" << finishedValues[0] << ") = " << pfObj.gen_pentnum(finishedValues[0]) << "\n\n";

73.      std::cout << "\t\t\tgen_pentnum(x[1]) + gen_pentnum(x[0]) = " << pfObj.gen_pentnum(finishedValues[1]) + pfObj.gen_pentnum(finishedValues[0]) << "\n";

74.      std::cout << "\t\t\tgen_pentnum(" << finishedValues[1] << ") + gen_pentnum(" << finishedValues[0] << ") = " << pfObj.gen_pentnum(finishedValues[1]) + pfObj.gen_pentnum(finishedValues[0]) << "\n\n";

75.
76.      std::cout << std::boolalpha;
77.      
78.      std::cout << "\t\t\t" << pfObj.gen_pentnum(finishedValues[1]) + pfObj.gen_pentnum(finishedValues[0]) << " is a pentagonal number: " << pfObj.is_pentnum(pfObj.gen_pentnum(finishedValues[1]) + pfObj.gen_pentnum(finishedValues[0])) << "\n\n";

79.      std::cout << "\t______________________________________________\n";
80.      std::cout << "\t______________________________________________\n\n\n";

81.      std::cout << "\tx[1] = " << finishedValues[1] << " --> gen_pentnum(x[1]) = gen_pentnum(" << finishedValues[1] << ") = " << pfObj.gen_pentnum(finishedValues[1]) << "\n";

82.      std::cout << "\tx[0] = " << finishedValues[0] << " --> gen_pentnum(x[0]) = gen_pentnum(" << finishedValues[0] << ") = " << pfObj.gen_pentnum(finishedValues[0]) << "\n\n";

83.      std::cout << "\t\t\tgen_pentnum(x[1]) - gen_pentnum(x[0]) = " << pfObj.gen_pentnum(finishedValues[1]) - pfObj.gen_pentnum(finishedValues[0]) << "\n";

84.      std::cout << "\t\t\tgen_pentnum(" << finishedValues[1] << ") - gen_pentnum(" << finishedValues[0] << ") = " << pfObj.gen_pentnum(finishedValues[1]) - pfObj.gen_pentnum(finishedValues[0]) << "\n\n";

85.      std::cout << "\t\t\t" << pfObj.gen_pentnum(finishedValues[1]) - pfObj.gen_pentnum(finishedValues[0]) << " is a pentagonal number: " << pfObj.is_pentnum(pfObj.gen_pentnum(finishedValues[1]) - pfObj.gen_pentnum(finishedValues[0])) << "\n\n";
86.      
87.      std::cout << "\n\t\t\tCalculation Time = " << timeDifference.count() << " seconds\n\n";
88.   
89.      system("pause");
90.}


For this to work, first add the pentnum_functions files to the project, as seen here:


At line 2, Euler_44_lambdas.cpp becomes aware of the pentnum_functions class through the include at line 2. Line 12 declares object pfObj of class pentnum_functions. To use the pfObj object functions, the lambdas need to “see” that object. Lambda closures make this possible. Add the &pbObj reference parameters to the lambda closures at lines 15 and 35. To use pfObj object functions in the lambdas, add “pfObj” to the front of the object function calls, as seen in this example from line 17:

17.   bool inner_is_sum_pentnum = pfObj.is_pentnum(pfObj.gen_pentnum(x[1]) + pfObj.gen_pentnum(x[0]));

Lines 18, 37, and 38 use similar code. With closures, we can easily add new classes to the lambdas we build.

Here, we saw that classes can boost C++ recursion efficiency. Part Nine - Memory Consumption will show how to measure recursive C++ software memory consumption, focusing on the C++ software described in this article.