Latest Posts (20 found)
Susam Pal 1 weeks ago

Circular Recursive Negating Acronyms

One of my favourite acronyms from the world of computing and technology is XINU. It stands for 'XINU Is Not Unix'. The delightful thing about this acronym is that XINU is also UNIX spelled backwards. For a given word W , a recursive acronym that both negates W and reverses it is possible when W has the form W = '?NI?' where each '?' denotes a distinct letter. Some fictitious examples make this clearer: Words of the form '?N?' also work if we are happy to contract the word 'is' in the acronym. In fact, in this case we can even obtain circular recursive acronyms: In each pair, the two acronyms negate each other, making them circular while also being reverses of one another. Such acronyms could serve as amusing names for expressing friendly banter between rival projects. Read on website | #miscellaneous LINA Is Not ANIL. TINK Is Not KNIT. ANI's Not INA. INA's Not ANI. ONE's Not ENO. ENO's Not ONE.

0 views
Susam Pal 3 weeks ago

My Coding Adventures in 2025

In this post, I return with a retrospective on my coding adventures, where I summarise my hobby projects and recreational programming activities from the current year. I did the last such retrospective in 2023 . So I think this is a good time to do another retrospective. At the outset, I should mention that I have done less hobby computing this year than in the past few, largely because I spent a substantial portion of my leisure time studying Galois theory and algebraic graph theory. In case you are wondering where I am learning these subjects from, the books are Galois Theory , 5th ed. by Ian Stewart and Algebraic Graph Theory by Godsil and Royle. Both are absolutely fascinating subjects and the two books I mentioned are quite good as well. I highly recommend them. Now back to the coding adventures. Here they go: MathB : The year began not with the release of a new project but with the opposite: discontinuing a project I had maintained for 13 years. MathB.in, a mathematics pastebin service, was discontinued early this year. This is a project I developed in 2012 for myself and my friends. Although a rather simple project, it was close to my heart, as I have many fond memories of exchanging mathematical puzzles and solutions with my friends using this service. Over time, the project grew quite popular on IRC networks, as well as in some schools and universities, where IRC users, learners, and students used the service to share problems and solutions with one another, much as my friends and I had done in its early days. I shut it down this year because I wanted to move on from the project. Before the shutdown, a kind member of the Archive Team worked with me to archive all posts from the now-defunct website. Although shutting down this service was a bittersweet event for me, I feel relieved that I no longer have to run a live service in my spare time. While this was a good hobby ten years ago, it no longer is. See my blog post MathB.in Is Shutting Down for more details on the reasons behind this decision. The source code of this project remains open source and available at github.com/susam/mathb . QuickQWERTY : This is a touch-typing tutor that runs in a web browser. I originally developed it in 2008 for myself and my friends. While I learned touch typing on an actual typewriter as a child, those lessons did not stick with me. Much later, while I was at university, I came across a Java applet-based touch-typing tutor that finally helped me learn touch typing properly. I disliked installing Java plugins in the web browser, which is why I later developed this project in plain HTML and JavaScript. This year, I carried out a major refactoring to collapse the entire project into a single standalone HTML file with no external dependencies. The source code has been greatly simplified as well. When I was younger and more naive, inspired by the complexity and multiple layers of abstraction I saw in popular open source and professional projects, I tended to introduce similar abstractions and complexity into my personal projects. Over time, however, I began to appreciate simplicity. The new code for this project is smaller and simpler, and I am quite happy with the end result. You can take a look at the code here: quickqwerty.html . If you want to use the typing tutor, go here: QuickQWERTY . Unfortunately, it does not support keyboard layouts other than QWERTY. When I originally developed this project, my view of the computing world was rather limited. I was not even aware that other keyboard layouts existed. You are, however, very welcome to fork the project and adapt the lessons for other layouts. CFRS[] : This project was my first contribution to the quirky world of esolangs. CFRS[] is an extremely minimal drawing language consisting of only six simple commands: , , , , , and . I developed it in 2023 and have since been maintaining it with occasional bug fixes. This year, I fixed an annoying bug that caused the drawing canvas to overflow on some mobile web browsers. A new demo also arrived from the community this year and has now been added to the community demo page. See Glimmering Galaxy for the new demo. If you want to play with CFRS[] now, visit CFRS[] . FXYT : This is another esolang project of mine. This too is a minimal drawing language, though not as minimal as CFRS[]. Instead, it is a stack-based, postfix canvas colouring language with only 36 simple commands. The canvas overflow bug described in the previous entry affected this project as well. That has now been fixed. Further, by popular demand, the maximum allowed code length has been increased from 256 bytes to 1024 bytes. This means there is now more room for writing more complex FXYT programs. Additionally, the maximum code length for distributable demo links has been increased from 64 bytes to 256 bytes. This allows several more impressive demos to have their own distributable links. Visit FXYT to try it out now. See also the Community Demos to view some fascinating artwork created by the community. Nerd Quiz : This is a new project I created a couple of months ago. It is a simple HTML tool that lets you test your nerdiness through short quizzes. Each question is drawn from my everyday moments of reading, writing, thinking, learning, and exploring. The project is meant to serve as a repository of interesting facts I come across in daily life, captured in the form of quiz questions. Go here to try it out: Nerd Quiz . I hope you will enjoy these little bits of knowledge as much as I enjoyed discovering them. Mark V. Shaney Junior : Finally, I have my own Markov gibberish generator. Always wanted to have one. The project is inspired by the legendary Usenet bot named Mark V. Shaney that used to post messages to various newsgroups in the 1980s. My Markov chain program is written in about 30 lines of Python. I ran it on my 24 years of blog posts consisting of over 200 posts and about 200,000 words and it generated some pretty interesting gibberish. See my blog post Fed 24 Years of My Posts to Markov Model to see the examples. Elliptical Python Programming : If the previous item was not silly enough, this one surely is. Earlier this year, I wrote a blog post describing the fine art of Python programming using copious amounts of ellipses. I will not discuss it further here to avoid spoilers. I'll just say that any day I'm able to do something pointless, whimsical and fun with computers is a good day for me. And it was a good day when I wrote this post. Please visit the link above to read the post. I hope you find it fun. Fizz Buzz with Cosines : Another silly post in which I explain how to compute the discrete Fourier transform of the Fizz Buzz sequence and derive a closed-form expression that can be used to print the sequence. Fizz Buzz in CSS : Yet another Fizz Buzz implementation, this time using just four lines of CSS. That wraps up my coding adventures for this year. There were fewer hobby projects than usual but I enjoyed spending more time learning new things and revisiting old ones. One long-running project came to an end, another was cleaned up and a few small new ideas appeared along the way. Looking forward to what the next year brings. Read on website | #programming | #technology | #retrospective MathB : The year began not with the release of a new project but with the opposite: discontinuing a project I had maintained for 13 years. MathB.in, a mathematics pastebin service, was discontinued early this year. This is a project I developed in 2012 for myself and my friends. Although a rather simple project, it was close to my heart, as I have many fond memories of exchanging mathematical puzzles and solutions with my friends using this service. Over time, the project grew quite popular on IRC networks, as well as in some schools and universities, where IRC users, learners, and students used the service to share problems and solutions with one another, much as my friends and I had done in its early days. I shut it down this year because I wanted to move on from the project. Before the shutdown, a kind member of the Archive Team worked with me to archive all posts from the now-defunct website. Although shutting down this service was a bittersweet event for me, I feel relieved that I no longer have to run a live service in my spare time. While this was a good hobby ten years ago, it no longer is. See my blog post MathB.in Is Shutting Down for more details on the reasons behind this decision. The source code of this project remains open source and available at github.com/susam/mathb . QuickQWERTY : This is a touch-typing tutor that runs in a web browser. I originally developed it in 2008 for myself and my friends. While I learned touch typing on an actual typewriter as a child, those lessons did not stick with me. Much later, while I was at university, I came across a Java applet-based touch-typing tutor that finally helped me learn touch typing properly. I disliked installing Java plugins in the web browser, which is why I later developed this project in plain HTML and JavaScript. This year, I carried out a major refactoring to collapse the entire project into a single standalone HTML file with no external dependencies. The source code has been greatly simplified as well. When I was younger and more naive, inspired by the complexity and multiple layers of abstraction I saw in popular open source and professional projects, I tended to introduce similar abstractions and complexity into my personal projects. Over time, however, I began to appreciate simplicity. The new code for this project is smaller and simpler, and I am quite happy with the end result. You can take a look at the code here: quickqwerty.html . If you want to use the typing tutor, go here: QuickQWERTY . Unfortunately, it does not support keyboard layouts other than QWERTY. When I originally developed this project, my view of the computing world was rather limited. I was not even aware that other keyboard layouts existed. You are, however, very welcome to fork the project and adapt the lessons for other layouts. CFRS[] : This project was my first contribution to the quirky world of esolangs. CFRS[] is an extremely minimal drawing language consisting of only six simple commands: , , , , , and . I developed it in 2023 and have since been maintaining it with occasional bug fixes. This year, I fixed an annoying bug that caused the drawing canvas to overflow on some mobile web browsers. A new demo also arrived from the community this year and has now been added to the community demo page. See Glimmering Galaxy for the new demo. If you want to play with CFRS[] now, visit CFRS[] . FXYT : This is another esolang project of mine. This too is a minimal drawing language, though not as minimal as CFRS[]. Instead, it is a stack-based, postfix canvas colouring language with only 36 simple commands. The canvas overflow bug described in the previous entry affected this project as well. That has now been fixed. Further, by popular demand, the maximum allowed code length has been increased from 256 bytes to 1024 bytes. This means there is now more room for writing more complex FXYT programs. Additionally, the maximum code length for distributable demo links has been increased from 64 bytes to 256 bytes. This allows several more impressive demos to have their own distributable links. Visit FXYT to try it out now. See also the Community Demos to view some fascinating artwork created by the community. Nerd Quiz : This is a new project I created a couple of months ago. It is a simple HTML tool that lets you test your nerdiness through short quizzes. Each question is drawn from my everyday moments of reading, writing, thinking, learning, and exploring. The project is meant to serve as a repository of interesting facts I come across in daily life, captured in the form of quiz questions. Go here to try it out: Nerd Quiz . I hope you will enjoy these little bits of knowledge as much as I enjoyed discovering them. Mark V. Shaney Junior : Finally, I have my own Markov gibberish generator. Always wanted to have one. The project is inspired by the legendary Usenet bot named Mark V. Shaney that used to post messages to various newsgroups in the 1980s. My Markov chain program is written in about 30 lines of Python. I ran it on my 24 years of blog posts consisting of over 200 posts and about 200,000 words and it generated some pretty interesting gibberish. See my blog post Fed 24 Years of My Posts to Markov Model to see the examples. Elliptical Python Programming : If the previous item was not silly enough, this one surely is. Earlier this year, I wrote a blog post describing the fine art of Python programming using copious amounts of ellipses. I will not discuss it further here to avoid spoilers. I'll just say that any day I'm able to do something pointless, whimsical and fun with computers is a good day for me. And it was a good day when I wrote this post. Please visit the link above to read the post. I hope you find it fun. Fizz Buzz with Cosines : Another silly post in which I explain how to compute the discrete Fourier transform of the Fizz Buzz sequence and derive a closed-form expression that can be used to print the sequence. Fizz Buzz in CSS : Yet another Fizz Buzz implementation, this time using just four lines of CSS.

0 views
Susam Pal 1 months ago

Mark V. Shaney Junior 0.2.0

Mark V. Shaney Junior 0.2.0 is the second release of this little Markov gibberish generator. This release brings two small changes. First, it now reads the training data from standard input instead of a hardcoded file. Second, the program filename has been changed from to to reflect that it is an executable file and can be run as on most Unix and Linux systems. The source and a detailed documentation for this project are available at github.com/susam/mvs . See also this related blog post and a discussion on Hacker News about it. Read on website | #python | #programming | #technology

1 views
Susam Pal 1 months ago

I Fed 24 Years of My Blog Posts to a Markov Model

Yesterday I shared a little program called Mark V. Shaney Junior at github.com/susam/mvs . It is a minimal implementation of a Markov text generator inspired by the legendary Mark V. Shaney program from the 1980s. If you don't know about Mark V. Shaney, read more about it on the Wikipedia article Mark V. Shaney . It is a very small program with only about 30 lines of Python that favours simplicity over efficiency. As a hobby, I often engage in exploratory programming where I write computer programs not to solve a specific problem but simply to explore a particular idea or topic for the sole purpose of recreation. I must have written small programs to explore Markov chains for various kinds of state spaces over a dozen times by now. Every time, I just pick my last experimental code and edit it to encode the new state space I am exploring. That's usually my general approach to such one-off programs. I have hundreds of tiny little experimental programs lying on my disk at any given time. Once in a while, I get the itch to take one of those exploratory programs, give it some finishing touches, wrap it up in a nice Git repo along with a , and the whole shebang and share it on github.com/susam and codeberg.org/susam . The Mark V. Shaney Junior program that I shared yesterday happened to be one such exercise. If you scroll down the README of this project, you'll find some nice examples of the gibberish produced by this program. The first few examples there are the result of training the model on A Christmas Carol by Charles Dickens, one of my favourite authors. It is often said that Dickens never used fewer words when more would suffice. So I thought there couldn't be a better piece of text when it comes to testing out my tiny Markov model. I'll not reproduce the generated text examples here for the sake of brevity. If you are interested to take a look, just head over to the Gibberish section of the README. Soon after sharing the project, I wondered what kind of gibberish it would produce if I fed all 24 years of my blog posts and pages into the program. Well, here's one of the results: This is the text that comes out after the program consumes over 200 posts consisting of about 200,000 words. My blog also has a comments section with over 500 comments consisting of about 40,000 words. All comments were excluded while training the model. Here is another output example: Here is a particularly incoherent but amusing one: No, I have never said anywhere that opening a Lisp source file could harm anyone's self-esteem. The text generator has picked up the 'Lisp source file' phrase from my Lisp in Vim post and the 'self-esteem' bit from the From Perl to Pi post. By default, this program looks at trigrams (all sequences of three adjacent words) and creates a map where the first two words of the trigram are inserted as the key and the third word is appended to its list value. This map is the model. In this way, the model captures each pair of adjacent words along with the words that immediately follow each pair. The text generator then chooses a key (a pair of words) at random and looks for a word which follows. If there are multiple followers, it picks one at random. That is pretty much the whole algorithm. There isn't much more to it. It is as simple as it gets. For that reason, I often describe a simple Markov model like this as the 'hello, world' for language models. Of course, in 2025, given the overwhelming popularity of large language models (LLMs), Markov models like this look unimpressive. Unlike LLMs, a simple Markov model cannot capture global structure or long-range dependencies within the text. It relies entirely on local word transition statistics. Also, these days, one hardly needs a Markov model to generate gibberish; social media provides an ample supply. Nevertheless, I think the simplicity of its design and implementation serves as a good entry point into language models. In my implementation, the number of words in the key of the map can be set via command line arguments. By default, it is 2 as described above. This value is also known as the order of the model. So by default the order is 2. If we increase it to, say, 3 or 4, the generated text becomes a little more coherent. Here is one such example: Except for a couple of abrupt and meaningless transitions, the text is mostly coherent. We need to be careful about not increasing the order too much. In fact, if we increase the order of the model to 5, the generated text becomes very dry and factual because it begins to quote large portions of the blog posts verbatim. Not much fun can be had with that. Before I end this post, let me present one final example where I ask it to generate text from an initial prompt: Apparently, this is how I would sound if I ever took up speaking gibberish! Read on website | #python | #programming | #technology

1 views
Susam Pal 1 months ago

Mark V. Shaney Junior 0.1.0

Mark V. Shaney Junior is a minimal implementation of a Markov gibberish generator inspired by the legendary Mark V. Shaney program from the 1980s. Mark V. Shaney was a synthetic Usenet user in the 1980s that posted messages to newsgroups using text generated by a Markov chain program. See the Wikipedia article Mark V. Shaney for more details. This release introduces the program mvs.py that implements a similar Markov text generator. It reads a text corpus of text from standard input, build an internal Markov model and then generate text using the model. Please visit github.com/susam/mvs for the source code and some output examples. Read on website | #python | #programming | #technology

0 views
Susam Pal 1 months ago

Fizz Buzz in CSS

How many CSS selectors and declarations do we need to produce the Fizz Buzz sequence? Of course we could do this with no CSS at all simply by placing the entire sequence as text in the HTML body. So to make the problem precise as well as to keep it interesting, we require that all text that appears in the Fizz Buzz sequence comes directly from the CSS. Placing any part of the output numbers or words outside the stylesheet is not allowed. JavaScript is not allowed either. With these constraints, I think we need at least four CSS selectors along with four declarations to solve this puzzle, as shown below: Here is a complete working example: css-fizz-buzz.html . The above solution contains four CSS rules with one selector and one declaration in each rule. For example, is one rule consisting of the selector and the declaration . Seasoned code golfers looking for a challenge can probably shrink this solution further. A common trick to solve this problem is to use an ordered list ( ) which provides the integers in the form of list markers automatically, thereby eliminating the need to maintain a counter in the stylesheet. However, this violates the requirement set out in the introduction. We want every integer to be produced directly by the stylesheet. Treating the integers in the list markers as part of the output sequence breaks this rule. Not to mention the output looks untidy because of the unnecessary dot after each marker and also because the numbers and words appear misaligned. See an example of that trick here: css-fizz-buzz-ol.html . Correcting the misaligned output calls for extra code that cancels out the number of declarations saved. In any case, the requirement that all integers of the output must come directly from the stylesheet prevents untidy solutions like this and also forces us to rely on the capabilities of CSS to solve this puzzle. The intention here was to obtain the smallest possible code in terms of the number of CSS declarations. This example is not crafted to minimise bytes, but for code golfers who enjoy reducing byte count, here is the number of bytes this solution consumes after removing all whitespace: Further reduction in byte count can be achieved by using the element instead of , nesting CSS selectors, etc. I'll leave that as an exercise for the reader. Returning to the focus of this post as well as to summarise it, the solution here uses four CSS rules consisting of four selectors and four declarations to render the Fizz Buzz sequence. Read on website | #absurd | #web | #technology | #puzzle

0 views
Susam Pal 1 months ago

CSS Fizz Buzz with Ordered List

A version of my CSS Fizz Buzz that uses ordered list ( ) to reduce code. However, I don't quite like how misaligned the numbers and the words look. Correcting that would call for extra code that would cancel out the bytes saved. Read on website | #web

0 views
Susam Pal 1 months ago

Triangle-Free Cayley Graph

In this note I elaborate the proof of a claim regarding Cayley graphs of symmetric groups with transpositions as generators that I found in the book Algebraic Graph Theory by Chris Godsil and Gordon Royle. This claim appears as commentary in Section 3.10 about Transpositions . Here I present it in the form of a theorem along with a complete proof. Theorem. If \( \mathcal{T} \) is a set of transpositions, then the Cayley graph \( X(\operatorname{Sym}(n), \mathcal{T}) \) has no triangles. Proof. Suppose the vertices \( a, b, c \in \operatorname{Sym}(n) \) form a triangle in the Cayley graph \( X(\operatorname{Sym}(n), \mathcal{T}). \) Since multiplication by \( a^{-1} \) is an automorphism of the Cayley graph (by the proof of Theorem 3.1.2 that comes earlier), the vertices \( e, ba^{-1}, ca^{-1} \) form a triangle too. Let us label them as \( e, b', c' \) respectively. Now by the definition of a Cayley graph, for any two vertices \( a, b \in \operatorname{Sym}(n), \) we have \begin{align*} a \sim b & \iff ba^{-1} \in \mathcal{T} \\ & \iff ba^{-1} = g \\ & \iff b = ga \end{align*} for some \( g \in \mathcal{T}. \) Therefore \begin{align*} e \sim b' & \iff b' = ge = g, \\ e \sim c' & \iff c' = he = h, \\ b' \sim c' & \iff c' = lb' \end{align*} for some \( g, h, l \in \mathcal{T}. \) Note that the last equality gives \[ l =c'b'^{-1} = hg^{-1} = hg \in \mathcal{T} \] Therefore \( g, h, hg \in \mathcal{T}. \) However, this is impossible since the product of two transpositions is \( e, \) a \( 3 \)-cycle or a product of two disjoint transpositions. For example, \( (12)(12) = e, \) \( (12)(13) = (123) \) and \( (12)(24) = (12)(24). \) Therefore \( hg \) cannot be a transposition, i.e. \( hg \notin \mathcal{T}. \) This is a contradiction. Therefore the vertices \( a, b, c \) cannot form a triangle. We conclude that the Cayley graph \( X(\operatorname{Sym}(n), \mathcal{T}) \) has no triangles. Read on website | #mathematics

0 views
Susam Pal 1 months ago

Emacs Info Expressions

On IRC or Matrix channels, we often share references to the built-in Emacs documentation as Elisp expressions that look like this: Here is another example: This is a common practice in the Emacs community even though all of the Emacs manual is available on the World Wide Web too. For example, the section referred to in the above expression eis available here: GNU Emacs Manual: Word Search . The reason for sharing Elisp expressions like this is likely partly tradition and partly convenience. Many Emacs users are logged into IRC networks via Emacs itself, so once the recipient sees an Elisp expression like the above one in their chat buffer, visiting the corresponding manual page is a simple matter of placing the cursor right after the closing parenthesis and typing . But isn't it clumsy for the sender to type Elisp expressions like this merely to share a pointer to a section of a manual with others? Turns out, it is not. This is Emacs! So of course there are key-bindings to do this. Say, while helping another Emacs user we type and land on the section "Branches" and realise that this is the section that the person we are trying to help should read. Now when we are on this section, we can simply type and Emacs will copy the name of the current Info node to the kill ring. The name looks like this: While this is handy in some situations, it isn't the expression we want. It's just the Info node name. To copy the complete expression with the node name, we need to use the zero prefix argument with the key. So when we are on the section "Branches", if we type , the following expression is copied to the kill ring: The person who receives this expression can visit the corresponding section of the manual simply by evaluating it. For example, after copying the expression in Emacs, they could type to paste the expression into a buffer and evaluate it immediately. Alternatively, they might want to type to bring the minibuffer, paste the expression there and evaluate it. Read on website | #emacs | #technology

0 views
Susam Pal 1 months ago

Fizz Buzz with Cosines

Fizz Buzz is a counting game that has become oddly popular in the world of computer programming as a simple test of basic programming skills. The rules of the game are straightforward. Players say the numbers aloud in order beginning with one. Whenever a number is divisible by 3, they say 'Fizz' instead. If it is divisible by 5, they say 'Buzz'. If it is divisible by both 3 and 5, the player says both 'Fizz' and 'Buzz'. Here is a typical Python program that prints this sequence: Here is the output: fizz-buzz.txt . 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? Trigonometric functions! Perhaps we can use trigonometric functions to encode all four rules of the sequence in a single closed-form expression. That is what we are going to explore in this article, for fun and no profit. By the end, we will obtain a discrete Fourier series that can take any integer \( n \) and select the corresponding text to be printed. In fact, we will derive it using two different methods. First, we will follow a long-winded but hopefully enjoyable approach that relies on a basic understanding of complex exponentiation, geometric series and trigonometric functions. Then, we will obtain the same result through a direct application of the discrete Fourier transform. Before going any further, we establish a precise mathematical definition for the Fizz Buzz sequence. We begin by introducing a few functions that will help us define the Fizz Buzz sequence later. We define a set of four functions \( \{ s_0, s_1, s_2, s_3 \} \) for integers \( n \) by: \begin{align*} s_0(n) &= n, \\ s_1(n) &= \mathtt{Fizz}, \\ s_2(n) &= \mathtt{Buzz}, \\ s_3(n) &= \mathtt{FizzBuzz}. \end{align*} We call these the symbol functions because they produce every term that appears in the Fizz Buzz sequence. The symbol function \( s_0 \) returns \( n \) itself. The functions \( s_1, \) \( s_2 \) and \( s_3 \) are constant functions that always return the literal words \( \mathtt{Fizz}, \) \( \mathtt{Buzz} \) and \( \mathtt{FizzBuzz} \) respectively, no matter what the value of \( n \) is. We define a function \( f(n) \) for integer \( n \) by \[ f(n) = \begin{cases} 1 & \text{if } 3 \mid n \text{ and } 5 \nmid n, \\ 2 & \text{if } 3 \nmid n \text{ and } 5 \mid n, \\ 3 & \text{if } 3 \mid n \text{ and } 5 \mid n, \\ 0 & \text{otherwise}. \end{cases} \] The notation \( m \mid n \) means that the integer \( m \) divides the integer \( n, \) i.e. \( n \) is a multiple of \( m. \) Equivalently, there exists an integer \( c \) such that \( n = cm . \) Similarly, \( m \nmid n \) means that \( m \) does not divide \( n, \) i.e. \( n \) is not a multiple of \( m. \) This function covers all four conditions involved in choosing the \( n \)th item of the Fizz Buzz sequence. As we will soon see, this function tells us which of the four symbol functions produces the \( n \)th item of the Fizz Buzz sequence. For this reason, we call \( f(n) \) the index function. We now define the Fizz Buzz sequence as the sequence \[ (s_{f(n)}(n))_{n = 1}^{\infty} \] We can expand the first few terms of the sequence explicitly as follows: \begin{align*} (s_{f(n)}(n))_{n = 1}^{\infty} &= (s_{f(1)}(1), \; s_{f(2)}(2), \; s_{f(3)}(3), \; s_{f(4)}(4), \; s_{f(5)}(5), \; s_{f(6)}(6), \; s_{f(7)}(7), \; \dots) \\ &= (s_0(1), \; s_0(2), \; s_1(3), \; s_0(4), s_2(5), \; s_1(6), \; s_0(7), \; \dots) \\ &= (1, \; 2, \; \mathtt{Fizz}, \; 4, \; \mathtt{Buzz}, \; \mathtt{Fizz}, \; 7, \; \dots). \end{align*} Note how the function \( f(n) \) produces an index \( i \) which we then use to select the symbol function \( s_i(n) \) to produce the \( n \)th term of the sequence. This is precisely why we decided to call \( f(n) \) the index function while defining it in the previous section. Here we discuss the first method of deriving our closed form expression, starting with indicator functions and rewriting them using complex exponentials and cosines. Here is the index function \( f(n) \) from the previous section with its cases and conditions rearranged to make it easier to spot interesting patterns: \[ f(n) = \begin{cases} 0 & \text{if } 5 \nmid n \text{ and } 3 \nmid n, \\ 1 & \text{if } 5 \nmid n \text{ and } 3 \mid n, \\ 2 & \text{if } 5 \mid n \text{ and } 3 \nmid n, \\ 3 & \text{if } 5 \mid n \text{ and } 3 \mid n. \end{cases} \] This function helps us select another function \( s_{f(n)}(n) \) which in turn determines the \( n \)th term of the Fizz Buzz sequence. Our goal now is to replace this piecewise formula with a single closed-form expression. To do so, we first define indicator functions \( I_m(n) \) as follows: \[ I_m(n) = \begin{cases} 1 & \text{if } m \mid n, \\ 0 & \text{if } m \nmid n. \end{cases} \] The formula for \( f(n) \) can now be written as: \[ f(n) = \begin{cases} 0 & \text{if } I_5(n) = 0 \text{ and } I_3(n) = 0, \\ 1 & \text{if } I_5(n) = 0 \text{ and } I_3(n) = 1, \\ 2 & \text{if } I_5(n) = 1 \text{ and } I_3(n) = 0, \\ 3 & \text{if } I_5(n) = 1 \text{ and } I_3(n) = 1. \end{cases} \] Do you see a pattern? Here is the same function written as a table: Do you see it now? If we treat the values in the first two columns as binary digits and the values in the third column as decimal numbers, then in each row the first two columns give the binary representation of the number in the third column. For example, \( 3_{10} = 11_2 \) and indeed in the last row of the table, we see the bits \( 1 \) and \( 1 \) in the first two columns and the number \( 3 \) in the last column. In other words, writing the binary digits \( I_5(n) \) and \( I_3(n) \) side by side gives us the binary representation of \( f(n). \) Therefore \[ f(n) = 2 \, I_5(n) + I_3(n). \] We can now write a small program to demonstrate this formula: We can make it even shorter at the cost of some clarity: What we have obtained so far is pretty good. While there is no universal definition of a closed-form expression, I think most people would agree that the indicator functions as defined above are simple enough to be permitted in a closed-form expression. In the previous section, we obtained the formula \[ f(n) = I_3(n) + 2 \, I_5(n) \] which we then used as an index to look up the text to be printed. We also argued that this is a pretty good closed-form expression already. However, in the interest of making things more complicated, we must ask ourselves: What if we are not allowed to use the indicator functions? What if we must adhere to the commonly accepted meaning of a closed-form expression which allows only 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. It turns out that the above formula can be rewritten using only addition, multiplication, division and the cosine function. Let us begin the translation. Consider the sum \[ S_m(n) = \sum_{k = 0}^{m - 1} e^{i 2 \pi k n / m}, \] where \( i \) is the imaginary unit and \( n \) and \( m \) are integers. This is a geometric series in the complex plane with ratio \( r = e^{i 2 \pi n / m}. \) If \( n \) is a multiple of \( m , \) then \( n = cm \) for some integer \( c \) and we get \[ r = e^{i 2 \pi n / m} = e^{i 2 \pi c} = 1. \] Therefore, when \( n \) is a multiple of \( m, \) we get \[ S_m(n) = \sum_{k = 0}^{m - 1} e^{i 2 \pi k n / m} = \sum_{k = 0}^{m - 1} 1^k = m. \] If \( n \) is not a multiple of \( m, \) then \( r \ne 1 \) and the geometric series becomes \[ S_m(n) = \frac{r^m - 1}{r - 1} = \frac{e^{i 2 \pi n} - 1}{e^{i 2 \pi n / m} - 1} = 0. \] Therefore, \[ S_m(n) = \begin{cases} m & \text{if } m \mid n, \\ 0 & \text{if } m \nmid n. \end{cases} \] Dividing both sides by \( m, \) we get \[ \frac{S_m(n)}{m} = \begin{cases} 1 & \text{if } m \mid n, \\ 0 & \text{if } m \nmid n. \end{cases} \] But the right-hand side is \( I_m(n). \) Therefore \[ I_m(n) = \frac{S_m(n)}{m} = \frac{1}{m} \sum_{k = 0}^{m - 1} e^{i 2 \pi k n / m}. \] We begin with Euler's formula \[ e^{i x} = \cos x + i \sin x \] where \( x \) is a real number. From this formula, we get \[ e^{i x} + e^{-i x} = 2 \cos x. \] Therefore \begin{align*} I_3(n) &= \frac{1}{3} \sum_{k = 0}^2 e^{i 2 \pi k n / 3} \\ &= \frac{1}{3} \left( 1 + e^{i 2 \pi n / 3} + e^{i 4 \pi n / 3} \right) \\ &= \frac{1}{3} \left( 1 + e^{i 2 \pi n / 3} + e^{-i 2 \pi n / 3} \right) \\ &= \frac{1}{3} + \frac{2}{3} \cos \left( \frac{2 \pi n}{3} \right). \end{align*} The third equality above follows from the fact that \( e^{i 4 \pi n / 3} = e^{i 6 \pi n / 3} e^{-i 2 \pi n / 3} = e^{i 2 \pi n} e^{-i 2 \pi n/3} = e^{-i 2 \pi n / 3} \) when \( n \) is an integer. The function above is defined for integer values of \( n \) but we can extend its formula to real \( x \) and plot it to observe its shape between integers. As expected, the function takes the value \( 1 \) whenever \( x \) is an integer multiple of \( 3 \) and \( 0 \) whenever \( x \) is an integer not divisible by \( 3. \) Similarly, \begin{align*} I_5(n) &= \frac{1}{5} \sum_{k = 0}^4 e^{i 2 \pi k n / 5} \\ &= \frac{1}{5} \left( 1 + e^{i 2 \pi n / 5} + e^{i 4 \pi n / 5} + e^{i 6 \pi n / 5} + e^{i 8 \pi n / 5} \right) \\ &= \frac{1}{5} \left( 1 + e^{i 2 \pi n / 5} + e^{i 4 \pi n / 5} + e^{-i 4 \pi n / 5} + e^{-i 2 \pi n / 5} \right) \\ &= \frac{1}{5} + \frac{2}{5} \cos \left( \frac{2 \pi n}{5} \right) + \frac{2}{5} \cos \left( \frac{4 \pi n}{5} \right). \end{align*} Extending this expression to real values of \( x \) allows us to plot its shape as well. Once again, the function takes the value \( 1 \) at integer multiples of \( 5 \) and \( 0 \) at integers not divisible by \( 5. \) Recall that we expressed \( f(n) \) as \[ f(n) = I_3(n) + 2 \, I_5(n). \] Substituting these trigonometric expressions yields \[ f(n) = \frac{1}{3} + \frac{2}{3} \cos \left( \frac{2 \pi n}{3} \right) + 2 \cdot \left( \frac{1}{5} + \frac{2}{5} \cos \left( \frac{2 \pi n}{5} \right) + \frac{2}{5} \cos \left( \frac{4 \pi n}{5} \right) \right). \] A straightforward simplification gives \[ f(n) = \frac{11}{15} + \frac{2}{3} \cos \left( \frac{2 \pi n}{3} \right) + \frac{4}{5} \cos \left( \frac{2 \pi n}{5} \right) + \frac{4}{5} \cos \left( \frac{4 \pi n}{5} \right). \] We can extend this expression to real \( x \) and plot it as well. The resulting curve takes the values \( 0, 1, 2 \) and \( 3 \) at integer points, as desired. Now we can write our Python program as follows: The keen-eyed might notice that the expression we obtained for \( f(n) \) is a discrete Fourier series. This is not surprising, since the output of a Fizz Buzz program depends only on \( n \bmod 15. \) Any function on a finite cyclic group can be written exactly as a finite Fourier expansion. In this section, we obtain \( f(n) \) using the discrete Fourier transform. It is worth mentioning that the calculations presented here are quite tedious to do by hand. Nevertheless, this section offers a glimpse of how such calculations are performed. By the end, we will arrive at exactly the same \( f(n) \) as before. There is nothing new to discover here. We simply obtain the same result by a more direct but more laborious method. If this doesn't sound interesting, you may safely skip the subsections that follow. We know that \( f(n) \) is a periodic function with period \( 15. \) To apply the discrete Fourier transform, we look at one complete period of the function using the values \( n = 0, 1, \dots, 14. \) Over this period, we have: \begin{array}{c|ccccccccccccccc} n & 0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 & 11 & 12 & 13 & 14 \\ \hline f(n) & 3 & 0 & 0 & 1 & 0 & 2 & 1 & 0 & 0 & 1 & 2 & 0 & 1 & 0 & 0 \end{array} The discrete Fourier series of \( f(n) \) is \[ f(n) = \sum_{k = 0}^{14} c_k \, e^{i 2 \pi k n / 15} \] where the Fourier coefficients \( c_k \) are given by the discrete Fourier transform \[ c_k = \frac{1}{15} \sum_{n = 0}^{14} f(n) e^{-i 2 \pi k n / 15}. \] for \( k = 0, 1, \dots, 14. \) The formula for \( c_k \) is called the discrete Fourier transform (DFT). The formula for \( f(n) \) is called the inverse discrete Fourier transform (IDFT). Let \( \omega = e^{-i 2 \pi / 15}. \) Then using the values of \( f(n) \) from the table above, the DFT becomes: \[ c_k = \frac{3 + \omega^{3k} + 2 \omega^{5k} + \omega^{6k} + \omega^{9k} + 2 \omega^{10k} + \omega^{12k}}{15}. \] Substituting \( k = 0, 1, 2, \dots, 14 \) into the above equation gives us the following Fourier coefficients: \begin{align*} c_{0} &= \frac{11}{15}, \\ c_{3} &= c_{6} = c_{9} = c_{12} = \frac{2}{5}, \\ c_{5} &= c_{10} = \frac{1}{3}, \\ c_{1} &= c_{2} = c_{4} = c_{7} = c_{8} = c_{11} = c_{13} = c_{14} = 0. \end{align*} Calculating these Fourier coefficients by hand can be rather tedious. In practice they are almost always calculated using numerical software, computer algebra systems or even simple code such as the example here: fizz-buzz-fourier.py . Once the coefficients are known, we can substitute them into the inverse transform introduced earlier to obtain \begin{align*} f(n) &= \sum_{k = 0}^{14} c_k \, e^{i 2 \pi k n / 15} \\[1.5em] &= \frac{11}{15} + \frac{2}{5} \left( e^{i 2 \pi \cdot 3n / 15} + e^{i 2 \pi \cdot 6n / 15} + e^{i 2 \pi \cdot 9n / 15} + e^{i 2 \pi \cdot 12n / 15} \right) \\ & \phantom{=\frac{11}{15}} + \frac{1}{3} \left( e^{i 2 \pi \cdot 5n / 15} + e^{i 2 \pi \cdot 10n / 15} \right) \\[1em] &= \frac{11}{15} + \frac{2}{5} \left( e^{i 2 \pi \cdot 3n / 15} + e^{i 2 \pi \cdot 6n / 15} + e^{-i 2 \pi \cdot 6n / 15} + e^{-i 2 \pi \cdot 3n / 15} \right) \\ & \phantom{=\frac{11}{15}} + \frac{1}{3} \left( e^{i 2 \pi \cdot 5n / 15} + e^{-i 2 \pi \cdot 5n / 15} \right) \\[1em] &= \frac{11}{15} + \frac{2}{5} \left( 2 \cos \left( \frac{2 \pi n}{5} \right) + 2 \cos \left( \frac{4 \pi n}{5} \right) \right) \\ & \phantom{=\frac{11}{15}} + \frac{1}{3} \left( 2 \cos \left( \frac{2 \pi n}{3} \right) \right) \\[1em] &= \frac{11}{15} + \frac{4}{5} \cos \left( \frac{2 \pi n}{5} \right) + \frac{4}{5} \cos \left( \frac{4 \pi n}{5} \right) + \frac{2}{3} \cos \left( \frac{2 \pi n}{3} \right). \end{align*} This is exactly the same expression for \( f(n) \) we obtained in the previous section. We see that the Fizz Buzz index function \( f(n) \) can be expressed precisely using the machinery of Fourier analysis. To summarise, we have defined the Fizz Buzz sequence as \[ (s_{f(n)}(n))_{n = 1}^{\infty} \] where \[ f(n) = \frac{11}{15} + \frac{2}{3} \cos \left( \frac{2 \pi n}{3} \right) + \frac{4}{5} \cos \left( \frac{2 \pi n}{5} \right) + \frac{4}{5} \cos \left( \frac{4 \pi n}{5} \right). \] and \( s_0(n) = n, \) \( s_1(n) = \mathtt{Fizz}, \) \( s_2(n) = \mathtt{Buzz} \) and \( s_3(n) = \mathtt{FizzBuzz}. \) A Python program to print the Fizz Buzz sequence based on this definition was presented earlier. That program can be written more succinctly as follows: We can also wrap this up nicely in a shell one-liner, in case you want to share it with your friends and family and surprise them: We have taken a simple counting game and turned it into a trigonometric construction consisting of a discrete Fourier series with three cosine terms and four coefficients. None of this makes Fizz Buzz any easier. Quite the contrary. But it does show that every \( \mathtt{Fizz} \) and \( \mathtt{Buzz} \) now owes its existence to a particular set of Fourier coefficients. We began with the modest goal of making this simple problem more complicated. I think it is safe to say that we did not fall short. Read on website | #absurd | #python | #programming | #technology | #mathematics | #puzzle Definitions Symbol Functions Index Function Fizz Buzz Sequence From Indicator Functions to Cosines Indicator Functions Complex Exponentials Discrete Fourier Transform One Period of Fizz Buzz Fourier Coefficients Inverse Transform

0 views
Susam Pal 1 months ago

Nerd Quiz #2

Nerd Quiz #2 is the second release of Nerd Quiz, a single-page HTML application that invites you to gauge your nerd level through short, focused quiz sets. Each question is carefully crafted from everyday moments of reading, writing, thinking, learning and exploring. This release introduces five new questions drawn from a range of topics such as chess, graph theory and linguistics. To try the quiz, visit nq.html . Read on website | #web | #miscellaneous | #game

0 views
Susam Pal 3 months ago

Nerd Quiz

A nerdy, handcrafted quiz built from everyday moments of reading, writing, thinking, learning and exploring. Read on website | #web | #technology

0 views
Susam Pal 3 months ago

Nerd Quiz #1

Nerd Quiz #1 is the first release of Nerd Quiz, a single-page HTML application that lets you test your nerd level through short, focused quiz sets. Each question in the quiz is handcrafted from everyday moments of reading, writing, thinking, learning and exploring. To try the quiz now, visit nq.html . The source code of Nerd Quiz is available at github.com/susam/nq under the terms of the MIT licence. Read on website | #web | #miscellaneous | #game

0 views
Susam Pal 3 months ago

QuickQWERTY 1.2.0

QuickQWERTY 1.2.0 is now available. QuickQWERTY is a web-based touch typing tutor for QWERTY keyboards that runs directly in the web browser. This release brings small improvements to make the typing tutor smoother and the lessons more accurate. When you return to the application, it no longer needlessly redirects you back to Unit 1.1 if that was the last lesson you practised. Several lessons have received minor corrections. Units 7.2 and 7.3 no longer include the word "tyre", avoiding a preference for either British or American spelling. Units 9.2 and 9.3 now spell "orwellian" correctly. A factual error in Unit 17.4 has been fixed too. It previously said "89 is one more than 99", which now correctly reads "89 is one more than 88". Finally, switching between the 5-6 and 6-7 split layouts is now more reliable. In the previous release, pressing Esc to cancel the confirmation dialogue still caused the switch to go through. Now pressing Esc properly cancels the switch as expected. To try out the new release of QuickQWERTY, go to quickqwerty.html . Read on website | #web | #programming

0 views
Susam Pal 3 months ago

Reinstated My Guestbook After 20 Years

I have reinstated the guestbook on this website after 20 years! As I have written in the About page, this website began its life as an intranet portal in my university network back in 2001–2005. That portal first ran on Microsoft Personal Web Server (PWS) and later on Microsoft Internet Information Services (IIS), with the guestbook data stored in a Microsoft Access database. At the same time, I also maintained a small public website on the Internet, hosted on a subdomain provided by a free hosting service, where I published a subset of the articles from the intranet portal. Both the intranet portal and the public website had guestbooks. The guestbook on the public website was powered by a CGI script provided by the hosting service, which inserted each comment directly into the guestbook HTML page. As some of you might guess, yes, it was vulnerable to cross-site scripting, but that's beside the point. After leaving the university, I registered my own domain name and set up my current website on the World Wide Web and included some of the content from both the original intranet portal and the old public website. For some reason, though, I never thought to include a guestbook. And so this website went on without a guestbook for the next 20 years. Finally, in June 2025, I decided to bring the guestbook back. I already had a commenting system implemented for this website using Common Lisp and Hunchentoot, so I simply reused it for the guestbook. The server program accepts POST requests to receive comments and writes them to text files on the web server for manual review. The comments are then rendered as static HTML pages by my static site generator. In a way, it is less a comment system and more a static comment pages generator. Unfortunately, I could not restore all the comments from the original guestbooks. The ASP source code of my intranet portal as well as the guestbook database are now lost to time. Note that what I refer to as ASP here is now known as Classic ASP, to avoid confusion with ASP.NET. A CD-ROM backup eventually succumbed to disc rot and with it vanished the source code and the database. But a handful of comments had survived because they had found their way into other files and correspondence and I have now included them here. I had better luck with the guestbook of the old public website, from which I was able to recover a greater number of comments. It is still only a small fraction of what once existed, but it feels good to have even those fragments preserved. The new guestbook is now available here: Guestbook . I wasn't expecting anybody to notice the new guestbook. It is only mentioned in the About and Links pages, neither of which see much traffic. Here are a few examples: I love that your website has a guestbook! :D Love the guestbook! We need more of these. Makes you feel invited. It's a small addition to my website, but after two decades, it feels good to see the guestbook alive again and even better to see visitors enjoying it! Read on website | #web | #technology

0 views
Susam Pal 3 months ago

QuickQWERTY 1.1.0

There has been a new release of QuickQWERTY after over 10 years! QuickQWERTY is a web-based touch typing tutor for QWERTY keyboards that runs directly in the web browser. You can try it out here: quickqwerty.html . The new release, version 1.1.0 of QuickQWERTY, introduces a new input command named , which is a synoymn for the existing commands and used to restart the current lesson. Another input command named runs an internal suite of tests to validate that no lesson involves keys that have not been introduced in the current or prior lessons. Further, in this release, the application has been fully rewritten as a single standalone HTML file with no external dependencies and the source code has been greatly simplified. There are a number of other changes too. Words per minute (WPM) calculation has been refined so the first character, which starts the timer, is not counted. The guides have been enhanced. Keys to be pressed are now highlighted more clearly and reminders to return fingers to their home positions have been added to each guide. The confirmation dialogue for switching between 6-7 split and 5-6 split styles now uses the HTML element, replacing the dated prompt. In addition, when the application is opened without a fragment identifier in the URL, the most recently practised lesson loads automatically. The user interface has been simplified. The previous and next links ( and ) for navigating lessons have been removed, as they added little value and made the layout of the various user interface components more complex. The "Next lesson" advice link remains for moving to the next lesson when the current one is completed successfully. Tooltips showing additional typing metrics have also been removed due to limited usefulness. The lessons have been updated to remove spellings specific to American English. Care has been taken to use only words that are spelled the same in American and British English with one exception. The word "tyre", in its British English spelling, was mistakenly left in the lesson. That will be fixed in the next release. Finally, QuickQWERTY's licence has changed from the BSD-2-Clause licence to the MIT licence. The source code is available at github.com/susam/quickqwerty . To run this release and learn touch typing on a QWERTY keyboard, go to quickqwerty.html . Read on website | #web | #programming

0 views
Susam Pal 4 months ago

My Lobsters Interview

I recently had an engaging conversation with Alex ( @veqq ) from the Lobsters community about computing, mathematics and a range of related topics. Our conversation was later published on the community website as Lobsters Interview with Susam . I should mention the sections presented in that post are not in the same order in which we originally discussed them. The sections were edited and rearranged by Alex to improve the flow and avoid repetition of similar topics too close to each other. This page preserves a copy of our discussion as edited by Alex, so I can keep an archived version on my website. In my copy, I have added a table of contents to make it easier to navigate to specific sections. The interview itself follows the table of contents. I hope you enjoy reading it. Hi @susam , I primarily know you as a Lisper, what other things do you use? Yes, I use Lisp extensively for my personal projects and much of what I do in my leisure is built on it. I ran a mathematics pastebin for close to thirteen years. It was quite popular on some IRC channels. The pastebin was written in Common Lisp. My personal website and blog are generated using a tiny static site generator written in Common Lisp. Over the years I have built several other personal tools in it as well. I am an active Emacs Lisp programmer too. Many of my software tools are in fact Emacs Lisp functions that I invoke with convenient key sequences. They help me automate repetitive tasks as well as improve my text editing and task management experience. I use plenty of other tools as well. In my early adulthood, I spent many years working with C, C++, Java and PHP. My first substantial open source contribution was to the Apache Nutch project which was in Java and one of my early original open source projects was Uncap , a C program to remap keys on Windows. These days I use a lot of Python, along with some Go and Rust, but Lisp remains important to my personal work. I also enjoy writing small standalone tools directly in HTML and JavaScript, often with all the code in a single file in a readable, unminified form. How did you first discover computing, then end up with Lisp, Emacs and mathematics? I got introduced to computers through the Logo programming language as a kid. Using simple arithmetic, geometry, logic and code to manipulate a two-dimensional world had a lasting effect on me. I still vividly remember how I ended up with Lisp. It was at an airport during a long layover in 2007. I wanted to use the time to learn something, so I booted my laptop running Debian GNU/Linux 4.0 (Etch) and then started GNU CLISP 2.41. In those days, Wi-Fi in airports was uncommon. Smartphones and mobile data were also uncommon. So it was fortunate that I had CLISP already installed on my system and my laptop was ready for learning Common Lisp. I had it installed because I had wanted to learn Common Lisp for some time. I was especially attracted by its simplicity, by the fact that the entire language can be built up from a very small set of special forms. I use SBCL these days, by the way. I discovered Emacs through Common Lisp. Several sources recommended using the Superior Lisp Interaction Mode for Emacs (SLIME) for Common Lisp programming, so that's where I began. For many years I continued to use Vim as my primary editor, while relying on Emacs and SLIME for Lisp development. Over time, as I learnt more about Emacs itself, I grew fond of Emacs Lisp and eventually made Emacs my primary editor and computing environment. I have loved mathematics since my childhood days. What has always fascinated me is how we can prove deep and complex facts using first principles and clear logical steps. That feeling of certainty and rigour is unlike anything else. Over the years, my love for the subject has been rekindled many times. As a specific example, let me share how I got into number theory. One day I decided to learn the RSA cryptosystem. As I was working through the RSA paper , I stumbled upon the Euler totient function \( \varphi(n) \) which gives the number of positive integers not exceeding n that are relatively prime to n. The paper first states that \[ \varphi(p) = p - 1 \] for prime numbers \( p. \) That was obvious since \( p \) has no factors other than \( 1 \) and itself, so every integer from \( 1 \) up to \( p - 1 \) must be relatively prime to it. But then it presents \[ \varphi(pq) = \varphi(p) \cdot \varphi(q) = (p - 1)(q - 1) \] for primes \( p \) and \( q. \) That was not immediately obvious to me back then. After a few minutes of thinking, I managed to prove it from scratch. By the inclusion-exclusion principle, we count how many integers from \( 1 \) up to \( pq \) are not divisible by \(p \) or \( q. \) There are \( pq \) integers in total. Among them, there are \( q \) integers divisible by \( p \) and \( p \) integers divisible by \( q. \) So we need to subtract \( p + q \) from \(pq. \) But since one integer (\( pq \) itself) is counted in both groups, we add \( 1 \) back. Therefore \[ \varphi(pq) = pq - (p + q) + 1 = (p - 1)(q - 1). \] Next I could also obtain the general formula for \( \varphi(n) \) for an arbitrary positive integer \( n \) using the same idea. There are several other proofs too, but that is how I derived the general formula for \( \varphi(n) \) when I first encountered it. And just like that, I had begun to learn number theory! You've said you prefer computing for fun. What is fun to you? Do you have an idea of what makes something fun or not? For me, fun in computing began when I first learnt IBM/LCSI PC Logo when I was nine years old. I had very limited access to computers back then, perhaps only about two hours per month in the computer laboratory at my primary school. Most of my Logo programming happened with pen and paper at home. I would "test" my programs by tracing the results on graph paper. Eventually I would get about thirty minutes of actual computer time in the lab to run them for real. So back then, most of my computing happened without an actual computer. But even with that limited access to computers, a whole new world opened up for me: one that showed me the joy of computing and more importantly, the joy of sharing my little programs with my friends and teachers. One particular Logo program I still remember very well drew a house with animated dashed lines, where the dashes moved around the outline of the house. Everyone around me loved it, copied it and tweaked it to change the colours, alter the details and add their own little touches. For me, fun in computing comes from such exploration and sharing. I enjoy asking "what happens if" and then seeing where it leads me. My Emacs package devil-mode comes from such exploration. It came from asking, "What happens if we avoid using the ctrl and meta modifier keys and use , (the comma key) or another suitable key as a leader key instead? And can we still have a non-modal editing experience?" Sometimes computing for fun may mean crafting a minimal esoteric drawing language, making a small game or building a tool that solves an interesting problem elegantly. It is a bonus if the exploration results in something working well enough that I can share with others on the World Wide Web and others find it fun too. How do you choose what to investigate? Which most interest you, with what commonalities? For me, it has always been one exploration leading to another. For example, I originally built MathB for my friends and myself who were going through a phase in our lives when we used to challenge each other with mathematical puzzles. This tool became a nice way to share solutions with each other. Its use spread from my friends to their friends and colleagues, then to schools and universities and eventually to IRC channels. Similarly, I built TeXMe when I was learning neural networks and taking a lot of notes on the subject. I was not ready to share the notes online, but I did want to share them with my friends and colleagues who were also learning the same topic. Normally I would write my notes in LaTeX, compile them to PDF and share the PDF, but in this case, I wondered, what if I took some of the code from MathB and created a tool that would let me write plain Markdown ( GFM ) + LaTeX ( MathJax ) in a file and have the tool render the file as soon as it was opened in a web browser? That resulted in TeXMe, which has surprisingly become one of my most popular projects, receiving millions of hits in some months according to the CDN statistics. Another example is Muboard , which is a bit like an interactive mathematics chalkboard. I built this when I was hosting an analytic number theory book club and I needed a way to type LaTeX snippets live on screen and see them immediately rendered. That made me wonder: what if I took TeXMe, made it interactive and gave it a chalkboard look-and-feel? That led to Muboard. So we can see that sharing mathematical notes and snippets has been a recurring theme in several of my projects. But that is only a small fraction of my interests. I have a wide variety of interests in computing. I also engage in random explorations, like writing IRC clients ( NIMB , Tzero ), ray tracing ( POV-Ray , Java ray tracer ), writing Emacs guides ( Emacs4CL , Emfy ), developing small single-file HTML games ( Andromeda Invaders , Guess My RGB ), purely recreational programming ( FXYT , may4.fs , self-printing machine code , prime number grid explorer ) and so on. The list goes on. When it comes to hobby computing, I don't think I can pick just one domain and say it interests me the most. I have a lot of interests. What is computing, to you? Computing, to me, covers a wide range of activities: programming a computer, using a computer, understanding how it works, even building one. For example, I once built a tiny 16-bit CPU along with a small main memory that could hold only eight 16-bit instructions, using VHDL and a Xilinx CPLD kit. The design was based on the Mano CPU introduced in the book Computer System Architecture (3rd ed.) by M. Morris Mano. It was incredibly fun to enter instructions into the main memory, one at a time, by pushing DIP switches up and down and then watch the CPU I had built execute an entire program. For someone like me, who usually works with software at higher levels of abstraction, that was a thrilling experience! Beyond such experiments, computing also includes more practical and concrete activities, such as installing and using my favourite Linux distribution (Debian), writing software tools in languages like Common Lisp, Emacs Lisp, Python and the shell command language or customising my Emacs environment to automate repetitive tasks. To me, computing also includes the abstract stuff like spending time with abstract algebra and number theory and getting a deeper understanding of the results pertaining to groups, rings and fields, as well as numerous number-theoretic results. Browsing the On-Line Encyclopedia of Integer Sequences (OEIS), writing small programs to explore interesting sequences or just thinking about them is computing too. I think many of the interesting results in computer science have deep mathematical foundations. I believe much of computer science is really discrete mathematics in action. And if we dive all the way down from the CPU to the level of transistors, we encounter continuous mathematics as well, with non-linear voltage-current relationships and analogue behaviour that make digital computing possible. It is fascinating how, as a relatively new species on this planet, we have managed to take sand and find a way to use continuous voltages and currents in electronic circuits built with silicon and convert them into the discrete operations of digital logic. We have machines that can simulate themselves! To me, all of this is fun. To study and learn about these things, to think about them, to understand them better and to accomplish useful or amusing results with this knowledge is all part of the fun. How do you view programming vs. domains? I focus more on the domain than the tool. Most of the time it is a problem that catches my attention and then I explore it to understand the domain and arrive at a solution. The problem itself usually points me to one of the tools I already know. For example, if it is about working with text files, I might write an Emacs Lisp function. If it involves checking large sets of numbers rapidly for patterns, I might choose C++ or Rust. But if I want to share interactive visualisations of those patterns with others, I might rewrite the solution in HTML and JavaScript, possibly with the use of the Canvas API, so that I can share the work as a self-contained file that others can execute easily within their web browsers. When I do that, I prefer to keep the HTML neat and readable, rather than bundled or minified, so that people who like to 'View Source' can copy, edit and customise the code themselves to immediately see their changes take effect. Let me share a specific example. While working on a web-based game, I first used 's to display text on the game canvas. However, dissatisfied with the text rendering quality, I began looking for IBM PC OEM fonts and similar retro fonts online. After downloading a few font packs, I wrote a little Python script to convert them to bitmaps (arrays of integers) and then used the bitmaps to draw text on the canvas using JavaScript, one cell at a time, to get pixel-perfect results! These tiny Python and JavaScript tools were good enough that I felt comfortable sharing them together as a tiny toolkit called PCFace . This toolkit offers JavaScript bitmap arrays and tiny JavaScript rendering functions, so that someone else who wants to display text on their game canvas using PC fonts and nothing but plain HTML and JavaScript can do so without having to solve the problem from scratch! Has the rate of your making new Emacs functions has diminished over time (as if everything's covered) or do the widening domains lead to more? I'm curious how applicable old functionality is for new problems and how that impacts the APIs! My rate of making new Emacs functions has definitely decreased. There are two reasons. One is that over the years my computing environment has converged into a comfortable, stable setup I am very happy with. The other is that at this stage of life I simply cannot afford the time to endlessly tinker with Emacs as I did in my younger days. More generally, when it comes to APIs, I find that well-designed functionality tends to remain useful even when new problems appear. In Emacs, for example, many of my older functions continue to serve me well because they were written in a composable way. New problems can often be solved with small wrappers or combinations of existing functions. I think APIs that consist of functions that are simple, orthogonal and flexible age well. If each function in an API does one thing and does it well (the Unix philosophy), it will have long-lasting utility. Of course, new domains and problems do require new functions and extensions to an API, but I think it is very important to not give in to the temptation of enhancing the existing functions by making them more complicated with optional parameters, keyword arguments, nested branches and so on. Personally, I have found that it is much better to implement new functions that are small, orthogonal and flexible, each doing one thing and doing it well. What design methods or tips do you have, to increase composability? For me, good design starts with good vocabulary. Clear vocabulary makes abstract notions concrete and gives collaborators a shared language to work with. For example, while working on a network events database many years ago, we collected data minute by minute from network devices. We decided to call each minute of data from a single device a "nugget". So if we had 15 minutes of data from 10 devices, that meant 150 nuggets. Why "nugget"? Because it was shorter and more convenient than repeatedly saying "a minute of data from one device". Why not something less fancy like "chunk"? Because we reserved "chunk" for subdivisions within a nugget. Perhaps there were better choices, but "nugget" was the term we settled on and it quickly became shared terminology between the collaborators. Good terminology naturally carries over into code. With this vocabulary in place, function names like , , , , , etc. immediately become meaningful to everyone involved. Thinking about the vocabulary also ensures that we are thinking about the data, concepts and notions we are working with in a deliberate manner and that kind of thinking also helps when we design the architecture of software. Too often I see collaborators on software projects jump straight into writing functions that take some input and produce some desired effect, with variable names and function names decided on the fly. To me, this feels backwards. I prefer the opposite approach. Define the terms first and let the code follow from them. I also prefer developing software in a layered manner, where complex functionality is built from simpler, well-named building blocks. It is especially important to avoid layer violations , where one complex function invokes another complex function. That creates tight coupling between two complex functions. If one function changes in the future, we have to reason carefully about how it affects the other. Since both are already complex, the cognitive burden is high. A better approach, I think, is to identify the common functionality they share and factor that out into smaller, simpler functions. To summarise, I like to develop software with a clear vocabulary, consistent use of that vocabulary, a layered design where complex functions are built from simpler ones and by avoiding layer violations. I am sure none of this is new to the Lobsters community. Some of these ideas also occur in domain-driven design (DDD). DDD defines the term ubiquitous language to mean, "A language structured around the domain model and used by all team members within a bounded context to connect all the activities of the team with the software." If I could call this approach of software development something, I would simply call it "vocabulary-driven development" (VDD), though of course DDD is the more comprehensive concept. Like I said, none of this is likely new to the Lobsters community. In particular, I suspect Forth programmers would find it too obvious. In Forth, it is very difficult to begin with a long, poorly thought-out monolithic word and then break it down into smaller ones later. The stack effects quickly become too hard to track mentally with that approach. The only viable way to develop software in Forth is to start with a small set of words that represent the important notions of the problem domain, test them immediately and then compose higher-level words from the lower-level ones. Forth naturally encourages a layered style of development, where the programmer thinks carefully about the domain, invents vocabulary and expresses complex ideas in terms of simpler ones, almost in a mathematical fashion. In my experience, this kind of deliberate design produces software that remains easy to understand and reason about even years after it was written. Not enhancing existing functions but adding new small ones seems quite lovely, but how do you come back to such a codebase later with many tiny functions? At points, I've advocated for very large functions, particularly traumatized by Java-esque 1000 functions in 1000 files approaches. When you had time, would you often rearchitecture the conceptual space of all of those functions? The famous quote from Alan J. Perlis comes to mind: It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures. Personally, I enjoy working with a codebase that has thousands of functions, provided most of them are small, well-scoped and do one thing well. That said, I am not dogmatically opposed to large functions. It is always a matter of taste and judgement. Sometimes one large, cohesive function is clearer than a pile of tiny ones. For example, when I worked on parser generators, I often found that lexers and finite state machines benefited from a single top-level function containing the full tokenisation logic or the full state transition logic in one place. That function could call smaller helpers for specific tasks, but we still need the overall - or - or ladder somewhere. I think trying to split that ladder into smaller functions would only make the code harder to follow. So while I lean towards small, composable functions, the real goal is to strike a balance that keeps code maintainable in the long run. Each function should be as small as it can reasonably be and no smaller. Like you, I program as a tool to explore domains. Which do you know the most about? For me too, the appeal of computer programming lies especially in how it lets me explore different domains. There are two kinds of domains in which I think I have gained good expertise. The first comes from years of developing software for businesses, which has included solving problems such as network events parsing, indexing and querying, packet decoding, developing parser generators, database session management and TLS certificate lifecycle management. The second comes from areas I pursue purely out of curiosity or for hobby computing. This is the kind I am going to focus on in our conversation. Although computing and software are serious business today, for me, as for many others, computing is also a hobby. Personal hobby projects often lead me down various rabbit holes and I end up learning new domains along the way. For example, although I am not a web developer, I learnt to build small, interactive single-page tools in plain HTML, CSS and JavaScript simply because I needed them for my hobby projects over and over again. An early example is QuickQWERTY , which I built to teach myself and my friends touch-typing on QWERTY keyboards. Another example is CFRS[] , which I created because I wanted to make a total (non-Turing complete) drawing language that has turtle graphics like Logo but is absolutely minimal like P′′. You use double spaces after periods which I'd only experienced from people who learned touch typing on typewriters, unexpected! Yes, I do separate sentences by double spaces. It is interesting that you noticed this. I once briefly learnt touch typing on typewriters as a kid, but those lessons did not stick with me. It was much later, when I used a Java applet-based touch typing tutor that I found online about two decades ago, that the lessons really stayed with me. Surprisingly, that application taught me to type with a single space between sentences. By the way, I disliked installing Java plugins into the web browser, so I wrote QuickQWERTY as a similar touch typing tutor in plain HTML and JavaScript for myself and my friends. I learnt to use double spaces between sentences first with Vim and then later again with Emacs. For example, in Vim, the option is on by default, so when we join sentences with the normal mode command or format paragraphs with , Vim inserts two spaces after full stops. We need to disable that behaviour with if we want single spacing. It is similar in Emacs. In Emacs, the command ( ) and the command ( ) both insert two spaces between sentences by default. Single spacing can be enabled with . Incidentally, I spend a good portion of the README for my Emacs quick-start DIY kit named Emfy discussing sentence spacing conventions under the section Single Space for Sentence Spacing . There I explain how to configure Emacs to use single spaces, although I use double spaces myself. That's because many new Emacs users prefer single spacing. The defaults in Vim and Emacs made me adopt double spacing. The double spacing convention is also widespread across open source software. If we look at the Vim help pages, Emacs built-in documentation or the Unix and Linux man pages, double spacing is the norm. Even inline comments in traditional open source projects often use it. For example, see Vim's :h usr_01.txt , Emacs's (info "(emacs) Intro") or the comments in the GCC source code . How do you approach learning a new domain? When I take on a new domain, there is of course a lot of reading involved from articles, books and documentation. But as I read, I constantly try to test what I learn. Whenever I see a claim, I ask myself, "If this claim were wrong, how could I demonstrate it?" Then I design a little experiment, perhaps write a snippet of code or run a command or work through a concrete example, with the goal of checking the claim in practice. Now I am not genuinely hoping to prove a claim wrong. It is just a way to engage with the material. To illustrate, let me share an extremely simple and generic example without going into any particular domain. Suppose I learn that Boolean operations in Python short-circuit. I might write out several experimental snippets like the following: And then confirm that the results do indeed confirm short-circuit evaluation ( followed by in this case). At this point, one could say, "Well, you just confirmed what the documentation already told you." And that's true. But for me, the value lies in trying to test it for myself. Even if the claim holds, the act of checking forces me to see the idea in action. That not only reinforces the concept but also helps me build a much deeper intuition for it. Sometimes these experiments also expose gaps in my own understanding. Suppose I didn't properly know what "short-circuit" means. Then the results might contradict my expectations. That contradiction would push me to correct my misconception and that's where the real learning happens. Occasionally, this process even uncovers subtleties I didn't expect. For example, while learning socket programming, I discovered that a client can successfully receive data using even after calling , contrary to what I had first inferred from the specifications. See my Stack Overflow post Why can recv() receive messages after the client has invoked shutdown()? for more details if you are curious. Now this method cannot always be applied, especially if it is very expensive or unwieldy to do so. For example, if I am learning something in the finance domain, it is not always possible to perform an actual transaction. One can sometimes use simulation software, mock environments or sandbox systems to explore ideas safely. Still, it is worth noting that this method has its limitations. In mathematics, though, I find this method highly effective. When I study a new branch of mathematics, I try to come up with examples and counterexamples to test what I am learning. Often, failing to find a counterexample helps me appreciate more deeply why a claim holds and why no counterexamples exist. Do you have trouble not getting distracted with so much on your plate? I'm curious how you balance the time commitments of everything! Indeed, it is very easy to get distracted. One thing that has helped over the years is the increase in responsibilities in other areas of my life. These days I also spend some of my free time studying mathematics textbooks. With growing responsibilities and the time I devote to mathematics, I now get at most a few hours each week for hobby computing. This automatically narrows down my options. I can explore perhaps one or at most two ideas in a month and that constraint makes me very deliberate about choosing my pursuits. Many of the explorations do not evolve into something solid that I can share. They remain as little experimental code snippets or notes archived in a private repository. But once in a while, an exploration grows into something concrete and feels worth sharing on the Web. That becomes a short-term hobby project. I might work on it over a weekend if it is small or for a few weeks if it is more complex. When that happens, the goal of sharing the project helps me focus. I try not to worry too much about making time. After all, this is just a hobby. Other areas of my life have higher priority. I also want to devote a good portion of my free time to learning more mathematics, which is another hobby I am passionate about. Whatever little spare time remains after attending to the higher-priority aspects of my life goes into my computing projects, usually a couple of hours a week, most of it on weekends. How does blogging mix in? What's the development like of a single piece of curiosity through wrestling with the domain, learning and sharing it etc.? Maintaining my personal website is another aspect of computing that I find very enjoyable. My website began as a loose collection of pages on a LAN site during my university days. Since then I have been adding pages to it to write about various topics that I find interesting. It acquired its blog shape and form much later when blogging became fashionable. I usually write a new blog post when I feel like there is some piece of knowledge or some exploration that I want to archive in a persistent format. Now what the development of a post looks like depends very much on the post. So let me share two opposite examples to describe what the development of a single piece looks like. One of my most frequently visited posts is Lisp in Vim . It started when I was hosting a Common Lisp programming club for beginners. Although I have always used Emacs and SLIME for Common Lisp programming myself, many in the club used Vim, so I decided to write a short guide on setting up something SLIME-like there. As a former long-time Vim user myself, I wanted to make the Lisp journey easier for Vim users too. I thought it would be a 30-minute exercise where I write up a README that explains how to install Slimv and how to set it up in Vim. But then I discovered a newer plugin called Vlime that also offered SLIME-like features in Vim! That detail sent me down a very deep rabbit hole. Now I needed to know how the two packages were different, what their strengths and weaknesses were, how routine operations were performed in both and so on. What was meant to be a short note turned into a nearly 10,000-word article. As I was comparing the two SLIME-like packages for Vim, I also found a few bugs in Slimv and contributed fixes for them ( #87 , #88 , #89 , #90 ). Writing this blog post turned into a month-long project! At the opposite extreme is a post like Elliptical Python Programming . I stumbled upon Python's Ellipsis while reviewing someone's code. It immediately caught my attention. I wondered if, combined with some standard obfuscation techniques, one could write arbitrary Python programs that looked almost like Morse code. A few minutes of experimentation showed that a genuinely Morse code-like appearance was not possible, but something close could be achieved. So I wrote what I hope is a humorous post demonstrating that arbitrary Python programs can be written using a very restricted set of symbols, one of which is the ellipsis. It took me less than an hour to write this post. The final result doesn't look quite like Morse code as I had imagined, but it is quite amusing nevertheless! What draws you to post and read online forums? How do you balance or allot time for reading technical articles, blogs etc.? The exchange of ideas! Just as I enjoy sharing my own computing-related thoughts, ideas and projects, I also find joy in reading what others have to share. Other areas of my life take precedence over hobby projects and hobby projects take precedence over technical forums. After I've given time to the higher-priority parts of my life and to my own technical explorations, I use whatever spare time remains to read articles, follow technical discussions and occasionally add comments. When you decided to stop with MathB due to moderation burdens, I offered to take over/help and you mentioned others had too. Did anyone end up forking it, to your knowledge? I first thought of shutting down the MathB -based pastebin website in November 2019. The website had been running for seven years at that time. When I announced my thoughts to the IRC communities that would be affected, I received a lot of support and encouragement. A few members even volunteered to help me out with moderation. That support and encouragement kept me going for another six years. However, the volunteers eventually became busy with their own lives and moved on. After all, moderating user content for an open pastebin that anyone in the world can post to is a thankless and tiring activity. So most of the moderation activity fell back on me. Finally, in February 2025, I realised that I no longer want to spend time on this kind of work. I developed MathB with a lot of passion for myself and my friends. I had no idea at the time that this little project would keep a corner of my mind occupied even during weekends and holidays. There was always a nagging worry. What if someone posted content that triggered compliance concerns and my server was taken offline while I was away? I no longer wanted that kind of burden in my life. So I finally decided to shut it down. I've written more about this in MathB.in Is Shutting Down . To my knowledge, no one has forked it, but others have developed alternatives. Further, the Archive Team has archived all posts from the now-defunct MathB-based website. A member of the Archive Team reached out to me over IRC and we worked together for about a week to get everything successfully archived. What're your favorite math textbooks? I have several favourite mathematics books, but let me share three I remember especially fondly. The first is Advanced Engineering Mathematics by Erwin Kreyszig. I don't often see this book recommended online, but for me it played a major role in broadening my horizons. I think I studied the 8th edition back in the early 2000s. It is a hefty book with over a thousand pages and I remember reading it cover to cover, solving every exercise problem along the way. It gave me a solid foundation in routine areas like differential equations, linear algebra, vector calculus and complex analysis. It also introduced me to Fourier transforms and Laplace transforms, which I found fascinating. Of course, the Fourier transform has a wide range of applications in signal processing, communications, spectroscopy and more. But I want to focus on the fun and playful part. In the early 2000s, I was also learning to play the piano as a hobby. I used to record my amateur music compositions with Audacity by connecting my digital piano to my laptop with a line-in cable. It was great fun to plot the spectrum of my music on Audacity, apply high-pass and low-pass filters and observe how the Fourier transform of the audio changed and then hear the effect on the music. That kind of hands-on tinkering made Fourier analysis intuitive for me and I highly recommend it to anyone who enjoys both music and mathematics. The second book is Introduction to Analytic Number Theory by Tom M. Apostol. As a child I was intrigued by the prime number theorem but lacked the mathematical maturity to understand its proof. Years later, as an adult, I finally taught myself the proof from Apostol's book. It was a fantastic journey that began with simple concepts like the Möbius function and Dirichlet products and ended with quite clever contour integrals that proved the theorem. The complex analysis I had learnt from Kreyszig turned out to be crucial for understanding those integrals. Along the way I gained a deeper understanding of the Riemann zeta function \( \zeta(s). \) The book discusses zero-free regions where \( \zeta(s) \) does not vanish, which I found especially fascinating. Results like \( \zeta(-1) = -1/12, \) which once seemed mysterious, became obvious after studying this book. The third is Galois Theory by Ian Stewart. It introduced me to field extensions, field homomorphisms and solubility by radicals. I had long known that not all quintic equations are soluble by radicals, but I didn't know why. Stewart's book taught me exactly why. In particular, it demonstrated that the polynomial \( t^5 - 6t + 3 \) over the field of rational numbers is not soluble by radicals. This particular result, although fascinating, is just a small part of a much larger body of work, which is even more remarkable. To arrive at this result, the book takes us through a wonderful journey that includes the theory of polynomial rings, algebraic and transcendental field extensions, impossibility proofs for ruler-and-compass constructions, the Galois correspondence and much more. One of the most rewarding aspects of reading books like these is how they open doors to new knowledge, including things I didn't even know that I didn't know. How does the newer math jell with or inform past or present computing, compared to much older stuff? I don't always think explicitly about how mathematics informs computing, past or present. Often the textbooks I pick feel very challenging to me, so much so that all my energy goes into simply mastering the material. It is arduous but enjoyable. I do it purely for the fun of learning without worrying about applications. Of course, a good portion of pure mathematics probably has no real-world applications. As G. H. Hardy famously wrote in A Mathematician's Apology : I have never done anything 'useful'. No discovery of mine has made or is likely to make, directly or indirectly, for good or ill, the least difference to the amenity of the world. But there is no denying that some of it does find applications. Were Hardy alive today, he might be disappointed that number theory, his favourite field of "useless" mathematics, is now a crucial part of modern cryptography. Electronic commerce wouldn't likely exist without it. Similarly, it is amusing how something as abstract as abstract algebra finds very concrete applications in coding theory. Concepts such as polynomial rings, finite fields and cosets of subspaces in vector spaces over finite fields play a crucial role in error-correcting codes, without which modern data transmission and storage would not be possible. On a more personal note, some simpler areas of mathematics have been directly useful in my own work. While solving problems for businesses, information entropy, combinatorics and probability theory were crucial when I worked on gesture-based authentication about one and a half decades ago. Similarly, when I was developing Bloom filter-based indexing and querying for a network events database, again, probability theory was crucial in determining the parameters of the Bloom filters (such as the number of hash functions, bits per filter and elements per filter) to ensure that the false positive rate remained below a certain threshold. Subsequent testing with randomly sampled network events confirmed that the observed false positive rate matched the theoretical estimate quite well. It was very satisfying to see probability theory and the real world agreeing so closely. Beyond these specific examples, studying mathematics also influences the way I think about problems. Embarking on journeys like analytic number theory or Galois theory is humbling. There are times when I struggle to understand a small paragraph of the book and it takes me several hours (or even days) to work out the arguments in detail with pen and paper (lots of it) before I really grok them. That experience of grappling with dense reasoning teaches humility and also makes me sceptical of complex, hand-wavy logic in day-to-day programming. Several times I have seen code that bundles too many decisions into one block of logic, where it is not obvious whether it would behave correctly in all circumstances. Explanations may sometimes be offered about why it works for reasonable inputs, but the reasoning is often not watertight. The experience of working through mathematical proofs, writing my own, making mistakes and then correcting them has taught me that if the reasoning for correctness is not clear and rigorous, something could be wrong. In my experience, once such code sees real-world usage, a bug is nearly always found. That's why I usually insist either on simplifying the logic or on demonstrating correctness in a clear, rigorous way. Sometimes this means doing a case-by-case analysis for different types of inputs or conditions and showing that the code behaves correctly in each case. There is also a bit of an art to reducing what seem like numerous or even infinitely many cases to a small, manageable set of cases by spotting structure, such as symmetries, invariants or natural partitions of the input space. Alternatively, one can look for a simpler argument that covers all cases. These are techniques we employ routinely in mathematics and I think that kind of thinking and reasoning is quite valuable in software development too. Read on website | #programming | #technology | #mathematics Lisp and Other Things Lisp, Emacs and Mathematics Interests and Exploration Computing for Fun Computing Activities Programming vs Domains Old Functionality and New Problems Designing for Composability Small vs Large Functions Domains and Projects Double Spacing and Touch Typing Approach to Learning Managing Time and Distractions MathB Moderation Problems Favourite Mathematics Textbooks Mathematics and Computing

0 views
Susam Pal 4 months ago

Prime Number Grid Explorer

A simple single-page HTML application to explore the distribution of prime numbers in a grid. Choose a starting number along with the number of rows and columns and the page generates the corresponding grid. Read on website | #web | #mathematics | #technology

0 views
Susam Pal 5 months ago

Miller-Rabin Speed Test

A demo page that implements the Miller-Rabin primality test to accurately detect primes for all numbers less than 318665857834031151167461 and compare its speed against a simple division based primality test algorithm. Read on website | #web | #programming | #mathematics | #technology

0 views