· 8 min read ·

The Arithmetic That Knows It Doesn't Know: Interval Unions and the Division Problem

Source: hackernews

The Field That Got Overlooked

Interval arithmetic is one of those ideas in computer science that seems obviously useful once you understand it, yet it has sat at the margins of mainstream programming for sixty years. The core concept comes from Ramón E. Moore’s 1966 book Interval Analysis: instead of representing a numeric value as a single floating-point number, you represent it as a closed interval [a, b], meaning “the true value is somewhere in here.” Every arithmetic operation then produces a new interval that is guaranteed to contain the true result.

The practical motivation is compelling. Floating-point arithmetic introduces rounding errors at every step. In a long computation these errors accumulate silently, and your final answer can be wrong by an amount that bears no relation to the precision you assumed. Interval arithmetic turns this into a controlled, auditable process: you always know the worst-case bounds on your result. The interval [1.9999, 2.0001] tells you something specific. A bare 2.0 with unnamed rounding error tells you nothing.

The rules for interval arithmetic on a closed interval [a, b] and [c, d] are straightforward:

[a,b] + [c,d] = [a+c, b+d]
[a,b] - [c,d] = [a-d, b-c]
[a,b] × [c,d] = [min(ac,ad,bc,bd), max(ac,ad,bc,bd)]
[a,b] / [c,d] = [a,b] × [1/d, 1/c]   (when 0 ∉ [c,d])

Addition and subtraction are immediate. Multiplication requires checking four products because the signs of a, b, c, and d can vary independently. Division is just multiplication by the reciprocal, and it works cleanly as long as the denominator interval does not contain zero.

That last clause is where the field has been quietly struggling for decades.

The Zero Problem

Consider what happens when you compute 1 / [-1, 2]. The denominator interval spans zero, which means you are dividing by values that include zero itself. The result is not a single interval. When the denominator approaches zero from the positive side, the quotient blows up to positive infinity. When it approaches from the negative side, it collapses to negative infinity. The set of values you can actually obtain is (-∞, -1] ∪ [0.5, +∞), two separate rays with a gap between them.

Standard interval arithmetic cannot represent this. Its only options are:

  1. Return [-∞, +∞], which is technically correct but contains the true result in the most useless way possible. You have learned nothing.
  2. Declare the operation undefined and stop the computation.

Both approaches have serious consequences. Option 1 propagates through subsequent computations. Once you have [-∞, +∞] anywhere in your expression tree, every interval that depends on it also becomes [-∞, +∞]. The whole point of interval arithmetic, to give you useful, narrow bounds, evaporates. Option 2 simply fails, which prevents you from computing over any domain that includes the possibility of dividing by an interval crossing zero.

The same issue appears with any non-continuous function. The tangent function, for example, has discontinuities at π/2 + nπ for every integer n. If you evaluate tan([π/4, 3π/4]), the interval spans the discontinuity at π/2. On the left side of π/2, tan runs to +∞. On the right side, it jumps back from -∞. A single output interval would have to be [-∞, +∞], again maximally uninformative, even though the actual image of this input set under tan has a clear gap around zero and large portions of the real line excluded.

Interval Unions

The solution is to change the representation. Instead of requiring that the result of every operation be a single interval, you allow it to be a finite union of disjoint intervals. A value like (-∞, -1] ∪ [0.5, +∞) is a first-class citizen of this system, not an error or a degraded fallback.

This is the subject of a 2017 paper by Schichl, Domes, Montanher, and Kofler titled “Interval Unions.” The paper formalizes the arithmetic over unions of disjoint closed intervals and proves that the system is closed: any finite sequence of arithmetic operations over interval union inputs produces an interval union output. No operation can escape the representation. This is the “closed arithmetic system” property that standard interval arithmetic fails to have once you introduce division or discontinuous functions.

The division rule in interval union arithmetic handles the zero-crossing case by splitting it explicitly. When dividing by an interval [c, d] where c < 0 < d:

1 / [c, d]  →  (-∞, 1/c] ∪ [1/d, +∞)

For 1 / [-1, 2], this gives (-∞, -1] ∪ [0.5, +∞). The gap (-1, 0.5) is exactly the set of values that cannot be obtained by dividing 1 by any number in [-1, 2]. That is genuinely useful information: you know with certainty that your result is not in that range.

The TypeScript Calculator

Victor Poughon has built an open-source interval union calculator in TypeScript that makes this interactive. You can type an expression like 1 / [-1, 2] and see the union result immediately, with visual representation of the disjoint intervals on the real line.

The implementation is interesting for a few reasons. TypeScript is not the obvious choice for a project rooted in numerical analysis; you might expect C++ or Julia. But for an interactive web tool where the goal is accessibility and visualization, it is a reasonable decision. The arithmetic precision considerations that drive most interval arithmetic library choices, IEEE 754 rounding modes, directed rounding, outward rounding for correct enclosure, all still apply in JavaScript floating-point, but the environment is more constrained than native code.

The tan() implementation that the author mentions struggling with is a good example of what makes discontinuous functions hard. You cannot just apply Math.tan to both endpoints of the interval and call it done. You need to:

  1. Check how many discontinuities at π/2 + nπ fall within the input interval.
  2. Split the input at each discontinuity.
  3. Evaluate tan on each continuous sub-piece.
  4. Union the results.

If the input interval is wider than π, it contains at least one full period of tan and the output is all of (-∞, +∞). But for narrower inputs that avoid discontinuities, you get a precise, bounded union. Implementing this correctly requires explicit discontinuity detection, not just function evaluation.

How Other Languages Handle This

The standard-bearer for interval arithmetic in production scientific computing is Julia’s IntervalArithmetic.jl package. It implements IEEE 1788-2015, the international standard for interval arithmetic, and does careful work on rounding modes using Julia’s ability to control floating-point behavior at a low level. Julia’s multiple dispatch makes the operator overloading clean.

using IntervalArithmetic
x = interval(-1, 2)
result = 1 / x  # Returns the extended interval

IntervalArithmetic.jl handles the zero-crossing case using the extended real number system and “proper” intervals that can be unbounded, but it does not natively represent disjoint unions as a single output type. The result of dividing across zero produces a pair of intervals rather than a first-class union value.

In C++, the Boost Interval Arithmetic Library (part of Boost.Numeric) provides templated interval classes with configurable rounding policies. It is precise and well-engineered, but again operates on single intervals. The library’s policies let you control what happens at the zero boundary, typically by throwing an exception or returning an empty interval, rather than producing a union.

Python’s pyinterval library is notable because it actually does represent interval unions internally. The interval type in pyinterval is defined as a sorted sequence of disjoint components, which means division across zero works correctly by design:

from interval import interval, imath, inf
result = interval([1, 1]) / interval([-1, 2])
# Returns: interval((-inf, -1.0], [0.5, inf))

This is the behavior that Poughon’s calculator also provides, and it is more useful than anything you get from the major C++ or Julia implementations without additional post-processing.

Why This Matters Beyond Calculators

The gap between standard interval arithmetic and interval union arithmetic has practical consequences in several domains.

In constraint solving and global optimization, interval arithmetic is used to prune search spaces. When you are looking for roots of a function, you divide the domain into intervals and eliminate any interval where the function cannot be zero. Tighter, more precise intervals mean more aggressive pruning and faster convergence. An uninformative [-∞, +∞] that should be a union of two rays allows no pruning at all.

In robotics and control systems, intervals represent uncertainty in sensor measurements or actuator positions. Computing reachable sets under dynamics often requires evaluating functions over intervals. A robot planner that collapses a reachable set to [-∞, +∞] because of a division somewhere in the dynamics equations has learned nothing about safety.

In validated numerical methods, the goal is to produce a result with a rigorous proof that the true answer lies within the output interval. The INTLAB toolbox for MATLAB is widely used in this space. These methods depend on intervals remaining useful throughout a computation. The zero-crossing problem is handled by case analysis in most implementations, splitting the computation before the division, but this requires the programmer to anticipate where the issue arises rather than having the arithmetic handle it transparently.

Interval union arithmetic offers a path to making this transparent. If division across zero automatically produces a union instead of an error or an infinite interval, the arithmetic stays useful without requiring the user to restructure their computation.

The Representation Cost

The trade-off is representation complexity. A single interval requires two numbers. A union of n disjoint intervals requires 2n numbers and a data structure to hold them. Operations on unions are more expensive: adding two unions of size m and n respectively can produce a union of size up to m × n before simplification. Multiplication is worse.

In practice, interval unions in real computations tend to stay small. The divisions-across-zero and discontinuous-function evaluations that produce multi-component unions often produce unions of two or three components. The worst-case exponential blowup is a theoretical concern more than a practical one for typical applications.

There is also the question of when to simplify. Adjacent or overlapping intervals in a union should be merged. Checking every pair after every operation is expensive; doing it lazily risks unbounded growth. The Schichl et al. paper discusses this, and any real implementation has to make a policy decision about it.

Poughon’s calculator is primarily a demonstration and educational tool rather than a high-performance library, so it does not need to optimize for large unions. For production use in optimization solvers or validated computing, the representation cost would need more careful attention.

What Gets Fixed by Doing This Right

The reason interval arithmetic has not achieved wider adoption despite its clear value is partly the zero-crossing problem. Standard interval arithmetic is presented as a tool for rigorous computation, but “rigorous” becomes hollow when division frequently yields [-∞, +∞]. A developer who tries interval arithmetic for a real problem, hits this limitation, and switches back to floating-point has made a rational decision, even if the limitation has a known fix.

Interval union arithmetic makes the system what it was always supposed to be: a closed arithmetic where every operation produces a useful result. The Schichl et al. paper gave this a solid theoretical foundation. Implementations like pyinterval have demonstrated that the idea is practical. Poughon’s calculator makes it tangible and interactive for anyone who wants to understand why standard interval arithmetic falls short and what a better design looks like.

The field is still niche. It probably will not appear in your standard library any time soon. But the next time you are working on a problem where you care about rigorous bounds, and you run into the zero-crossing wall, it is worth knowing that the wall has a door.

Was this interesting?