C++: FizzBuzz

Bjarne-stroustrup
 


Write a program that prints the integers 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”.

FizzBuzz was presented as the lowest level of comprehension required to illustrate adequacy.

#include <iostream>

using namespace std;
int main ()
{
	for (int i = 1; i <= 100; i++) 
	{
		if ((i % 15) == 0)
		cout << "FizzBuzz\n";
		else if ((i % 3) == 0)
		cout << "Fizz\n";
		else if ((i % 5) == 0)
		cout << "Buzz\n";
		else
		cout << i << "\n";
	}
	return 0;
}

Alternate version not using modulo 15:

#include <iostream>
using namespace std;

int main()
{
	for (int i = 0; i <= 100; ++i)
	{
		bool fizz = (i % 3) == 0;
		bool buzz = (i % 5) == 0;
		if (fizz)
		cout << "Fizz";
		if (buzz)
		cout << "Buzz";
		if (!fizz && !buzz)
		cout << i;
		cout << "\n";
	}
	return 0;
}

Alternate version that avoids using modulo. (Modulo can be expensive on some architectures.)

#include <iostream>

int main()
{
	int i, f = 2, b = 4; 

	for ( i = 1 ; i <= 100 ; ++i, --f, --b )
	{
		if ( f && b ) { std::cout << i;             }
		if ( !f )     { std::cout << "Fizz"; f = 3; }
		if ( !b )     { std::cout << "Buzz"; b = 5; }
		std::cout << std::endl;
	}

	return 0;
}

A version using std::transform:

Works with: C++11

#include <iostream>                                                                                                     
#include <algorithm>
#include <vector>

int main()
{
	std::vector<int> range(100);
	std::iota(range.begin(), range.end(), 1);

	std::vector<std::string> values;
	values.resize(range.size());

	auto fizzbuzz = [](int i) -> std::string {
		if ((i%15) == 0) return "FizzBuzz";
		if ((i%5) == 0)  return "Buzz";
		if ((i%3) == 0)  return "Fizz";
		return std::to_string(i);
	};

	std::transform(range.begin(), range.end(), values.begin(), fizzbuzz);

	for (auto& str: values) std::cout << str << std::endl;

	return 0;
}

Version computing FizzBuzz at compile time with metaprogramming:

#include <iostream>
 
template <int n, int m3, int m5> 
struct fizzbuzz : fizzbuzz<n-1, (n-1)%3, (n-1)%5>
{
  fizzbuzz() 
  { std::cout << n << std::endl; }
};
 
template <int n>
struct fizzbuzz<n, 0, 0> : fizzbuzz<n-1, (n-1)%3, (n-1)%5>
{
  fizzbuzz() 
  { std::cout << "FizzBuzz" << std::endl; }
};
 
template <int n, int p>
struct fizzbuzz<n, 0, p> : fizzbuzz<n-1, (n-1)%3, (n-1)%5>
{
  fizzbuzz() 
  { std::cout << "Fizz" << std::endl; }
};
 
template <int n, int p>
struct fizzbuzz<n, p, 0> : fizzbuzz<n-1, (n-1)%3, (n-1)%5>
{
  fizzbuzz() 
  { std::cout << "Buzz" << std::endl; }
};
 
template <>
struct fizzbuzz<0,0,0>
{
  fizzbuzz() 
  { std::cout << 0 << std::endl; }
};
 
template <int n>
struct fb_run
{
  fizzbuzz<n, n%3, n%5> fb;
};
 
int main()
{
  fb_run<100> fb;
  return 0;
}

Hardcore templates (compile with -ftemplate-depth-9000 -std=c++0x):

#include <iostream>
#include <string>
#include <cstdlib>
#include <boost/mpl/string.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/size_t.hpp>

using namespace std;
using namespace boost;

///////////////////////////////////////////////////////////////////////////////
// exponentiation calculations
template <int accum, int base, int exp> struct POWER_CORE : POWER_CORE<accum * base, base, exp - 1>{};

template <int accum, int base>
struct POWER_CORE<accum, base, 0>
{
	enum : int { val = accum };
};

template <int base, int exp> struct POWER : POWER_CORE<1, base, exp>{};

///////////////////////////////////////////////////////////////////////////////
// # of digit calculations
template <int depth, unsigned int i> struct NUM_DIGITS_CORE : NUM_DIGITS_CORE<depth + 1, i / 10>{};

template <int depth>
struct NUM_DIGITS_CORE<depth, 0>
{
	enum : int { val = depth};
};

template <int i> struct NUM_DIGITS : NUM_DIGITS_CORE<0, i>{};

template <>
struct NUM_DIGITS<0>
{
	enum : int { val = 1 };
};

///////////////////////////////////////////////////////////////////////////////
// Convert digit to character (1 -> '1')
template <int i>
struct DIGIT_TO_CHAR
{
	enum : char{ val = i + 48 };
};

///////////////////////////////////////////////////////////////////////////////
// Find the digit at a given offset into a number of the form 0000000017
template <unsigned int i, int place> // place -> [0 .. 10]
struct DIGIT_AT
{
	enum : char{ val = (i / POWER<10, place>::val) % 10 };
};

struct NULL_CHAR
{
	enum : char{ val = '\0' };
};

///////////////////////////////////////////////////////////////////////////////
// Convert the digit at a given offset into a number of the form '0000000017' to a character
template <unsigned int i, int place> // place -> [0 .. 9]
struct ALT_CHAR : DIGIT_TO_CHAR< DIGIT_AT<i, place>::val >{};

///////////////////////////////////////////////////////////////////////////////
// Convert the digit at a given offset into a number of the form '17' to a character

// Template description, with specialization to generate null characters for out of range offsets
template <unsigned int i, int offset, int numDigits, bool inRange>  
struct OFFSET_CHAR_CORE_CHECKED{};
template <unsigned int i, int offset, int numDigits>                
struct OFFSET_CHAR_CORE_CHECKED<i, offset, numDigits, false> : NULL_CHAR{};
template <unsigned int i, int offset, int numDigits>                
struct OFFSET_CHAR_CORE_CHECKED<i, offset, numDigits, true>  : ALT_CHAR<i, (numDigits - offset) - 1 >{};

// Perform the range check and pass it on
template <unsigned int i, int offset, int numDigits>
struct OFFSET_CHAR_CORE : OFFSET_CHAR_CORE_CHECKED<i, offset, numDigits, offset < numDigits>{};

// Calc the number of digits and pass it on
template <unsigned int i, int offset>
struct OFFSET_CHAR : OFFSET_CHAR_CORE<i, offset, NUM_DIGITS<i>::val>{};

///////////////////////////////////////////////////////////////////////////////
// Integer to char* template. Works on unsigned ints.
template <unsigned int i>
struct IntToStr
{
	const static char str[];
	typedef typename mpl::string<
	OFFSET_CHAR<i, 0>::val,
	OFFSET_CHAR<i, 1>::val,
	OFFSET_CHAR<i, 2>::val,
	OFFSET_CHAR<i, 3>::val,
	OFFSET_CHAR<i, 4>::val,
	OFFSET_CHAR<i, 5>::val,
	/*OFFSET_CHAR<i, 6>::val,
	OFFSET_CHAR<i, 7>::val,
	OFFSET_CHAR<i, 8>::val,
	OFFSET_CHAR<i, 9>::val,*/
	NULL_CHAR::val>::type type;
};

template <unsigned int i>
const char IntToStr<i>::str[] = 
{
	OFFSET_CHAR<i, 0>::val,
	OFFSET_CHAR<i, 1>::val,
	OFFSET_CHAR<i, 2>::val,
	OFFSET_CHAR<i, 3>::val,
	OFFSET_CHAR<i, 4>::val,
	OFFSET_CHAR<i, 5>::val,
	OFFSET_CHAR<i, 6>::val,
	OFFSET_CHAR<i, 7>::val,
	OFFSET_CHAR<i, 8>::val,
	OFFSET_CHAR<i, 9>::val,
	NULL_CHAR::val
};

template <bool condition, class Then, class Else>
struct IF
{
	typedef Then RET;
};

template <class Then, class Else>
struct IF<false, Then, Else>
{
	typedef Else RET;
};


template < typename Str1, typename Str2 >
struct concat : mpl::insert_range<Str1, typename mpl::end<Str1>::type, Str2> {};
template <typename Str1, typename Str2, typename Str3 >
struct concat3 : mpl::insert_range<Str1, typename mpl::end<Str1>::type, typename concat<Str2, Str3 >::type > {};

typedef typename mpl::string<'f','i','z','z'>::type fizz;
typedef typename mpl::string<'b','u','z','z'>::type buzz;
typedef typename mpl::string<'\r', '\n'>::type mpendl;
typedef typename concat<fizz, buzz>::type fizzbuzz;

// discovered boost mpl limitation on some length

template <int N>
struct FizzBuzz
{
	typedef typename concat3<typename FizzBuzz<N - 1>::type, typename IF<N % 15 == 0, typename fizzbuzz::type, typename IF<N % 3 == 0, typename fizz::type, typename IF<N % 5 == 0, typename buzz::type, typename IntToStr<N>::type >::RET >::RET >::RET, typename mpendl::type>::type type;
};

template <>
struct FizzBuzz<1>
{
	typedef mpl::string<'1','\r','\n'>::type type;
};

int main(int argc, char** argv)
{
	const int n = 7;
	std::cout << mpl::c_str<FizzBuzz<n>::type>::value << std::endl;
	return 0;
}

Note: it takes up lots of memory and takes several seconds to compile. To enable compilation for 7 < n <= 25, please, modify include/boost/mpl/limits/string.hpp BOOST_MPL_LIMIT_STRING_SIZE to 128 instead of 32).

SOURCE

Content is available under GNU Free Documentation License 1.2.