Euler's Fizzbuzz (2020)
philcrissman.net
philcrissman.net
Not that anyone cares for FizzBuzz but I'll just note that n**4%15 is more efficiently written using the 3 argument pow function in python, eg pow(n, 4, 15).
>>> timeit("(1<<100000000)**4%15", number=1)
1.5620321459136903
>>> timeit("pow(1<<100000000, 4, 15)", number=1)
0.05834826407954097
>>>
If n gets large then n**4 is very large so the % 15 has to deal with a big number. pow runs the modulo operation at the same time as the power operation so the intermediates never get bigger than 15.EDIT: What I wrote was more about the general case. In this specific case, the largest number we get after modulo would be 14, and 14^4 is only 38,416 so it does actually stay small for this specific instance of the problem.
> If the commutative property holds for a pair of elements under a certain binary operation then the two elements are said to commute under that operation.
https://en.wikipedia.org/wiki/Modular_arithmetic#Properties
It should be easy to see that
n ≡ (n % 15) (mod 15)
which, applying compatibility of exp, then gives us n^4 ≡ (n % 15)^4 (mod 15)
which can be rewritten in Python's notation as n**4 % 15 == (n % 15) ** 4 % 15So the terms are correct.
As far as programmers, modulus is an operator, complete with operator overloading in many languages and satisfying operator precedence. So operator is the correct word there also.
Here's the idea from math https://mathoverflow.net/questions/20968/rules-for-operator-...
You really want to say that mod15(pow4(x)) == mod15(pow4(mod15(x))).
Example:
(3 ** 4) % 15 = 81 % 15 = 6.
But,
(3 % 15) ** 4 = 3 ** 4 = 81.
(That said, the two functions do commute when you restrict your domain and range to Z/15.)
edit: also, I wouldn't consider mod15 to be an injection, as it's, um, not injective (it maps multiple inputs to the same output).
It's not actually the same pow4 on the LHS and RHS (the LHS is in Z, the RHS in Z/15), but I think "commutative" still fits.
> as it's, um, not injective
Er, surjection :)
Then the desired statement showing commutativity is
pow4'(mod15(x)) = pow4'(x) = mod15(pow4'(x))
where that last equality is trivial because mod15 o mod15 = mod15
so mod15 o pow4' = mod15 o mod15 o pow4 = mod15 o pow4 = pow4'
per associativity of function compositionI thought it was a fantastic post on a extremely well trodden subject, up there with solving fizzbuzz in Tensorflow post. (https://joelgrus.com/2016/05/23/fizz-buzz-in-tensorflow/)
I feel like I need to revisit after seeing tensorflow and Euler. I need to find some way of making the lucky number using things around a room, like a mentalist or something.
Some other subversive ones I've seen of are the java enterprise version, and several that import a fizzbuzz library and just run.
It seems kind of obvious compared to the Euler method, though. Once you realize it's 4 bits across a cycle of 15, it's just just a matter of finding the right seed. It should be on the order of 1 in a billion, which is no big deal. In hindsight, if I had combined my number theory knowledge I might have been able to accomplish the Euler solution, but I didn't, so hats off to them.
The presentation of the tensorflow provides more a much higher contempt for the question than I've achieved as well. The fact it isn't 100% accurate, but can be trained to be accurate to a certain level, just makes it better.
I will redouble my research efforts on this or some other problem which doesn't need solving.
You want it without ANY conditional logic try this
(python3): [str(n)*(n%3!=0)*(n%5!=0) + 'Fizz'*(n%3==0) + 'Buzz'*(n%5==0) for n in range(1,101)]
I was talking about the idea behind the code - that map is a pythonic shorthand for a bunch of if-then statements, it still expresses conditionals. While using string multiplication doesn't.
What if instead of 3 and 5, we did FizzBuzz with 7 and 11? Let's do n%77, now we need to map 7, 14, 21, 28, 35, 42, 49, 56, 63, 70 to Fizz, and 11, 22, 33, 44, 55, 66 to Buzz, unless we can find some way to have them all reduce to the same number. Is that really so straightforward?
Now that we know the trick with the exponents, we could try a few to start.
For multiples of 11 it seems the smallest one which works is 6! Great, let's try it on multiples of 7.. Nope. Ok, for multiples of 7, I see that ^10 works.. but that doesn't work for multiples of 11.
* the article addresses this at the end, and tells us that the correct exponent is ^30, the lowest common denominator of 6 and 10. But if I'd been given this problem, I'd have remained stuck on the second paragraph of this comment, with no idea where to start when seeking to reduce the divisors to a single number.
Therefore you need to pick a common multiple of 6 and 10.
I'm definitely an amateur mathematician, though I tried my best to write the post like I think I'd try to write a proof. It came about because I stumbled across the equation, but I did not know _why_ it worked, so I was semi-obsessed with figuring out the _why_ for a long time.
I have nothing else to promote, haven't even put anything on the site since this one and only post... Anyways, thanks, news-YC.
You probably know this already, but I'd think of this the following way. There are two main mathematical ideas involved here:
• The first, easy to underrate because it can seem "obvious", is the Chinese remainder theorem. This, for instance, here implies that any function of the quantities (x mod 3) and (x mod 5) can be rewritten as a function of just (x mod 15). So if you used just this one idea and not the next one, you could implement FizzBuzz as
lambda n: ['FizzBuzz', n, n, 'Fizz', n, 'Buzz', 'Fizz', n, n, 'Fizz', 'Buzz', n, 'Fizz', n, n][n % 15]
• The second is Fermat's little theorem. It says (x^(p-1) mod p) = [x is not a multiple of p], where the notation […] is Iverson bracket, i.e. 1 or 0 depending on whether the condition is true or not. So the question of whether x is a multiple of 5 or not is equivalent to whether x^4 mod 5 is 0 or 1. This just gives us a convenient way of restating the divisibility condition.To get from Fermat's little theorem to Euler's theorem (or to be pedantic, Carmichael's theorem, as you're not using φ(15) which is technically 2*4 = 8, but rather using lcm(2, 4)=4: https://en.wikipedia.org/w/index.php?title=Carmichael_functi... ) is itself an application of the Chinese remainder theorem, which is why I think it's important and mentioned it first.
And putting these two ideas together gives the function in your post. Namely: the FizzBuzz you want is a function of [x is a multiple of 3] and [x is a multiple of 5], so you can (using the second idea) rewrite it as a function of (x^2 mod 3) and (x^4 mod 5), and put them together (using the CRT) as a function of (x^4 mod 15).
Coincidentally, both the ideas here are connected to Lagrange: the Chinese remainder theorem is the same kind of thing as the Lagrange interpolation formula (https://artofproblemsolving.com/community/c1157h990758_the_c...), and Fermat's/Euler's/Carmichael's theorem is the same kind of thing as Lagrange's theorem in group theory.
Re the margin notes, the footnote numbers are clickable to toggle them inline when the width is too small... I should add a bit of color or underline to them in the css so that this is easier to intuit. :/
BTW, for the question “Where do the constant values 0, 6, 10, and 1 come from?”, though it's implicit in the post, it is useful to note explicitly that as x^4 takes only the values 0 or 1 either mod 3 or mod 5, these four possibilities—namely (0,0), (0,1), (1,0), (1,1)—precisely account for those values:
(0 mod 3) and (0 mod 5) ⇔ (0 mod 15)
(0 mod 3) and (1 mod 5) ⇔ (6 mod 15)
(1 mod 3) and (0 mod 5) ⇔ (10 mod 15)
(1 mod 3) and (1 mod 5) ⇔ (1 mod 15)
This would also simplify the post considerably maybe, as much of the algebra wouldn't be needed.My favorite FizzBuzz solution is actually:
``` ->(n){[[["Fizz"][n%3],["Buzz"][n%5]].join].find(->{n}){|w| w if !w.empty?}} ```
This is Ruby, of course, probably something very similar can be done in several other languages.
https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Operation
Sadly, quantum supremacy may mean this form of cryptography will soon be dead, but this curious application is why modular arithmetic is a favorite of mine. It was a branch of math that historically had a few niche applications, and then in the 21st century became an underpinning to global capitalism.
I don't think it will be soon, but when it happens it won't necessarily be sad.
e.g. dumb phones, analog TV, CRT monitors, floppy disks...
To break RSA-N you need a superposition of all the numbers up to 2^N, AFAIK there is even not a hint how to approach it physically.
Is it? How do you do it? The papers I've seen so far shown that given enough measurements we can conclude that the qbits ware in superposition in many cases. I still haven't seen any way to have superposition of all numbers from 0 to 2^n.
What you're describing in the rest of your comment is solved by Shor's algorithm. It is quite straight-forward. If we can get the superposition as an input and have working quantum gates it would work.
Similar how all we need to draw a square with -1 area is to take a line segment with a length of i, the rest is simple.
message_handler = {type_0, type_1, ..., type_999}; // imagine it being generated
message_handler[message.type](message);
In the case of computed go to in Fortran, it's similar. I had the "pleasure" of maintaining this once. It's been a while so I had to look up the syntax, IIRC it used something like a dispatch tree and dispatched off each digit in the type but I could be wrong: go to (0, 100, 200, 300, ...), message_type / 100 -- integer division
0
go to ...
100
go to ...
200
go to ...
... //pseudocode
map(f, ns)
for i in (0 .. ns.length - 1)
f(ns[i])The key lookup in dict definitely has conditionals, though.
Of course, the guy could get rid of that by just using an 11-element array and addressing directly instead of hashing integers as keys.
And how does the iterator know that it should raise an exception? A conditional.
I am much more interested in an explanation of how to find this solution, than a theoretical solution of why it is correct. Specifically I don't understand from the article why the trick of raising n to the power of LCM(phi(3), phi(5)) works.
The author is trying to use Euler's theorem (if a, n are coprimes, then a^{\phi(n)} \equiv 1 \mod n), but the map defined by the exponentiation doesn't say anything about what happens when (a, n) are not coprime.
I'd encourage you to read this post, which is linked by the article: https://blog.antfeedr.com/posts/fizzbuzz.html.
This is because your number theory-fu is poor.
Don't take this in a bad way, I'm probably even less capable. What I mean is that readability is predicated on a reader. Seasoned number theorists might not be as cool with goroutines or walrii operators or virtual DOMs.
In general (ab) mod n == (a mod n)(b mod n) mod n
In the case of (3*c)^4, 3^4 mod 15 -> 108 mod 15 -> 3.
Let i = ((n % 3) == 0) | ((n % 5) == 0) << 1
Then map output as { n, 'Fizz', 'Buzz', 'FizzBuzz' }
Let i = ((n % 3) ** 2) + ((n % 5) ** 4) * 2
Or, given any number n of primes p_j, the "fizzbuzz index" i is just
Let i = sum_over_j(((n % p_j) ** (p_j - 1)) * (n ** j))
(This doesn't generalize to non-primes via the totient function for the same reason the post's solution doesn't generalize - (a % k) * phi(k) for prime k is zero if and only if k divides a, but for non-prime k it can also become zero for other a.)
E.g., considering `var rectified = x*(x>0);` or `var foo = predicate ? bar : baz;` both lend themselves to having their invariants easily verified, even if many such constructions are littered through a program. Contrast that with something like `if (predicate) {/*nightmares*/} else {/*slightly changed nightmares*/}` -- too many branches can quickly lead to an explosion of possible execution paths and all the problems that entails.
char ds[5];
char * words[4] = {ds, "Fizz\n", "Buzz\n", "FizzBuzz\n"};
for (i = 1; i < 101; ++i) {
sprintf(ds, "%d\\n", i)
printf(words[((i*i*i*i)%15)/4]);
}* heh! https://projecteuler.net
It should solve:
3: fizz
5: buzz
15: fizzbuzzfizzbuzz
Why is this?
15 is divisible by 3
15 is divisible by 5
15 is divisible by 3 and 5
All three statements in the description are true. You never said they were mutually exclusive.
n^4 % x = m
== (n % x)^4 % x = m
By way of demonstration: n = 18, x = 15
18^4 = 104976 = 6 (mod 15)
----
18 % 15 = 3
3^4 = 81 = 6 (mod 15)
A very handy result to remember for cases where you don't want to use or don't have easy access to arbitrary precision integers.EDIT: Pasting into Lynx screwed formatting from Groff.
That is not generally true. A quick counterexample:
a = 2, n = 3, b = 5
2^3 % 5 = 8 % 5 = 3
2 % 5 = 2
3 != 2 (a ^ n) % n = a % nThis is really funny. I had an intuition there must be a lambda function solution for fizzbuzz, but I don't do coding interviews and never pursued it. I can see why now, because it's waaay out of my skillset, but so neat to read.
def fizzbuzz(n):
num_map = { 1: n, 6: "Fizz", 10: "Buzz", 0: "FizzBuzz" }
return num_map[n**4%15]
for i in range(100):
print(fizzbuzz(i + 1))
The real skill would be to demonstrate that you know/remember/can apply Euler's totient theorem off-the-cuff in an interview! [{ 1: n, 6: "Fizz", 10: "Buzz", 0: "FizzBuzz" }[n**4%15] for n in range(1, 101)]
The lambda in the original code is just used to convert the 0..99 that's generated by range(100) to 1..100. Using range(1, 101) instead generates the appropriate range of numbers from the beginning.