Everything

Adding Floating-Point Decimals for Fun and Profit

Many people know that you shouldn’t do decimal calculations, such as those involving U.S. dollars and cents, with the floating-point numbers in most programming languages. This is because decimal numbers can’t be expressed exactly as such floating-point numbers, so you will encounter rounding errors.

Famously, with IEEE double-precision floats, 0.1 + 0.2 is not 0.3, but rather, 0.30000000000000004.

On the other hand, I use a Python REPL to add up decimal numbers for receipts all the time. Of course, my stakes are lower; I’m summing things in the $1–$100 range and know to manually round the microscopic errors off before copying the sum somewhere. But actually it’s quite often that those errors don’t appear at all.

If we sum every pair of multiples of 0.01 up to 1.00 and look at whether the printed result is too large (blue), too small (red), or correct, we get a cool pattern:

Figure 1: How floating-point affects summing two multiples of 0.01, up to 1.00

Where does this pattern come from?

all the words we leave behind

Here I go quoting song lyrics to myself again

I have to confess I almost forgot to write a year-end post until today, New Year’s Eve.

What did I do in 2025? As before, I worked on a lot of things on Anthropic’s interpretability team, including our massive circuit tracing and biology papers from March. Also as before, I helped run Galactic Puzzle Hunt 2025 with the rest of ✈✈✈ Galactic Trendsetters ✈✈✈ in September. Throughout the year I posted less-polished posts more often on my bear blog. Otherwise I didn’t do a whole lot of publicly linkable things.

That’s a bit sad. Some part of me still wants to grow up to be an unclassifiable maker-of-things-on-the-Internet. There are excuses I can make and a few other miniprojects I can point to in my defense, but mostly I just haven’t set aside time for it, and I can partially make peace with this — continuing the trend, 2025 was one of the most offline social years I’ve had.

Other things I did offline:

Gold-medaling the 2025 IMO was easier than average

(Background/disclaimer: I work at Anthropic, far from any efforts related to math reasoning or evaluations; opinions are my own. I was an IMO gold medalist in 2012.)

I way missed the news window on this one, but I thought it was interesting and a bit underappreciated that the fraction of gold medalists at the 2025 IMO (72/630 = 11.4%) is the highest it’s been since 1981.

Crudely, IMO gold medals are awarded to the highest-scoring 1/12 of contestants.1 However, because scores are integers up to 42 and there’s no provision for tiebreaking, it’s possible for a lot of contestants to be tied around the threshold. In that case, either all of them get a gold medal or none do, and the fraction of gold medalists might deviate substantially from 1/12. That’s what happened this year: 46 contestants all won a gold medal by scoring exactly 35 points.

Here’s a comparison with the fraction of IMO gold medalists for each year since 2000. (See appendix 1 for a full table and appendix 2 for discussion of the choice of 2000.)

Vim Digraphs: The Unnecessarily Detailed Guide

In Vim, in Insert mode, if you type Ctrl-K followed by two characters, you can insert a special Unicode character corresponding to those two characters. The two-character combo is often easier to remember than other codes. These are called digraphs.

For example, Ctrl-K12 will insert ½.

Everything below this is unnecessary detail.

What are all the digraphs?

I used to think the big table :help digraphs-table at the bottom of Vim’s help page for digraphs was exhaustive. As the page explains, the mnemonics are based on RFC1345, an Internet standard that provides two-character mnemonics for various characters.

Right Back Here

I’m still doing interpretability at Anthropic. This year, among many other research updates, we scaled sparse autoencoders to Claude 3 Sonnet. There’s not a whole lot I have to add. I like to think I improved at various clichéd abstract work skills that I don’t have anything insightful to say about, the most front-of-mind being communication and prioritization. It’s good to, uh, communicate what everybody is prioritizing and communicate all the information everybody needs to prioritize things. Thanks for coming to my TED talk.

In my personal life, I went to more in-person social events than ever before. I took a bunch of improv classes and might actually end up performing soon™. I went to a Jacob Collier concert and a Bear Ghost concert. I scored 141/150 plus two beers on the AMC 12. I attended three separate furry conventions, one of which I believe I have to credit with indirectly motivating me to hit the gym semiregularly for the first time in my life. (Also I went to Tural for summer vacation.) I’m pretty happy with all that, but it also doesn’t really add up to exciting reflections.

How is viridis defined?

and other adventures in colormapping

If you’ve dabbled in data visualization, there’s a good chance you’ve encountered the colormap viridis, which was created for matplotlib in ~2015.

This particular gradient is brought to you by d3

You may also know about some of the considerations went into the colormap’s design, chiefly perceptual uniformity: equally distant colors on the colormap should “look equally different” to humans.

I won’t discuss color theory much here; the talk introducing viridis (below) is quite good, and there are many other resources online, such as Jamie Wong’s From Hexcodes to Eyeballs or Bartosz Ciechanowski’s Color Spaces.

Instead, I nerd-sniped myself with a different question: How is viridis, specifically, defined?

This seems like it should be easy to answer. Just go into matplotlib and find the source code for viridis, right? Unfortunately, that source code is just a list of 256 RGB triples along which colors are interpolated. This makes sense for efficiency and even portability because (as we’ll see) the formula for producing viridis is incredibly complicated, but it isn’t a very satisfying answer. How did those triples originally come to be?

D3 the Hard FP Way

In theory, the idea here is similar to when I was learning React/Redux and diving into SQL selects. In practice, I think most of D3’s complexity isn’t exactly in a direction that is elucidated by writing down types for everything, so the title is a mere personal snowclone. I’m just writing things out to an arbitrary amount of detail until I understand them and can refer to what I wrote here later.

Background

D3 is “a JavaScript library for visualizing data”. It has a lot of sublibraries that interoperate well but could be used separately — for example, it has utilities for manipulating colors, time, and SVG paths. Of the various concepts, though, I think D3 selections are the most distinctive and fundamental, so they are the focus of this post.

At a high level, D3 selections feel like jQuery. You run some code and it goes into the DOM and adds, deletes, and mutates a bunch of elements. The docs even endorse monkeypatching d3.selection to add custom helpers. However, D3 has data binding and batch operations that make it easy to change the DOM in a way that resembles reconciliation in a framework like React.

Selections

API: Selecting Elements.

A D3 selection holds an array of arrays of nullable1 DOM elements. The intermediate arrays are called groups. Additionally, each group in a selection is associated with a parent node. During basic D3 usage, you might only ever work with selections with a single group and ignore parent nodes.

When relevant, I will call the index of an element inside its group the “within-group index” and the index of a group among all groups in a selection the “across-group index”.

Despite Everything

…it’s still you. Looking at yourself in the window. The second afternoon after you finally get COVID for the first time.

As previously reported, I left Zoom late last year and spent a bit of time unemployed, traveling for some of it but mostly staying home. In the process, I got COVID, though not with a particularly interesting story. Would not recommend.

Then I started work at Anthropic doing interpretability research — moving way back into my comfort zone in a way by returning to my web dev roots to create many of the visualizations we cared about, and way out of it in another by jumping into the deeply theoretical end of research, in a field where my total experience is one college course and one casual reading group. Still, I figured some things out and we published Towards Monosemanticity in early October.

I don’t have much to add to the research results in the paper, though I can share some trivial, mildly entertaining anecdotes about the process:

Concurrency

I want to add a second word in the title, something like “Koans” or “Vignettes”, but I don’t know a word with the right connotations.

I realized recently that I have been walking around for a long time with some confusion and unknown unknowns about how concurrency works in various settings, and decided to write about it until I stopped being confused. This post doesn’t therefore have much of a “point”.

Concurrency and Parallelism

Wikipedia, as of time of writing:

Concurrency is the ability of different parts or units of a program, algorithm, or problem to be executed out-of-order or in partial order, without affecting the outcome.

There are two broad reasons concurrency is useful. One is for performance: if you want your computer to perform as many floating point operations as possible by lunchtime, you want all CPUs/GPUs/etc. to be performing operations simultaneously. Another is that you’re in a problem domain where you simply can’t predict the order of events: you’re writing a user interface, and the user can click on any of multiple buttons in any order; or you’re writing a web server, and any number of clients can request any pages in any order. These reasons are not mutually exclusive.

Yet Another Diceware-Style Word List

Passwords. It’s 2023 and we still have to deal with them.

Many people know that, per the canonical xkcd, sequences of randomly chosen words such as

soak-science-wander-pew-goldfish-xray-speed-consult
or get the list as .txt or a standalone generator (if my JavaScript were working the above would be a random password and you wouldn’t be seeing this message)

make relatively memorable but hard-to-crack passwords. One popular strategy for randomly choosing words is Arnold Reinhold’s Diceware™, a list of 65 = 7776 “words” that you can randomly sample from by rolling five dice (analog or digital). (I won’t go into topics like how to calculate the entropy of passwords and how long a password you should try to have here, since most Diceware overviews already discuss them at length.)

Five dice arranged in a V shape, digitally altered to be red
Somehow this image was already on my blog without being used in any post, but if there’s a post it belongs in, it’s surely this one

A few people have iterated on the concept since then: probably most notably, the Electronic Frontier Foundation published their own word list in 2016, with words chosen to be more well-known and memorable, at the cost of taking longer to type. I’m a fast typer and prefer the EFF’s wordlist over the original, and am very grateful to them for creating it, but after generating quite a few passwords with it over the last few years, I began to feel that it still had a lot of room for improvement.