exupero's blog

Stack math revisited

A couple years ago I wrote a series about performing mental math calculations using stack-oriented programming, which I termed "stack math". That series culminated in a compendium of stack algorithms to approximate conversions I've occasionally needed. To keep the algorithms short enough for human working memory, I chunked several easy-to-perform operations, such as double and add-tenth, but I avoided aliasing more than the simplest operations, and I retained some traditional stack-oriented operations like dup and dip.

On problem I found with using these stack algorithms is that while they were easy enough to perform mentally, it was often difficult to remember the one I wanted and tough to make sure I wasn't confusing it with another algorithm. Even seven or fewer primitives were hard to remember when they were so similar. To help with this, both shortening algorithms and making them more distinct from each other, I've revised the algorithms to chunk more. The trick is knowing what to chunk. In the case of mental math, some sequences of operations are more intuitive than others, and we can chunk those sequences to make them easier to remember without significantly increasing the time necessary to unpack the operations mentally. For example, adding a tenth originally used three operations, dup tenth +, but if you know how to add a tenth, it's easier to think of the operation as a whole than of the individual steps. Instead of dup tenth +, the revised compendium uses the operation +tenth. Similarly, I add several more operations, such as -twentieth, quarter, ten-thousandfold, etc.

The other sticking point I encountered in practice was the use of dup and dip. They're easy enough to perform mentally, but anytime I actually had to do them I felt I needed to slow down and track my mental data stack more carefully. The reason, I think, is due to how stack programs implicitly operate on the top of the data stack and use dip to operate on the value below the top of the stack. I rarely have more than one number in my mental data stack, but when I do I don't think of one as the top of the stack and the other as the one below the top, I think of the top number as the right-hand number and the value below it as the left-hand number. To align stack math with that mental picture, I'm experimenting with new operators called left and right. Each checks the stack to see how many values are on it; if there's only one value they duplicate it, if there's more than one, they do nothing. Once that's done, left is only an alias of dip, and right is a no-op. I have yet to use these operations extensively, but the symmetry of them feels more intuitive.

I've generated a new compendium of algorithms based on the above considerations, available in the next post. The new compendium also includes looser approximations, for times when you don't need accuracy within 3% of the exact calculation, which, if you're like me, is probably most of the time you're doing mental math. I've still provided the more accurate algorithms, though, since they're pleasingly brief and relatively easy to execute.