Skip to content

Fastest FizzBuzz

The always-entertaining FizzBuzz problem came up again on Hacker News today, and for no other reason than I just got out from under a nasty deadline, I looked around on the net for interesting solutions, for which this Rosetta Code page is a gold mine. The Windows batch file and BSD make versions are hilarious, though I was a bit disappointed that Piet was not represented. Anyhow, here it is: (reference)

Another wonderful FizzBuzz solution uses template metaprogramming to evaluate the solution at compile time. I was disappointed, however, to look at the code emitted by Clang++, G++, and Intel’s C++ compiler, which all generate a large amount of crap instead of boiling the program down to its essence: emitting a single string.

I also noticed that various sites that discuss the efficiency of FizzBuzz implementations, such as this one, failed to provide what I would consider the most efficient code:

#include <stdio.h>

int main (void)
{
  puts("1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n11\nFizz\n13\n14\nFizzBuzz\n16\n17\nFizz\n19\nBuzz\nFizz\n22\n23\nFizz\nBuzz\n26\nFizz\n28\n29\nFizzBuzz\n31\n32\nFizz\n34\nBuzz\nFizz\n37\n38\nFizz\nBuzz\n41\nFizz\n43\n44\nFizzBuzz\n46\n47\nFizz\n49\nBuzz\nFizz\n52\n53\nFizz\nBuzz\n56\nFizz\n58\n59\nFizzBuzz\n61\n62\nFizz\n64\nBuzz\nFizz\n67\n68\nFizz\nBuzz\n71\nFizz\n73\n74\nFizzBuzz\n76\n77\nFizz\n79\nBuzz\nFizz\n82\n83\nFizz\nBuzz\n86\nFizz\n88\n89\nFizzBuzz\n91\n92\nFizz\n94\nBuzz\nFizz\n97\n98\nFizz\nBuzz");
  return 0;
}

It would perhaps be better style to use printf() instead of puts(), counting on the compiler to optimize the former to the latter, but the version of GCC that I use does not actually do that.

Using my timing code on a random Nehalem 64-bit Linux machine I get:

g++ -O3: 125,000 cycles

Intel C++ -fast: 103,000 cycles

Clang++ -O3: 103,000 cycles

gcc -O3: 29,000 cycles

gcc -O3 -static: 21,000 cycles

Here’s the C code and C++ code. For benchmarking purposes I piped their STDOUT to /dev/null.

{ 8 } Comments

  1. pdw | November 15, 2012 at 4:22 pm | Permalink

    You should call write(2) directly, you don’t want to pay the cost of stdio’s buffering.

  2. Robby | November 15, 2012 at 5:53 pm | Permalink

    Someone should add an optimization that detects if stdout is going to /dev/null and then just not do anything. I bet you can finish that in less than 21,000 cycles.

    PS: Benchmarks suck.

  3. Eitan | November 15, 2012 at 6:11 pm | Permalink

    Robby, I wonder if the system call + branch to figure that out would be fast enough to be worth the optimization?

  4. Johannes | November 15, 2012 at 11:52 pm | Permalink

    It’s not a DOS batch file, though. I went through all of Rosetta code a few years ago changing the name of the language, because all but two examples were using Windows features anyway.

  5. Jeroen Mostert | November 16, 2012 at 4:48 am | Permalink

    Obviously we’re I/O-bound. The solution is to convince management to buy a faster console.

  6. regehr | November 16, 2012 at 7:07 am | Permalink

    Hi pdw, I considered that but figured portable C was better.

    Robby, given how UNIX redirection works, is it even possible for the process to tell whether its stdout is hooked to /dev/null? I’m not sure it is, at least portably.

  7. Geoff | November 23, 2012 at 1:12 am | Permalink

    Redirection itself doesn’t pose any difficulty: there’s still a file underlying a redirected descriptor, and you can just look to see whether that’s the same file underlying /dev/null:

    struct stat stdout_stat;
    struct stat devnull_stat;

    if (fstat(STDOUT_FILENO, &stdout_stat) < 0)
    err(2, "failed fstat");

    if (stat("/dev/null", &devnull_stat) /dev/null should do the job.

  8. Geoff | November 23, 2012 at 11:11 pm | Permalink

    *sigh* Well, that’s what I get for assuming that the comment box uses markdown.

    The code just compares inode numbers. I also point that you can defeat such trickery easily enough by piping through cat – although that comes with a performance hit.