According to your specific needs, which seems to be more syntax and not performance related:
While loop:
Clear[a, n]
n = 1; a = 1;
While[n <= 20, Print[a = a*fib[n]]; n++]
For loop:
Clear[a, n]
For[n = 1; a = 1, n <= 20, n++, Print[a = a*fib[n]]]
I guess you know that there are other ways for compute Fibonacci.
Roman Maeder's book, for instance, Computer Science with Mathematia or
Michael Trott's Guidebook to Programming in Mathematica.
Edit: Approaches to calculate product of Fibonacci Numbers:
Times @@ Array[Fibonacci, 20]
Times @@ Fibonacci[Range@20]
a = 0; Times @@ NestWhileList[a + # &, 1, (a = #1) < Fibonacci@19 &, 2]
fibProduct[n_Integer?Positive] :=
Module[{f1 = 1, f2 = 0, res = 1},
Do[{f1, f2} = {f1 + f2, f1}; res *= f1, {n - 1}];
res]
fibProduct[n_Integer?NonPositive] := Times @@ ((-1)^(n - 1) Fibonacci[Range@-n])
Edit 2: the not for the faint of heart approach:
The .tm file:
:Begin:
:Function: fibProduct
:Pattern: FibProduct[n_]
:Arguments: { n }
:ArgumentTypes: { Integer }
:ReturnType: Integer
:End:
The .cpp file:
#include <algorithm>
#include <iostream>
#include <numeric>
#include <iterator>
#include <vector>
using namespace std;
template<class F, class X, class S>
X foldl( F && f, X x, const S & s)
{
return std::accumulate(std::begin(s), std::end(s), std::move(x), std::forward<F>(f));
}
unsigned long long fibProduct( int n )
{
std::function<int(int)> fibonacci = [&fibonacci](int n) -> int { return (n < 2) ?
n : fibonacci(n - 1) + fibonacci(n - 2); };
vector<int> vec(n);
int i = 0;
generate( begin(vec), end(vec), [&i, &fibonacci]() { return fibonacci(i += 1); } );
return foldl( std::multiplies<int>(), 1, vec );
}
Attention: Don't use n > 10....
Edit 3: the not for the faint of memoized heart approach:
Add these includes:
#include <unordered_map>
#include <map>
Change this in .cpp file:
template <typename ReturnType, typename... Args>
std::function<ReturnType (Args...)>
memoize(ReturnType (*func) (Args...))
{
auto cache = std::make_shared<std::map<std::tuple<Args...>, ReturnType>>();
return ([=](Args... args) mutable {
std::tuple<Args...> t(args...);
if (cache->find(t) == cache->end())
(*cache)[t] = func(args...);
return (*cache)[t];
});
}
template <typename F_ret, typename... F_args>
std::function<F_ret (F_args...)> memoized_recursion(F_ret (*func)(F_args...))
{
typedef std::function<F_ret (F_args...)> FunctionType;
static std::unordered_map<decltype(func), FunctionType> functor_map;
if(functor_map.find(func) == functor_map.end())
functor_map[func] = memoize(func);
return functor_map[func];
}
unsigned long fibonacci(unsigned n)
{
return (n < 2) ? n :
memoized_recursion(fibonacci)(n - 1) +
memoized_recursion(fibonacci)(n - 2);
}
unsigned long long fibProduct( int n )
{
vector<int> vec(n);
int i = 0;
generate( begin(vec), end(vec), [&i]() { return fibonacci(i += 1); } );
return foldl( std::multiplies<int>(), 1, vec );
}
The rest is just proper compilation, linking and link installation in Mathematica...
Btw. you've to link explicitly against libstdc++.6.0.9.dylib (or another version number), since there is all the basic_string code etc. (MacOSX)
Addendum:
Has someone dealt so far, presumably yes, with big Integer issues with MathLink?
Any tips for me?
Edit 4: the not for the faint of memoized heart MultiPrecision approach:
The .tm file:
:Begin:
:Function: fibProductMP
:Pattern: FibProductMP[n_]
:Arguments: { n }
:ArgumentTypes: { Integer }
:ReturnType: Manual
:End:
The .cpp file:
Add this include:
#include <boost/multiprecision/integer.hpp>
Maybe, if you'd like to avoid long namespace names:
using boost::multiprecision::cpp_int;
template<typename T>
inline T Identity(const std::multiplies<T>&) { return T(1); }
void fibProductMP( int n )
{
vector<int> vec(n);
int i = 0;
generate( begin(vec), end(vec), [&i]() { return fibonacci(i += 1); } );
cpp_int result = foldl( std::multiplies<cpp_int>(), Identity<cpp_int
(multiplies<cpp_int>()), vec );
MLNewPacket(stdlink);
MLPutString(stdlink, result.str().c_str() );
}
Mathematica side:
link = Install["wherever the binary is", LinkMode -> Launch];
FibProductMP[30]
(* 607373569868916007005878071331449502263924414704952629297115029592606\
043656028160000000 *)
What we've achieved is a multiprecision FibProduct function which is cool, decent C++11 code, exception safe and memoized. Now I'd be tempted to say victory!
P.S.: My life wouldn't be what it is, if there would not still exist one caveat.
I return the result as a const char*; so a ToExpression is needed to reuse the result for further calculations.
Just can't get enough (until 47 ;) ... Gosh...could solve that as well, but I've to say, enough is enough :)
FibProductMP[#] & /@ Range[47] // TableForm

That was real fun...
Thank you.
Printdoes. It prints the results to a new line, but doesn't actually return it. If you removePrintand run either of your examples, the result will be stored inaat the end of the loop. – jVincent Feb 15 at 10:26