Benjamin Esham

What’s the smallest amount of currency that can’t be represented by a floating-point number?

At this point it’s common wisdom among software developers that if you’re going to store amounts of currency, you shouldn’t use floating-point numbers. Floats can represent numbers within a huge range, but only some numbers in that range can be represented exactly, and while this is fine sometimes it’s almost never what you want when dealing with money.

I got to wondering: counting up cent by cent from zero, where would you first run into a problem if you were using a float to store an amount in dollars? (For U.S. currency, the base unit is the dollar and the smallest subdivision is the cent, which is one hundredth of a dollar.)

If we want to express a number exactly in binary floating point, one requirement is that we be able to write it as a fraction p/q in lowest terms, where p and q are integers and q = 2n for some integer n.1 Let’s consider the smallest nonzero amount of currency: one cent. Expressed in dollars, this amount is 0.01, or 1/100. The denominator, 100, cannot be written as 2n for any integer n, so 0.01 cannot be expressed exactly as a binary floating-point number. Notice that we didn’t even get as far as asking whether it would be representable in an IEEE float, or double, or any other specific format—the decimal number 0.01 just can’t be represented by any finite string of binary digits, period.

So there we have our answer: the problems with representing decimal amounts in floats start with the “first” decimal amount, at least as far as dollars and cents go. Of course, if you were to write double x = 0.01 in your program and then do some calculations with x, your results wouldn’t necessarily be wrong—but they wouldn’t necessarily be right, either.

  1. According to a Stack Overflow answer by Alexander Yee, “A number can be represented exactly in binary if the prime factorization of the denominator contains only 2.” This might seem to suggest that integers aren’t exactly representable, but they are. A more precise statement would be, “…if the denominator is unity or if its prime factorization contains only powers of 2.”↩︎

Counterfactual fgrep

For years and years I thought the fgrep command was a shorthand for running grep with the -f flag (“Obtain patterns from FILE, one per line”). I thought this was a weird flag to promote to its own command; I never used it. Why did other people have all of these files full of regexes to search for but I’d never needed such a thing?

Life made so much more sense when I realized that fgrep was a shortcut not for grep -f but for grep -F, which interprets the given pattern as a plain string instead of as a regex. Okay, now that’s an option I’ve used plenty of times.

Here’s a thought experiment: if you had an alias for grep -f, how it would even work? The synopsis for this form of grep looks like

grep [OPTION...] -f PATTERN_FILE [FILE...]

Presumably the heretical fgrep would work like


What if you had multiple pattern files, though? How would you distinguish them from the files to be searched? Maybe you could separate them with the -- dummy argument, like

fgrep patterns1 patterns2 -- file.txt

But in that case, how would a command like

fgrep filename1 filename2

be interpreted? Is filename2 a file to read patterns from or a file to search? If all filenames up to -- are assumed to be pattern files then suddenly the user needs to type a -- every single time they want to search a file! The only sane way to specify multiple pattern files would be to require an -f to precede each one after the first:

fgrep patterns1 -f patterns2 file.txt

This asymmetric syntax is definitely not an improvement on just typing out grep -f.

Road work, next few miles

Ways of writing “two and a half” on highway signage
Notation What it means to a mathematician How often is it used on highway signage?
2 1/2 10.5 All the time
2–1/2 1.5 Pretty often
21/2 1.414… Occasionally
2 + 1/2 2.5 Never ever

Wikipedia curiosity of the day

The Vim text editor can run scripts written in several programming languages: Python, Ruby, and Lua, to name just three, and MzScheme, to name one more. I got curious about this last one. I assumed from the name that MzScheme is a dialect of Lisp, but I’ve never seen evidence of anyone actually writing a Vim script in this language. I popped open LaunchBar (whose ability to search Wikipedia I’ve mentioned before), selected Wikipedia, and typed in “mzscheme,” which gave me these results:

A screenshot of LaunchBar showing two search results: the articles on the Racket programming language and Abraham M. Schermerhorn.

That wasn’t what I expected. Okay, apparently “MzScheme” is an older name for the programming language and environment that are now called Racket. But Abraham M. Scher­mer­horn was… the mayor of Rochester, New York? The city I used to live in? And he died in 1855, preceding even ancient Lisp by over a century. What the hell was he doing in the search results for “mzscheme”? It took me a lot of squinting to realize that “M. Scher­mer­horn” does sort of, a little bit, look like “mzscheme.”1

One mystery still remains: why are Vim users so uninterested in writing scripts in Lisp? Snarky Emacs-related answers aside, I think the answer at this point may just be that many distributions ship a Vim that’s been compiled without support for Racket.2 This issue thread suggests that you can’t build a Racket-enabled Vim under Ubuntu unless you compile Racket yourself. Homebrew doesn’t include Racket support in its formula for Vim, and even the flexibility-obsessed Nix doesn’t offer Racket support in its vim_configurable derivation. This leads to a chicken-and-egg problem where people don’t script Vim with Racket because their copy of Vim doesn’t support that, and packagers don’t build in Racket support because no one is asking for it.

  1. Wikipedia has an article called “A. M. Schemerhorn”—note the missing “r”—that redirects to “Abraham M. Scher­mer­horn.” I don’t think the search algorithm would have even identified a match had this redirect not existed.↩︎

  2. If only Vim had supported the GNU flavor of Scheme instead, we could call these builds guileless.↩︎