2008年5月30日金曜日

FizzBuzz Questions

思いつきでFizzBuzz Questionsをやってみる。お題はこちら:

Write a program that prints the numbers from 1 to 100. But for multiples of three print "Fizz" instead of the number and for the multiples of five print "Buzz". For numbers which are multiples of both three and five print "FizzBuzz".


普通に解くと
#include <iostream>
using namespace std;

void FizzBuzz( int n ){
if( n % 15 )
if( n % 5 )
if( n % 3 )
cout << n;
else
cout << "Fizz";
else
cout << "Buzz";
else
cout << "FizzBuzz";
cout << endl;
}

int main(){
for( int i = 1; i < 101; i++ )
FizzBuzz( i );
}
こんな感じ?

当たり前ですが実行時に分岐しています。でもTMP(Template MetaProgramming)を使えばコンパイル時に分岐できます。
#include <iostream>
using namespace std;

template<int n, int mod3 = n % 3, int mod5 = n % 5>
struct FizzBuzz{
static ostream& print(){
return FizzBuzz<n-1>::print() << n << endl;
}
};

template<int n, int mod5>
struct FizzBuzz<n, 0, mod5>{
static ostream& print(){
return FizzBuzz<n-1>::print() << "Fizz" << endl;
}
};

template<int n, int mod3>
struct FizzBuzz<n, mod3, 0>{
static ostream& print(){
return FizzBuzz<n-1>::print() << "Buzz" < endl;
}
};

template<int n>
struct FizzBuzz<n, 0, 0>{
static ostream& print(){
return FizzBuzz<n-1>::print() << "FizzBuzz" << endl;
}
};

template<> ostream& FizzBuzz<0>::print(){
return cout;
}

int main(){
FizzBuzz<100>::print();
}
本当はループ展開とかもTMPでできるかも…でもやり方がよくわかりませんでした。

しかし更にすごい方法が…
#include <iostream>
#include <boost/preprocessor/arithmetic/mod.hpp>
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
using namespace std;

#define FizzBuzz( z, n, data ) \
BOOST_PP_IF( BOOST_PP_MOD( n, 15 ), \
BOOST_PP_IF( BOOST_PP_MOD( n, 5 ), \
BOOST_PP_IF( BOOST_PP_MOD( n, 3 ), \
#n, \
"Fizz" ), \
"Buzz" ), \
"FizzBuzz" ) \
"\n"

int main(){
cout << BOOST_PP_REPEAT_FROM_TO( 1, 101, FizzBuzz, );
}
コンパイル前にすべての処理を終わらせてしまい、preprocessorだけで単一の文字列を作り上げてしまうことも。いやはや。

0 件のコメント: