Update
This commit is contained in:
parent
58976da528
commit
01b86872e4
11 changed files with 18 additions and 13 deletions
11
fizzbuzz.md
11
fizzbuzz.md
|
@ -1,6 +1,6 @@
|
|||
# FizzBuzz
|
||||
|
||||
FizzBuzz is a relatively simple programming problem that's famous/infamous by having a number of different approach solutions and is often used e.g. in interviews to test the skills of to-be-hired programmers. It comes from a child game that teaches basic integer division in which kids are supposed to shout a specific word if a number is divisible by some other number -- what's of interest about the problem is not the solution itself (which is trivial) but rather how one should structure an [algorithm](algorithm.md) that solves the problem. The problem is stated as follows:
|
||||
FizzBuzz is a relatively simple programming problem that's famous/infamous by having a number of different approach solutions and is often used e.g. in interviews to test the skills of potential hires. It comes from a child game that teaches basic integer division in which kids are supposed to shout a specific word if a number is divisible by some other number -- what's of interest about the problem is not the solution itself (which is trivial) but rather how one should structure an [algorithm](algorithm.md) that solves the problem. The problem is stated as follows:
|
||||
|
||||
*Write a program that writes out numbers from 1 to 100 (including both); however if a number is divisible by 3, write "Fizz" instead of the number, if the number is divisible by 5, write "Buzz" instead of it and if it is divisible by both 3 and 5, write "FizzBuzz" instead of it.*
|
||||
|
||||
|
@ -133,8 +133,6 @@ int main(void)
|
|||
*s = '0' + (i / 10) % 10;
|
||||
s += (*s != '0') | (i >= 100);
|
||||
*s = '0' + i % 10;
|
||||
s++;
|
||||
*s = 0;
|
||||
|
||||
int offset = ((i % 3 == 0) + ((i % 5 == 0) << 1)) << 3;
|
||||
printf(str + offset);
|
||||
|
@ -145,15 +143,14 @@ int main(void)
|
|||
}
|
||||
```
|
||||
|
||||
The idea is to have a kind of [look up table](lut.md) of all options we can print, then take the thing to actually print out by indexing the table with the 2 bit divisibility value we used in the above example. Our lookup table here is the global string `str`, we can see it rather as an array of zero terminated strings, each one starting at the multiple of 8 index (this alignment to power of two will make the indexing more efficient as we'll be able to compute the offset with a mere bit shift as opposed to multiplication). The first item in the table is initially empty (all zeros) and in each loop cycle will actually be overwritten with the ASCII representation of currently checked number, the second item is "Fizz", the third item is "Buzz" and last one is "FizzBuzz". In each loop cycle we compute the 2 bit divisibility value, which will be a number 0 to 3, bit shift it by 3 to the left (multiply it by 8) and use that as an offset, i.e. the place where the printing function will start printing (also note that printing will stop at encountering a zero value). The conversion of number to ASCII is also implemented without any branches (and could be actually a bit simpler as we know e.g. the number 100 won't ever be printed). However notice that we pay a great price for all this: the code is quite ugly and unreadable and also performance-wise we many times waste time on converting the number to ASCII even if it then won't be printed, i.e. something that a branch can actually prevent. So at this point we probably overengineered this.
|
||||
The idea is to have a kind of [look up table](lut.md) of all options we can print, then take the thing to actually print out by indexing the table with the 2 bit divisibility value we used in the above example. Our lookup table here is the global string `str`, we can see it rather as an array of zero terminated strings, each one starting at the multiple of 8 index (this alignment to power of two will make the indexing more efficient as we'll be able to compute the offset with a mere bit shift as opposed to multiplication). The first item in the table is initially empty (all zeros) and in each loop cycle will actually be overwritten with the ASCII representation of currently checked number, the second item is "Fizz", the third item is "Buzz" and last one is "FizzBuzz". In each loop cycle we compute the 2 bit divisibility value, which will be a number 0 to 3, bit shift it by 3 to the left (multiply it by 8) and use that as an offset, i.e. the place where the printing function will start printing (also note that printing will stop at encountering a zero value). The conversion of number to ASCII is also implemented without any branches (and could be actually a bit simpler as we know e.g. the number 100 won't ever be printed). However notice that we pay a great price for all this: the code is quite ugly and unreadable and also performance-wise we many times waste time on converting the number to ASCII even if it then won't be printed, i.e. something that a branch can actually prevent, and the conversion actually further uses modulo and division instructions which we are trying to avoid in the first place... so at this point we probably overengineered this.
|
||||
|
||||
If the problem asks for shortest code, even on detriment of [readability](readability.md) and efficiency, we might try **the [code golfer](code_golf.md) approach**:
|
||||
|
||||
```
|
||||
#include <stdio.h>
|
||||
#define P printf
|
||||
int i;int main(){while(i<100){if(i++)P(", ");int a=!(i%3)+!(i%5)*2;
|
||||
if(a)P("FizzBuzz\0Fizz"+(4+(a==1)*5)*(a!=3));else P("%d",i);}P("\n");}
|
||||
#define P printf(
|
||||
int i;int main(){while(i<100){if(i++)P", ");int a=!(i%3)+!(i%5)*2;if(a)P"FizzBuzz\0Fizz"+(4+(a==1)*5)*(a!=3));else P"%d",i);}P"\n");}
|
||||
```
|
||||
|
||||
It's almost definitely not minimal but can be a good start.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue