
Hi, as a casual/newbie boost-user I'm trying to come to grips with why/when nested functional composition with boost::bind might be of help - following Karlsson's book, in its fifth printing. ---------------------- 1) It seems that he suggests, that if one is into doing something like T faa(int); T foo(const& T); int i; vector<T> v(10); // container for(i=0; i<10; i++) { v[i] = faa(i); // set it v[i] = foo(v[i]); // operate on it } then instead of the 'old style' for-loops it would be more desirable to use 'STL style' algorithms with the functors created from boost::bind, say like transform(v.begin(),v.end(),boost::bind(&foo,_1)); instead of the 2nd line in the previous for-loop, a.s.o. ---------------------- 2) Then, it is suggested furthermore that if foo() is a (simple?) nested function, say T=double and, double foo(double x) { return 2*x; } then one should do 'functional composition', i.e. create the functor for the previous point 1) by boost::bind(std::multiplies<double>(),2,_1) (Karlsson has this example on adding and subtracting 10%.) ----------------------- Now, my question is, if such nested construction of functors at the call site, which is suggested also in the 'Bind Summary' in Karlsson's book, will actually lead to code which has no relevant performance loss as compared to 'old-style' for-loops? To check this, I do something rather simple (simplistic?). Namely, I take a vector of some size, then I fill it with random doubles between 0 and M_PI, then (stupid me) I test if sin(v[i])^2 + cos([i])^2 = 1 for each element of the vector. The code is attached. I do this many many times and measure the runtime. I do this for two cases: case 1: with old-style for loops case 3: with STL algorithms and boost::bind At least for this little program, the old-style code is faster by roughly a factor of 2 as compared to the boost::bind approach. (compiled with gcc version 4.3.2 and optimized) Case 2 just to show that this is not due to more sin()/cos() function calls within the nested functor, since it is also a factor of 2 faster than then the boost variant. So, in conclusion: when/how should I really use functional composition? wb --------------------------------- #include <iostream> #include <vector> #include <math.h> #include <algorithm> #include "boost/lambda/bind.hpp" #include <assert.h> #include <time.h> using namespace std; using namespace boost; using namespace boost::lambda; int main() { int in; unsigned n(1000),i,l; double x,y,t; vector<double> v(n); clock_t start, stop; cin >> in; // tell me which case to check switch(in) { case 0: // Check how much time is lost in loops and math // --------------------------------------------------------------------------- t = 0.0; assert((start = clock())!=-1); for(l=0;l<10000;l++) { for(i=0;i<n;i++) { x= (random()*M_PI)/RAND_MAX; x = sin(v[i]); x = x*x; y = cos(v[i]); y = y*y; x = x + y; } } stop = clock(); t = (double) (stop-start)/CLOCKS_PER_SEC; cout << t << endl; break; case 1: // Time for old-style for-loops // --------------------------------------------------------------------------- t = 0.0; assert((start = clock())!=-1); for(l=0;l<10000;l++) { for(i=0;i<n;i++) { v[i] = (random()*M_PI)/RAND_MAX; x = sin(v[i]); x = x*x; y = cos(v[i]); y = y*y; v[i] = x + y; } } stop = clock(); t = (double) (stop-start)/CLOCKS_PER_SEC; cout << t << endl; break; case 2: // Time for old-style for-loops and unnecessarily many sin/cos calls // --------------------------------------------------------------------------- t = 0.0; assert((start = clock())!=-1); for(l=0;l<10000;l++) { for(i=0;i<n;i++) { v[i] = (random()*M_PI)/RAND_MAX; v[i] = sin(v[i])*sin(v[i])+cos(v[i])*cos(v[i]); } } stop = clock(); t = (double) (stop-start)/CLOCKS_PER_SEC; cout << t << endl; break; case 3: // Time needed with nested boost::bind and STL iteration over container // --------------------------------------------------------------------------- t = 0.0; assert((start = clock())!=-1); for(l=0;l<10000;l++) { generate(v.begin(),v.end(), bind(multiplies<double>(), bind(&random), M_PI/RAND_MAX)); transform(v.begin(),v.end(),v.begin(), bind(plus<double>(), bind(multiplies<double>(),bind(sin,_1),bind(sin,_1)), bind(multiplies<double>(),bind(cos,_1),bind(cos,_1)) ) ); } stop = clock(); t = (double) (stop-start)/CLOCKS_PER_SEC; cout << t << endl; break; } return EXIT_SUCCESS; }