[ANN] MathChecker.jl: Find problems in floating-point calculations

I’m always surprised this isn’t a bigger topic of conversation among Julia users: how to find where problems are coming from in numerics. The gap between our pretty equations and algorithms on one hand, and practical code implementations on the other can simultaneously be frightening and invisible. Most importantly, we need to know:

  1. Where do NaNs, Infs, and subnormal numbers come from, or go to?
  2. Where do we lose precision — due to cancellation or absorption, inexact rounding, or simply mixing number types with unintended precision?
  3. Did we use uninitialized values? Maybe we forgot to initialize a recurrence relation?

Because Julia is generic, we can answer all of these questions by creating our own number type to wrap any given float type. This is what the MathChecker.Checked type does. The type is parameterized by the underlying float type, and flags for whether or not to check each of the items in the list above.

Using that type is as easy as wrapping input values or arrays in the constructor:

x = Checked(1.0)

Then, just feed these into your functions, and most should work just fine — until a problem with your numerics is found.

By default, only NaN and Inf or mismatched precisions are considered problems. Features can be turned on or off (or adjusted) using keyword arguments, as in

y = Checked(3.14159265; inf=false, cancellation=true, absorption=true)

If problems are found, the default behavior is to raise an error, showing exactly where the problematic code is. But it’s also possible to handle problems using custom behaviors, such as logging, so we can see where all the problems are in a program.

I first got into this when trying to figure out where a NaN was coming from in some massive pile of code. Basically, I was looking for a signaling NaN. Then, I came across this discourse post by @brianguenter, which was basically the inspiration for this approach. This package has significant overlap (but not precise equivalence) with the IEEE 754 floating-point exception flags.

This project has been on my to-do list for a long time, and I’ve frequently found myself slapping together worse versions of this code for quick tests. But now I had some free time, and a lot of help from Claude, and I’ve managed to put something together that might be useful to more people than just myself.

9 Likes