Of course, we could calculate the DFT using a tool, and from there work out the coefficients for the cosine terms. For example, we could get the coefficients for the exponential form like this:
https://www.wolframalpha.com/input?i=Fourier%5B%7B3%2C+0%2C+...
And then convert them to the coefficients for the cosine form like this:
https://www.wolframalpha.com/input?i=%7B11%2F15%2C+2*0%2C+2*...
That's certainly one way to avoid the tedious work but I decided to use the shortcuts as the basis for my post because I found this approach more interesting. The straightforward DFT method is perfectly valid as well and it would make an interesting post by itself.
Here is the direct link to the new section on DFT: https://susam.net/fizz-buzz-with-cosines.html#dft
Does this ring a bell for anyone?
---
Found it!
https://aphyr.com/posts/340-reversing-the-technical-intervie...
https://aphyr.com/posts/341-hexing-the-technical-interview
https://aphyr.com/posts/342-typing-the-technical-interview
https://aphyr.com/posts/353-rewriting-the-technical-intervie... (the FizzBuzz one)
https://aphyr.com/posts/354-unifying-the-technical-interview
wow.
Does aphyr even have comments, or is it a pure political protest?
That's the first thing that's tempted to break out an ssh tunnel - I can live without the occasional NSFW reddit group.
https://github.com/taolson/Admiran/blob/main/examples/fizzBu...
Yes, very much yes.
> interviewer: Great, we find that candidates who can't get this right don't do well here.
> me: ...
Shit attitude from that candidate, considering the interviewer is completely correct. I wouldn't hire them since they are obviously a problem employee.
For those that don't know, Fizz Buzz is less an aptitude test and more of an attitude test. That's why this candidate failed and didn't get the job.
The amount of (highly credentialed) interviewees that can't 0-shot a correct and fully functional fizzbuzz is also way higher than a lot of people would think. That's where the attitude part also comes in.
from pysr import PySRRegressor
def f(n):
if n % 15 == 0:
return 3
elif n%5 == 0:
return 2
elif n%3 == 0:
return 1
return 0
n = 500
X = np.array(range(1,n)).reshape(-1,1)
Y = np.array([f(n) for n in range(1,n)]).reshape(-1,1)
model = PySRRegressor(
maxsize=25,
niterations=200, # < Increase me for better results
binary_operators=["+", "*"],
unary_operators=["cos", "sin", "exp"],
elementwise_loss="loss(prediction, target) = (prediction - target)^2",
) model.fit(X,Y)
Result I got is this:((cos((x0 + x0) * 1.0471969) * 0.66784626) + ((cos(sin(x0 * 0.628323) * -4.0887628) + 0.06374673) * 1.1508249)) + 1.1086457
with compleixty 22 loss: 0.000015800686 The first term is close to 2/3 * cos(2pi*n/3) which is featured in the actual formula in the article. the constant doesn't compare to 11/15 though
> Can we make the program more complicated? The words 'Fizz', 'Buzz' and
> 'FizzBuzz' repeat in a periodic manner throughout the sequence. What else is
> periodic?
and then I'm thinking ..
> Trigonometric functions!
is a good start, but there are so many places to go!
EDIT: the llm gods do recreational mathematics as well. claude actually thinks it was able to come up with and verify a solution...
https://claude.ai/share/5664fb69-78cf-4723-94c9-7a381f947633
That was a fun read, but I can see that persona quickly becoming wearing. I had a "talk like a wiki article" persona for a while that worked better (for me) than any attempt to inject personality. The greyer the better, when it comes to tools.
(Being a child of the internet rather than the classroom my abusive solution would be to look up the sequence in OEIS, but I think fizzbuzz could be encoded into an L-system quite neatly).
On their default behavior they try too hard to make me like them, which I find intolerable. "You're absolutely right!" for some reason drives me insane; getting "lmaaoooo my bad fam i dun goofed" twenty times a day is equally annoying in terms of models being confidently wrong, but somehow the lazy shitbag attitude pisses me off less than the goody two shoes energy.
And if they're low on crazyness and you force them to be crisp and emotionless like a wikipedia article, I notice that I tend to trust them more... even though again the tendency to bullshit is unchanged, still there.
Somehow this really works for me.
Also when coding it makes it very clear which bits I haven't inspected yet because the comments and variable names will be super nsfw, thus keeping me on my toes as to not accidentally submit PRs filled with "unfuck_json()" functions.
- increases i on every \n,
- prints i when that produces x, otherwise prints the character
(Disregarding rounding errors)
That would be fairly obfuscated, I think.
arr = [];
y = 0;
setInterval(()=>{arr[y]=x},10)
setInterval(()=>{x=y++},1000)
setInterval(()=>{x="fizz"},3000)
setInterval(()=>{x="buzz"},5000)
setInterval(()=>{x="fizzbuzz"},15000)
(The divisions will get optimized away.)
f(n) = 5226577487551039623 + 1537228672809129301*(1669582390241348315^n + 636260618972345635^n) + 3689348814741910322*(725554454131936870^n + 194643636704778390^n + 1781303817082419751^n + 1910184110508252890^n) mod (2^61-1).
This involves 6 exponentiations by n with constant bases. Because in fizzbuzz the inputs are sequential, one can further precompute c^(2^i) and c^(-2^i) and, having c^n, one can go to c^(n+1) in average 2 modular multiplications by multiplying the appropriate powers c^(+-2^i) corresponding to the flipped bits.TFA implies that branches (if statements and piecewise statements) are not allowed, but I don't see why not. Seems like a basic operation to me.
Nevermind that `s[i]` is essentially a piecewise statement.
There is no universal definition of 'closed-form expression'. But there are some basic operations and functions that are broadly accepted, and they are spelled out directly after the 'finite combinations' phrase you quoted from the post. Quoting the remainder of that sentence here:
'[...] finite combinations of basic operations such as addition, subtraction, multiplication, division, integer exponents and roots with integer index as well as functions such as exponentials, logarithms and trigonometric functions.'
I see a case for 3 * 5 in here:
for n in range(1, 101):
if n % 15 == 0:
print('FizzBuzz')
elif n % 3 == 0:
print('Fizz')
elif n % 5 == 0:
print('Buzz')
else:
print(n)
Why?If we add 'Bazz' for mod 7, are we going to hardcode:
for n in range(1, 105):
if n % 105 == 0: # 3 * 5 * 7
print('FizzBuzzBazz')
elif n % 15 == 0: # 3 * 5
print('FizzBuzz')
elif n % 21 == 0: # 3 * 7
print('FizzBazz')
elif n % 35 == 0: # 5 * 7
print('BuzzBazz')
elif n % 3 == 0:
print('Fizz')
elif n % 5 == 0:
print('Buzz')
elif n % 7 == 0:
print('Bazz')
else:
print(n)
Or should we have done something like: for n in range(1, 105):
out = ''
if n % 3 == 0:
out += 'Fizz'
if n % 5 == 0:
out += 'Buzz'
if n % 7 == 0:
out += 'Bazz'
print(out or n)
I've been told sure, but that's a premature optimization, 3 factors wasn't in the spec. OK, but if we changed our minds on even one of the two factors, we're having to find and change 2 lines of code ... still seems off.Sort of fun to muse whether almost all FizzBuzz implementations are a bit wrong.
They're only wrong if they provide output that isn't in the spec. Adding "bazz" isn't in the spec, and assuming that something indeterminate MIGHT come later is also not part.
Folks really really don't like thinking that "FizzBuzz" case maybe shouldn't be there, future extension or factor edit or no.
// And as long as we're just manually computing factor times factor and typing out the results for it like "FizzBuzz" we might as well just hardcode the whole series...