Euler’s Fizzbuzz

FizzBuzz is a common coding problem of the sort asked in technical screenings or interviews. It goes something like this:

Write a function to list the integers from 1 to 100, but for every multiple of 3, write “Fizz”, and for every multiple of 5, write “Buzz”. For numbers which are multiples of both 3 and 5, it should write “FizzBuzz”; for every other number, it should print the number unchanged.

It is possible to write a function which uses no conditional logic at all, but which uses math to separate integers into 4 possible categories: The usual solution is left as an exercise for the interested reader.

  1. Those which have 3 as a factor, but not 5
  2. Those which have 5 as a factor, but not 3
  3. Those which have both 3 and 5 as a factor
  4. Those which have neither 3 nor 5 as factors

We want a function that will return

Consider an implementation of such a function in python:

[(lambda n: { 1: n, 6: "Fizz", 10: "Buzz", 0: "FizzBuzz" }[n**4%15])(n+1) for n in range(100)]

The same function in ruby:

(1..100).map{|n| {1 => n, 6 => "Fizz", 10 => "Buzz", 0 => "FizzBuzz"}[n**4%15] }

As expected, each of these returns a list of the integers from 1 to 100 with “Fizz”, “Buzz”, or “FizzBuzz” substituted in the correct spots.

But why? Where do the constant values 0, 6, 10, and 1 come from? Why does n4mod15 return 6 for multiples of 3 but not 5, 10 for multiples of 5 but not 3, 0 for multiples of 5 and 3, and 1 otherwise? Most important, does this hold true for every n we might choose?

I. n4mod15 solves FizzBuzz

The proposition is:

n4mod15={0,if n is divisible by 3 and 56,if n is divisible by 3 and coprime to 510,if n is divisible by 5 and coprime to 31,if n is coprime to 3 and 5

The first case is trivial; if n has both 3 and 5 as factors, then raising n to any power and returning the result mod15 will always be 0, as any integer with both 3 and 5 as factors is also a multiple of 15 (35).

For the second case, we have 3 as a factor of some constant c:

3c46(mod15)

or

3c4mod15=6

for every constant c > 0 as long as c is coprime to 5. (If c is not coprime to 5, we have the first case, which will return 0.)

To begin, suppose c=1. This gives 34mod15, or 81mod15, which will return 6: 155=75, leaving a remainder of 6 from 81.

Suppose c is an integer > 1. Applying the exponent to each factor and making use of the identity (ab)=(a+a(b1)):

34c4mod1581c4mod15(81+81(c41))mod15

Consider the expression c4 by itself for a moment. We know from Euler’s totient theorem Euler’s totient theorem is that aϕ(n)1(modn) where a is coprime to n and ϕ is Euler’s totient function; the totient function of n returns the number of integers less than n that are coprime to n. For every prime number p, ϕ(p) is equal to p1. A photo of Leonhard Euler
Figure Leonhard Euler
that since c is coprime to 5, c4mod5 is equal to 1; if c4/5 has a remainder of 1, then it must be the case that c41 divides evenly by 5; that is, no matter what c is, if it is coprime to 5 then (c41) has 5 as a factor. The other factor is not significant, so let’s rewrite (c41) as 5x.

(1)(81+81(5x))mod15(2)(81mod15+81(5x)mod15)mod15(3)(6+81(5x)mod15)mod15(4)6mod15

We can rewrite this in (2) because a property of modular expressions is (a+b)modn=(amodn+bmodn)modn.

In line (3), the expression 81(5x) has both 3 and 5 as factors, so 81(5x)mod15=0, which gives us 6mod15, which is 6.

So for any c coprime to 5 and > 1, 3c4mod15 will return 6.

The same process finds that 5c4mod15 will always return 10; for c = 1, we have 625mod15, which is 10. Again, for c>1 (coprime to 3), we can write

(625+625(c41))mod15

Euler’s totient theorem tells us that if c is coprime to 3, then c21mod3; but we have c4. However, c4 is c2c2, and since abmodn=((amodn)(bmodn))modn, c4mod3 is also 1.

Again, if c41(mod3) then (c41) divides evenly by 3 and had 3 as a factor. This again reduces the 2nd term to 0, leaving 625mod15, which again is 10.

This leaves the case where we have some number c which is coprime to both 3 and 5. If c is 1, we have 1mod15, which is 1.

If c > 1, we can again write this as (1+(c41))mod15. Since we know that if c is coprime to both 3 and 5, and c41(mod3) and c41(mod5), then (c41) has both 3 and 5 as factors. So again,

(1+(c41))mod15(1mod15+(c41)mod15)mod15(1+0)mod151mod151

So n4mod15 will always return 0 if both 3 and 5 are factors of n, 6 if 3 is a factor but not 5, 10 if 5 is a factor but not 3, and 1 if n is coprime to both 3 and 5, and a function like ->(n){ {1 => n, 6 => "Fizz", 10 => "Buzz", 0 => "FizzBuzz"}[n**4%15] } will always return a correct FizzBuzz result for every n Up until n4 overflows the integer type used by a given computer. .

II. Solving any FizzBuzz-category problem

A similar function can be created for any similar problem, which I’ll call FizzBuzz-category problems FizzBuzz-category problems: e.g., print “Foo” for multiples of 2, “Bar” for multiples of 3, “Baz” for multiples of 5, and a concatenate each word for numbers which have more than one of 2,3, or 5 as factors . The numbers chosen as factors do not need to be prime, but if one of them has another as a factor, some groups will not exist. For example, if we chose to modify FizzBuzz such that multiples of 2 return “Fizz”, and multiples of 4 return “Buzz” (instead of the traditional 3 and 5), we will see “Fizz” for any multiple of 2, “FizzBuzz” for any multiple of both 2 and 4, but we will never see “Buzz” alone, as there is no multiple of 4 which is coprime to 2. The general solution presented below is not quite as general as I implied here: there are many number pairs for which is will not work well; so the factors must actually be chosen much more specifically. It will work for distinct primes, but not so well for composite numbers. I’d like to thank the author of this very well explained post, which goes into some detail about why the general formula will not work for composite numbers.

The equation used to solve FizzBuzz above can also be written

nLCM(ϕ(3),ϕ(5))mod(35)

where ϕ is Euler’s totient function, and LCM is the least common multiple.

Generalized, for any set of k factors n1,n2,..nk for which we want a FizzBuzz-like function, we can use the formula:

nLCM(ϕ(n1),ϕ(n2),..ϕ(nk))modi=1kni

For a FizzBuzz-like function which returns “Foo” for multiples of 7 and “Bar” for multiples of 11, find:

nLCM(ϕ(7),ϕ(11))mod(711)

ϕ(7) is 6 and ϕ(11) is 10, and the LCM of 6 and 10 will be 30. So the equation will be:

n30mod77

An implementation in python:

[(lambda n: { 1: n, 7**30%77: "Foo", 11**30%77: "Bar", 0: "FooBar" }[n**30%77])(n+1) for n in range(100)]

This gives the expected result:

[1, 2, 3, 4, 5, 6, 'Foo', 8, 9, 10, 'Bar', 12, 13, 'Foo', 15, 16, 17, 18, 19, 20, 'Foo', 'Bar', 23, 24, 25, 26, 27, 'Foo', 29, 30, 31, 32, 'Bar', 34, 'Foo', 36, 37, 38, 39, 40, 41, 'Foo', 43, 'Bar', 45, 46, 47, 48, 'Foo', 50, 51, 52, 53, 54, 'Bar', 'Foo', 57, 58, 59, 60, 61, 62, 'Foo', 64, 65, 'Bar', 67, 68, 69, 'Foo', 71, 72, 73, 74, 75, 76, 'FooBar', 78, 79, 80, 81, 82, 83, 'Foo', 85, 86, 87, 'Bar', 89, 90, 'Foo', 92, 93, 94, 95, 96, 97, 'Foo', 'Bar', 100]

Conclusion

So

aLCM(ϕ(n1),ϕ(n2),..ϕ(nk)){0(modi=1kni),if n is divisible by every n1,n2,..nkr1,r2,..rk(modi=1kni),a distinct result for every other combination of factors in n1,n2,..nk1(modi=1kni),if n is coprime to every n1,n2,..nk

… if the numbers n1,n2,..nk are distinct primes. Again, thanks to the author of this post for illustrating this so clearly.

The author makes no assertion that there is any practical application for this formula other than as a solution to FizzBuzz-category problems with arbitrary integers chosen as candidates.