Tuesday, December 23, 2025

I don't understand why Ramanujan summation is taken seriously

One of the most (in)famous "proofs" that the sum of all natural numbers is -1/12 uses as one of its steps a so-called Ramanujan summation to declare that the the infinite sum

1 - 1 + 1 - 1 + 1 - 1 + ... = 1/2

I don't see anything that would justify this equality. The infinite sum is divergent, ie. it does not converge to any particular value no matter how far you advance in it. There is no justification to assigning the arbitrary value 1/2 to it. (There is no justification to just declare that the result of the entire sum is the average of two consecutive partial results. There's even less justification for it because what you get as partial results depends on how you group the terms.)

How this kind of thing should normally be handled is like this:

1) Hypothesis: The infinite sum 1 - 1 + 1 - 1 + ... = 1/2

2) Counter-proof: We assume that the hypothesis is true and show that it leads to a contradiction. Namely: The assumption leads to the contradictory statement that the sum of all natural numbers, which is divergent, is a particular finite value, which would imply the sum would be convergent. An infinite sum cannot be both divergent and convergent at the same time, thus it's a mathematical contradiction.

3) Thus: The hypothesis cannot be true.

In general, whenever a statement leads to a contradiction, it proves that the statement is false. In this case, we have proven by contradiction the Ramanujan summation as incorrect.

But rather than declaring said summation as incorrect (because it leads to a contradictory result), instead mathematicians have taken it as correct and subsequently also the nonsensical statement that results from it.

It's incomprehensible. 

Saturday, December 20, 2025

Quake speedruns slightly marred for me

Some time ago I wrote a blog post about why I don't really watch speedruns anymore, even though I used to be a huge and avid fan 20 years ago. The (quite long) article can be found here. The short summary is: While 20 years ago I didn't mind and in fact was fascinated by extensive glitch abuse, over the years I have grown tired of it and consider it so boring that I don't even watch glitch-heavy speedruns anymore. And, unfortunately, nowadays "glitch-heavy speedruns" covers about 90% of them, if not even more.

I mention in that post that Quake is one of the few games I still watch speedruns of, and the main reason is that, due to how glitch-free the game is, the speedruns are also almost completely glitch-free, and thus show just pure within-the-game sheer awesome playing skill without much if any game-breaking glitches.

I also say this in that post, quote:

"One particularly bad example made me outright want to puke: In a speedrun of the game The Talos Principle, the runner at one point would go to the main menu, go to the game options, set the framerate limit to 30 frames per second, return to the game, perform a glitch (that could only be done with a low framerate), and afterwards go back to the options menu and set the framerate back to unlimited. This was so utterly far-removed from gameplay proper, and was just so utterly disgusting, that I just stopped watching the speedrun right then and there."

Well, you might guess where I'm going with this.

Indeed, framerate abuse has been introduced into Quake speedrunning. It's not an extremely recent addition, mind you (I believe it was started being used several years ago). It's just that I only have noticed now.

I probably did not notice because the framerate abuse is so subtle, as a key can be bound to change the framerate cap, and thus it can be changed on the fly without having to go into any menus, and it doesn't interrupt the speedrun. The only visible indication of this is that a message appears on the top left of the screen telling about the settings change, and it's very easy to miss when watching the speedrun. The framerate is also changed so rarely during speedruns that it's easy to miss for that reason as well.

The game supports capping the framerate in steps of 10, with the minimum being 10 fps, and the maximum 100 fps. And the framerate abuse swaps between those two framerates. 

Quite naturally, I don't really like the idea much better than with other games, like The Talos Principle mentioned above. Some details about it, however, make it slightly less bothering though, so it doesn't really make me want to quit watching Quake speedruns:

  1. As mentioned, it can be done on the fly rather than going to the settings menu to have to do it, so it doesn't interrupt the speedrun itself. Not that this would be the main reason to dislike the technique, but still.
  2. As far as I understand, the technique cannot (so far) be used for any major skips and instead it can only be used in two very specific situations: To press buttons slightly earlier, and to reach the end slightly earlier.
  3. And that "slightly earlier" really means it: At most 0.1 seconds can be saved this way for each button that has to be pressed and once at the end of the level (as a direct consequence of the framerate being 10 frames per second.) And even then, this is only when the button is right in front of the player (and is not eg. pressed from the side by barely glancing it.)

So in a typical level, where the speedrunner might have to press three buttons, about 0.4 seconds can be saved at most.

While I don't really like the technique in principle, it has so little effect on the speedruns that I consider this only an extremely minor annoyance. 

Tuesday, December 16, 2025

How an experienced programmer approaches Matt Parker's wordle problem

I have written earlier a blog post about an example of where program optimization actually really matters and can make an absolutely enormous difference in how much you have to wait for a program to do something (even though the notion that program optimization is not all that important is way too widespread). In that case it was a question of Matt Parker's original Python program taking an entire month to calculate something that could be (quite trivially) calculated in just a few seconds, even in under a second with a bit of algorithmic optimization.

I would like to describe here how an experienced programmer approaches such a problem.

Said problem is:

Given a big English dictionary file (ie. a file containing hundreds of thousands of unique English words), find all combinations of five 5-letter words that combined use 25 unique letters of the alphabet.

Any experienced programmer would very quickly think of ways to do that in a few seconds at most, and categorically know that one month is way, way too slow. This even if we restrict ourselves to using Python.

Matt Parker is not an experienced programmer, and his approach to solving the problem with a Python program was extraordinarily naive and inefficient. Essentially, he read the entire dictionary into some kind of data container, all the several hundreds of thousands of words, and then went through every single combination of 5 words and checked if they matched the conditions: In other words, all five words are 5 letters long, and all the 25 letters are unique.

That is, of course, an extremely inefficient way of doing it and, as it so happens, it can be sped up by several orders of magnitude with extremely simple optimizations. These optimizations might sound trivial to most programmers, and when said, but they might not come to the mind of a beginner programmer.

First: By far the biggest and also the simplest optimization (that Matt clearly didn't think of): We are only interested in 5-letter words. That means we can discard all the other words from the get-go. It's that simple. When reading the dictionary file, if a word doesn't have 5 letters, just discard it and don't add it to the data container.

That simple step reduces the number of words from several hundred thousands to just a few thousands. That speeds up the entire subsequent calculations by several orders of magnitude (more than two because we are talking about quadratic behavior).

Matt's biggest mistake was to take all the words in the dictionary file without discarding any of them. That, rather obviously, is completely unnecessary and extremely wasteful and inefficient. Just this optimization alone, even without anything else, would have probably reduced the runtime of his program from one month to just an hour or so, perhaps even less.

Second: We can actually discard even more words than that, further reducing the amount of data to process. In particular, if any word has a repeated letter, we can also discard it when reading the input, because such words would fail the conditions immediately and cannot be part of the answer. This will further reduce the amount of words probably to less than half of all 5-letter words in the dictionary.

This second optimization would have likely made Matt's program, even without any other changes, take just ten minutes, perhaps even less.

Third: This is where actual algorithmic knowledge and thinking is more required.

Matt's program went through every single possible combination of 5 words in the input. This is unnecessary and we can go through significantly less combinations than that, further reducing runtime by an order of magnitude or two, perhaps even more.

This algorithmic trick is very common and very well known when dealing with exactly this kind of problem. And the idea is: If two words share any letters, you don't need to check any combinations containing those two words (because, rather obviously, all of those combinations will fail.) Just this idea alone allows skipping the vast, vast majority of possible combinations, speeding up the program enormously.

While the idea and principle is quite simple, it might not be immediately obvious to the beginner programmer how to actually implement it in code (and many beginner and even not-so-beginner programmers will often succumb to really complicated and lengthy solutions to try to achieve this.) This is where programming and algorithmic expertise becomes very helpful, as the solution is much simpler than it might sound.

Explaining in great detail the simple algorithm to achieve this would require a bit of text, so I'll just summarize the general idea instead: Going through all the combinations of elements (words in this case) can be implemented as a recursive function which keeps track of which elements we are dealing with. The recursion can be stopped (and execution returned to the previous recursion level) when we detect two words with shared letters, thus skipping all the subsequent deeper recursions.

Fourth: Comparing words.

Here, too, Matt used a very naive approach, where he would take the original words and do an elaborated quadratic comparison of each of their letters.

The thing is: When doing comparison we don't need the letters of the words in their original order. That's unnecessary for this comparison because we only want to know if they share letters, and the order of the letters in the word doesn't matter. Thus, we can rearrange the letters in each word to be eg. alphabetically ordered in order to make the comparison simpler and faster. (The original word can be kept alongside the reordered one in order to print out the found words.)

But that's not even the most efficient way of doing it. Since no letters are repeated (as we have discarded all the words with repeated letters), can just create a small bitmap of each word, with each bit representing each letter of the alphabet. Since the English alphabet consists of 26 letters, a 32-bit integer more than suffices for this. Thus, we can "convert" each 5-letter word into an integer (which bits tells which letters are used in the word), and then we can use a bitwise "and" operator to compare two of them to see if they share any of the bits. In other words, rather than going through a string of letters, we are just comparing two integers with a bitwise-and operator. This is extraordinarily fast.

Even if we restricted ourselves to using Python, doing the four optimizations above would solve the problem in just a few seconds, perhaps even in less than a second. 

Sunday, December 14, 2025

Programmers are strangely dogmatic about cryptic variable names

As a very long-time computer programmer, I have noticed an interesting psychological phenomenon: For some reason beginner programmers absolutely love when they can express a lot of functionality with as little code as possible. They also tend to love mainstream programming languages that allow them to do so.

As an example, if they are learning C, and they encounter the fact that you can implement the functionality of strcpy() with a very short one-liner (directly with C code, without using any standard library function), a one-liner that's quite cryptic compared to how it's done in an average programming language, they just love that stuff and get enamored with it.

This love of brevity in programming quite quickly becomes a habit to the vast majority of programmers, and most of them never "unlearn" said habit. One of the most common and ubiquitous language feature where most programmers will apply this love of brevity is in variable names. (Oftentimes they will do the same with other names in the program as well, such as function and class names, but variable names are the most common target for this, even when they keep those other names relatively clear.)

It becomes an instinct that's actually hard to get rid of (and I'm speaking of personal experience): That strong instinct of using single-letter variables, abbreviations and acronyms, no matter how cryptic and unreadable they may be to the casual reader. (Indeed, their most common defense of those names is "I can understand them perfectly well", without acknowledging that it may not be so clear to others reading the code. Or even to they themselves five years along the line.)

Thus, they will use variable names like for example i instead if index, pn instead of player_name, ret instead of return_value, col instead of column (or even better, column_index), col instead of colorrc instead of reference_count, and so on and so forth. After all, why go through the trouble of writing "return_value" when you can just write "ret"? It's so much shorter and convenient!

But the thing is, the more the code is littered with cryptic short variable names, the harder it becomes to read and understand to someone reading (and trying to understand) the code. I have got an enormous amount of experience on that, as I have had in the past to write an absolutely humongous amount of unit tests for a huge existing library. The thing about writing unit tests for existing code is that you really, really need to understand what the code is doing in order to write meaningful unit tests for it (especially when you are aiming for 100% code coverage).

And, thus, I have seen a huge amount of code that I have had to fully understand (in order to write unit tests for), and I have seen in intricate detail the vast difference in readability and understandability between code that uses cryptic variable and function names vs. code that uses clear readable names. Unsurprisingly, the latter helps quite a lot.

In fact, this is not some kind of niche and novel concept. The coding guidelines of many huge companies, like Google, Microsoft, Facebook and so on, have sections delineating precisely this. In other words, they strongly recommend using full English words in variable and function names rather than abbreviations and cryptic acronyms. One common principle is, relating to the latter: "If the acronym does not have an article in Wikipedia, just write it fully out."

One particular situation where I have noticed how much clear variable naming helps is in loop variables. Loop variables are the one thing that most programmers abbreviate the most, and the most often. Sometimes they go to outright unhealthy lengths to use loop variables that are as short as possible, preferably single-letter, even if that means using meaningless cryptic names like i, j and k.

I have, myself, noticed the importance of, and gotten into the habit of, naming loop variables after their use, ie. what they represent and are being used for. For example, let's say you are iterating through an array of names using a loop, with the loop variable indexing said array. Thus, I will name said variable eg. name_index rather than just i (which is way too common.) If the loop variable is counting something, I will usually name it something_count, or similar, rather than just i or n.

The longer the body of the loop is, and especially if there are several nested loops, the more important it becomes to name the loop variables clearly. It helps immensely keep track of and understand the code when the loop variables are directly naming what they represent, especially alongside naming everything else clearly. For example, suppose you see this line of code:

pd[i].n = n[i];

That doesn't really tell us anything. Imagine, however, if we changed it to this:

player_data[player_index].name = names[player_index];

Is it longer? Sure. But is it also significantly clearer? Absolutely! Even without seeing any of the surrounding code we already get a very good idea of what's happening here, much unlike with the original version.

Yet, try to convince the average experienced programmer, who is used to litter his code with short cryptic variable names, of this. You will invariably fail. In fact, for some reason the majority of computer programmers are strangely dogmatic about it. They are, in fact, so dogmatic about it that if you were to make this argument in an online programming forum or discussion board, you will be likely starting a full on flamewar. They will treat it like you are a stupid arrogant person who has personally insulted them to the core. I'm not exaggerating.

The instinct to write short cryptic code, very much including the use of short cryptic variable names, sits very deep in the mind of the average programmer. It's a strange psychological phenomenon, really.

I have concocted a name for this kind of cryptic programming style: Brevity over clarity. 

Monday, December 8, 2025

I'm tired of "viral math problems" involving PEMDAS

In recent years (or perhaps the last decade or so) there has been a rather cyclic phenomenon of a "viral math problem" that somehow stumps people and reveals that they don't know how to calculate it. It seems that every few months the exact same problem (with just perhaps the numbers involved changed) makes the rounds. And it always makes me think: "Sigh, not this again. It's so tiresome."

And the "viral math problem" is a simple arithmetic expression which, however, has been made confusing and obfuscated not only by using unclear operator precedence but, moreover, by abusing the division symbol ÷ instead of using fractional notation. Pretty much invariably the "problem" involves having a division followed by a multiplication, which is what introduces the confusion. A typical version is something like:

12 ÷ 3(2+2) = ?

This "problem" is so tiresome because it deliberately uses the ÷ symbol to keep it all in one line instead of using the actual fractional notation (ie. a horizontal line with the numerator above it and the denominator below it) which would completely disambiguate the expression. And, of course, it deliberately has the division first and the multiplication after that, causing the confusion.

This is deliberately deceptive because, as mentioned, the normal fractional notation would completely disambiguate the expression: If the division of 12 by 3 is supposed to be calculated first and then the result then multiplied by (2+2), then the fraction would have 12 at the top, 3 on the bottom, and the (2+2) would follow the fraction (ie. be at the same level as the horizontal line of the fraction).

If, however, the 12 is supposed to be divided by the result of 3(2+2) then that entire latter expression would be in the denominator, ie. below the fraction line.

That clearly and uniquely disambiguates the notation. Something that "12 ÷ 3(2+2)" quite deliberately does not.

Many people would think: "What's the problem? It's quite simple: Follow so-called PEMDAS, where multiplication and division have the same precedence, and operators of the same precedence are evaluated from left to right. In other words, calculate 12 by 3 first, then multiply the result by (2+2)."

Except that it's not that simple. It so happens that "PEMDAS" does not really deal with the "implied multiplication", ie. the symbolless product notation, such as when you write "2x + 3y", which has two implied products.

The fact is that there is no universal consensus on whether the implied product should have a higher precedence than explicit multiplication and division. And the reason for this is that in normal mathematical notation the distinction is unnecessary because you don't get these ambiguous situations, and that's because the ÷ symbol is not usually used to denote division alongside implied multiplication.

In other words, there is no universal consensus on whether "1 ÷ 2x" should be interpreted as "(1÷2)x" or "1 ÷ (2x)". People have actually found published physics and math papers that actually use the latter interpretation, so it's not completely unheard of.

The main problem is that this is deliberately mixing two different notations: Usually the mathematical notation that uses implied multiplication does not use ÷ for division, instead using the fraction notation. And usually the notation that does use ÷ does not use implied multiplication. These are two distinct notations (although not really "standardized" per se, which only adds to the confusion.)

Thus, the only correct answer to "how much is 12 ÷ 3(2+2)?" is: "It depends on your operator precedence agreement when it comes to the ÷ symbol and the implied multiplication." In other words, "tell me the precedence rules you want to use, and then I'll tell you the answer, because it depends on that."

(And, as mentioned, "PEMDAS" is not a valid answer to the question because, ironically, that's ambiguous too. Unless you take it literally and consider ÷ and implied multiplication to be at the same precedence level, and thus to be evaluated from left to right. But you would still want to clarify that that's what's meant.)

Also somewhat ironically, even if instead of implied multiplication we borrowed the actual arithmetic notation for multiplication from the same set as the ÷ symbol, in other words, the expression would be:

12 ÷ 3×(2+2)

that would still be ambiguous because even here there is no 100% consensus.

The entire problem is just disingenuous and specifically designed to confuse and trick people, which is why I really dislike it and am tired of it.

An honest version of the problem would use parentheses to disambiguate. In other words, either:

(12÷3)×(2+2)

or

12 ÷ (3×(2+2))