Un des problèmes ultra classiques d’entretien, c’est d’afficher les nombres du jeu fizzbuzz.
On va voir comment aller au dela.
Bon, déjà, l’énoncé du problème:
interviewer: OK, so I need you to print the numbers from 1 to 100, except that if the number is divisible by 3 print “fizz”, if it’s divisible by 5 print “buzz”, and if it’s divisible by 15 print “fizzbuzz”.
Si vous n’avez jamais codé ce problème, prenez un moment pour y réfléchir, et essayer de le faire.
Voici une solution en python:
def fizzbuzz(n:int) -> int|str:
if n%3 == 0 and n%5 ==0:
return 'fizzbuzz'
if n%3 == 0:
return 'fizz'
if n%5 == 0:
return 'buzz'
return n
for i in range(100):
print(fizzbuzz(i))
Et une trace d’exécution:
$ python fizzbuzz.py
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
[…]
Il y a deux difficultés:
%
: n % 3 == 0
if
. Si vous mettez if n%3 == 0 and n%5 ==0
en dernier, ca ne marche plus.Il y a plein de choses à dire
Il est amusant de voir qu’en python, on peut répondre par un one-liner:
def fizzbuzz(n:int) -> int|str:
return 'fizz'*(n%3==0)+'buzz'*(n%5==0) or n
Pour comprendre ce one-liner, il faut savoir qu’en python:
Ca fait la même chose que précédemment: si n est divisable par 3 ou 5, on inclus le bout de chaine correspondant. Et donc s’il est divisible par les deux, on a bien fizzbuzz.
S’il n’est divisible par aucun des deux, on a une chaine vide, et on renvoie le nombre de départ.
Alors oui, c’est pas du code qui arrivera en production tous les jours, mais après avoir levé les yeux au ciel lorsque j’ai vu cette approche la première fois, je lui trouve une certaine élégance.
Ruby, qui est pourtant très expressif, ne permet pas cette concision:
def fizzbuzz(n)
s = 'fizz'*((n%3==0)?1:0)+'buzz'*((n%5==0)?1:0)
if s.length > 0 then return s else return n end
end
(0..15).each do |n|
puts fizzbuzz(n)
end
On est obligé de transformer le booléen en entier via une opération ternaire, et d’inclure une seconde condition ternaire pour renvoyer la bonne valeur.
Bon résoudre le problème, c’est une chose, mais et si on essayait de le résoudre très vite? Quelqu’un a posé la question de quel débit on pouvait avoir ?
La réponse du vainqueur est de l’ordre de 50GiB/s, soit environ 10x plus que le second. La solution est en assembleur. L’auteur y donne quelques explications, honnêtement j’ai été content de lire un second writeup.
En gros:
vmsplice
plutôt que write
pour éviter des copies de mémoire inutiles.Tensorflow est une librairie d’apprentissage statistique très largement surdimensionnée pour ce simple problème. Si vous avez aimé ce que vous avez lu jusqu’à présent, vous adorerez ce… compte rendu d’entretien.
Tant qu’on est dans l’overengineering, faut qu’on parle de FizzBuzz enterprise edition.