Fizz-Buzz is a some kind of test used in interviews, which I have heard. But, I was never asked this question.
In Fizz-Buzz test, what you have to do is to write a code, to print Fizz, Buzz, FizzBuzz or a number.
To go in detail, you have to loop over some number or test some number and check that.
if the number is divisible by 15 then print “FizzBuzz”
if the number is divisible by 3 then print “Fizz”
if the number is divisible by 5 then print “Buzz”
otherwise print the number.
A normal code, the code is written exactly like the pseudocode, shown above. We write few branches to test the number and print a message.
This is a branched code, that means depending on the number, used in testing, processor will execute instructions from different branches.
Which is bad for branch predictor, so, I will be writing a code to show how this can be done without branches.
First, I will declare a sealed interface, which will have two methods.
- handle(final int value)
- onFailure(Consumer<Integer> consumer)
sealed interface Handler permits FizzBuzz, None{ void handle(int value); default void onFailure(Consumer<Integer> consumer){} }
This can be implemented by only Two classes FizzBuzz, and None.
These classes implements handle() to provide the instructions on what to do when it is provided with an integer.
In onFailure() function, the implementing classes accepts a consumer, which is used in the scenarios, where it gets called ,when the divisor in that class is not able to divide the integer.
So, If FizzBuzz class is not able to divide the number, it will call it’s onFailure() function.
So, how do we make this branch code branch-less?
I am going to store an array of codes, or consumers.
And, the remainder of divide operation is going to be used as an index in the array of consumers to handle the integer division.
This is my implementation of FizzBuzz class.
private final class FizzBuzz implements Handler{ final int divisor; final Consumer<Integer>[] consumers; private FizzBuzz(final String _message, final int _divisor){ this.divisor = _divisor; this.consumers = new Consumer[_divisor]; this.consumers[0] = (value) -> System.out.println(_message); } @Override public void handle(final int _value){ consumers[_value % divisor].accept(_value); } @Override public void onFailure(final Consumer<Integer> _consumer){ Arrays.fill(consumers, 1, divisor, _consumer); } }
In the FizzBuzz, the constructor takes two inputs,
- _message : it is printed, if divide operation generates remainder equal to ‘0’
- _divisor : this number is used as divisor of input numbers
In the implementation of handle function, we divide the input integer with a divisor and pass that remainder in the ‘consumers’ array.
The consumers array is an array of consumers, where the first element, that can be accessed by zero index, is the action to be executed when the remainder is ‘0’.
And, from index 1 onward, we keep a copy of the consumer passed in the onFailure() function.
Let us walk through the case where we are diving an integer by ’15’.
If the number is divisible by 15, we get a remainder ‘0’.
Otherwise, the remainder can be from 1 to 14.
And, the ‘consumers’ array, stores at ‘0’ index an action which gets called when the number is divisible by 15, because the remainder is ‘0’, the consumer at zeroth index gets called.
Similarly, if the remainder is 1 or 2 or 14, consumers at respective indices are called.
This is entire logic of making the code for Fizz-Buzz test branch-less.
How to use these classes.
public static void main(String[] args) { final BranchLessFizzBuzz branchLessFizzBuzz = new BranchLessFizzBuzz(); final FizzBuzz divisibleByFifteen = branchLessFizzBuzz.new FizzBuzz("FizzBuzz", 15); final FizzBuzz divisibleByFive = branchLessFizzBuzz.new FizzBuzz("Fizz", 5); final FizzBuzz divisibleByThree = branchLessFizzBuzz.new FizzBuzz("Buzz", 3); final None none = branchLessFizzBuzz.new None(); divisibleByFifteen.onFailure(divisibleByFive::handle); divisibleByFive.onFailure(divisibleByThree::handle); divisibleByThree.onFailure(none::handle); IntStream.rangeClosed(1, 50).forEach(divisibleByFifteen::handle); }
In the main function, you can see, I have created four objects, one for each case of division by 15, 5, and 3. And, one is the case where the number is not-divisible.
final BranchLessFizzBuzz branchLessFizzBuzz = new BranchLessFizzBuzz(); final FizzBuzz divisibleByFifteen = branchLessFizzBuzz.new FizzBuzz("FizzBuzz", 15); final FizzBuzz divisibleByFive = branchLessFizzBuzz.new FizzBuzz("Fizz", 5); final FizzBuzz divisibleByThree = branchLessFizzBuzz.new FizzBuzz("Buzz", 3); final None none = branchLessFizzBuzz.new None();
After the objects are created, I pass the object’s method as an implementation into onFailure() function.
divisibleByFifteen.onFailure(divisibleByFive::handle); divisibleByFive.onFailure(divisibleByThree::handle); divisibleByThree.onFailure(none::handle);
If divisibleByFifteen fails to divide the number, it will call it’s onFailure() function.
It does not have to call that function directly, it will get called based on the remainder after division.
Complete Code:
import java.util.Arrays; import java.util.function.Consumer; import java.util.stream.IntStream; public class BranchLessFizzBuzz { sealed interface Handler permits FizzBuzz, None{ void handle(int value); default void onFailure(Consumer<Integer> consumer){} } private final class FizzBuzz implements Handler{ final int divisor; final Consumer<Integer>[] consumers; private FizzBuzz(final String _message, final int _divisor){ this.divisor = _divisor; this.consumers = new Consumer[_divisor]; this.consumers[0] = (value) -> System.out.println(_message); } @Override public void handle(final int _value){ consumers[_value % divisor].accept(_value); } @Override public void onFailure(final Consumer<Integer> _consumer){ Arrays.fill(consumers, 1, divisor, _consumer); } } private final class None implements Handler{ @Override public void handle(final int value){ System.out.println(value); } } public static void main(String[] args) { final BranchLessFizzBuzz branchLessFizzBuzz = new BranchLessFizzBuzz(); final FizzBuzz divisibleByFifteen = branchLessFizzBuzz.new FizzBuzz("FizzBuzz", 15); final FizzBuzz divisibleByFive = branchLessFizzBuzz.new FizzBuzz("Fizz", 5); final FizzBuzz divisibleByThree = branchLessFizzBuzz.new FizzBuzz("Buzz", 3); final None none = branchLessFizzBuzz.new None(); divisibleByFifteen.onFailure(divisibleByFive::handle); divisibleByFive.onFailure(divisibleByThree::handle); divisibleByThree.onFailure(none::handle); IntStream.rangeClosed(1, 50).forEach(divisibleByFifteen::handle); } }