Show HN: I made a calculator that works over disjoint sets of intervals (victorpoughon.github.io)
309 points by fouronnes3 32 days ago | 51 comments




Author here. Outward rounding to combat precision issues is what interval arithmetic is most known for (try 0.1+0.2 with "full precision mode" enabled), but that's really a shame in my opinion. Outward rounding is cool, but the "inclusion property", as it's known in research papers, works at every scale! This is what enables things like:

     50 * (10 + [-1, 1])
    [450, 550]
which is lovely, I think. Adding the union layer to it enables even cooler things, like the true inverse of the square function. Did you know it's not sqrt? Try 'sqinv(64)'.

I made interval calculator actually mostly as a way to test my implementation of interval union arithmetic [0], which I needed for another project: a backwards updating spreadsheet [1][2].

[0] https://github.com/victorpoughon/not-so-float

[1] https://victorpoughon.github.io/bidicalc/

[2] https://news.ycombinator.com/item?id=46234734

thekoma 32 days ago | flag as AI [–]

Nice! I am interested in how the arithmetic you implemented differs from the IEEE 1788 Standard for Interval Arithmetic (and how the two linked papers relate to it). To address the challenges you mention, did you have to start from scratch or was it something that can build on top of the IEEE standard?

Interesting! I'm not familiar with IEEE 1788. The TypeScript library (not-so-float) that I wrote which powers the calculator uses the JS Number type which is double precision IEEE 754. Outward rounding is not supported by JS so I used a bit level manipulation hack by casting to TypedArray [0] to implement the equivalent of C's nextafter() function. Otherwise I mostly followed Hickey & van Emden paper which is really delightful [1]. The real hard work is actually generating all the test cases. Good luck getting 100% test coverage on interval division!

[0] https://github.com/victorpoughon/not-so-float/blob/main/src/...

[1] https://fab.cba.mit.edu/classes/S62.12/docs/Hickey_interval....


Very cool, I'll definitely be playing around with this some more! Two questions:

- How difficult would it be to add many-valued functions to this? It would be really nice to be able to get the full set of [pi/2, pi/2] + n[2pi, 2pi] from asin(1) without needing to break out Mathematica.

- And:

> Numbers input by the user are interpreted as the smallest interval that contains the IEEE 754 value closest to the input decimal representation but where neither bounds are equal to it

Am I missing something obvious, or should this be the other way round, i.e. the output bounds are the closest two IEEE 754 numbers that contain the input number?

The way it's written I'd interpret the smallest interval to be IEEE754(input)+[-epsilon, epsilon] for infinitesimally small epsilon.

iamwil 32 days ago | flag as AI [–]

This is great. You might be interested in Matt Keeter's work on Implicit surfaces, and using interval math for its optimization:

https://youtu.be/UxGxsGnbyJ4?si=Oo6Lmc4ACaSr5Dk6&t=1006

memalign 32 days ago | flag as AI [–]

You might be interested in this graphing calculator I made using interval arithmetic:

https://memalign.github.io/m/formulagraph/index.html

Some detail on how this works, including links to the relevant interval math code:

https://memalign.github.io/p/formulagraph.html

0xml 31 days ago | flag as AI [–]

Looks like GrafEq?

http://www.peda.com/grafeq/

_Microft 32 days ago | flag as AI [–]

Very nice, thanks for sharing! Maybe show which upper or lower values are included in the intervals? A notation I am familiar with uses outward facing brackets if the value is not included in the interval. That always applies to infinity.

Applied to the cases here:

]-∞, -1] U [0.5, +∞[

The excluded interval in between becomes ]-1, 0.5[ then.

That’s how min (and analogously max) works, right? min(A, B) = [lo(A,B), lo (hi(A), hi(B))].

Edit: idea: copy a formula from the results section to the input field if the user clicks/taps on it.


I was also a bit confused by this. I thought the standard notation was round brackets, but maybe doesn't work well in ASCII?
qbit42 32 days ago | flag as AI [–]

Round brackets are standard in the US but that notation is used in France and some other places.
meindnoch 32 days ago | flag as AI [–]

  (0, 1)
Is this an twice-open interval or a 2D vector?

See, this is why Bourbaki introduced the ]0,1[ notation.

jdj49 32 days ago | flag as AI [–]

Round brackets were standard when I learned interval notation in the 80s. The outward-bracket style never really caught on outside French textbooks. ASCII rendering is the real issue — (0,1) reads as a coordinate pair too easily in monospace.
adito 32 days ago | flag as AI [–]

From reading the linked paper[0], It explains closed interval only. "An interval union is a set of closed and disjoint intervals where the bounds of the extreme interval can be ±∞".

[0]: https://www.ime.usp.br/~montanhe/unions.pdf


It's possible to support that but it makes the code very very much more complicated. I've decided early on to not support it. Would be a cool addition though!
akst 32 days ago | flag as AI [–]

Very cool! I don't entirely understand some of the operations, but for what I do understand its pretty neat.

I wish in classes we were introduced to a notion of arithmetic on intervals as it comes up. Like in basic statistics with confidence intervals there's ±, as well as in the quadratic equation. It found some what dissatisfying we couldn't chain the resulting a series of operations and instead repeat the operations for the 2 seperate values of the ±. I get a teacher would rather not get hung up on this because they want to bring it back to the application generally, like solving a more complicated equation or hypothesis testing in basic stats. I just wish they hinted at the idea we can do arithmetic on these kinds of things more generally.

I realise what you've got here is well beyond this, but seeing this was some level of validation that treating the interval as a piece of data with its own behaviour of certain operations does make some sense.

vishal_ch 30 days ago | flag as AI [–]

The division example is a perfect illustration of why this matters — [-∞, +∞] as an answer is technically correct but operationally useless. The union representation actually preserves information that standard interval arithmetic throws away. Curious about the composition behavior: if you chain multiple operations that each produce disjoint unions, does the number of intervals in the result grow exponentially in the worst case? And how does the implementation handle that — is there a merging/simplification step, or do you let it grow? The tan() implementation must have been painful given the infinite number of discontinuities.

I wish I had known about interval arithmetic when I first wrote tick, a time interval library in Clojure, which includes a. implementation of Allen's Interval Algebra. It also embraces the notion of sets of discrete intervals which are useful for practical work calculations, like determining the set of intervals of your vacations that are in a particular year (for HR calculations). I accidentally stumbled on benefits of these sets without knowing much beyond Allen's work.

https://github.com/juxt/tick

https://en.wikipedia.org/wiki/Allen's_interval_algebra

wvlia5 31 days ago | flag as AI [–]

Hey, what about this idea? redefine interval representation, such that [a, b] means the same if a<b; but if b<a, it means [-∞, b]U[a, +∞]. Then your example would become 1/[-1,2]=[0.5,-1]

That's a very cool idea :) It was proposed as far back as 1968 (!) in a paper by none other than the legend of floating point himself: Wiliam Kahan https://interval.louisiana.edu/historical-preprints/1968-Kah...

I recently implemented something somewhat similar, but from the perspective of set membership.

I therefore needed to include a complement operation, so that I could do full Boolean analysis of interval membership.

Your intervals are all closed sets, consequently the complements are open intervals. I chose not to distinguish between open and closed intervals, since for my practical purposes whether the end points are members of the set is unimportant.

Of course, with inexact arithmetic, the question of whether the set is open of closed probably not well-defined.

anematode 32 days ago | flag as AI [–]

Excellent!! I love interval arithmetic and also wrote a TS implementation for a graphing calculator project. Agree that it's very underrated, and I wish that directed rounding was exposed in more languages.

Yeah it's super interesting. Like you said, I learned that the IEEE 754 spec actually requires that complete implementations of floating point numbers expose a way to programmatically choose the rounding mode. As far as I know only C allows you to do that, and even then it depends on hardware support. For JS I had to use ugly typedarray casts. Which kinda only accidentally work due to endianess. But technically there should be an API for it!

There's other unused stuff in IEEE 754 like that: the inexact bit or signaling NaNs!


Julia supports full IEEE 754 rounding mode support.
ben85 32 days ago | flag as AI [–]

Rounding mode switches in production code are how you get heisenbugs that only show up under load. I've seen fewer things scarier on a pager at 3am than "works fine on my machine."
SkiFire13 31 days ago | flag as AI [–]

Expanding the logic to union of intervals looks cool, but what is the complexity of that? Since you introduce the the possibility of an operation on an interval producing two intervals I suspect executing N operations might have an exponential complexity, which unfortunately makes this unfeasible to use for some common intervals applciations like abstract interpretation, unless you start introducing approximations once you have enough intervals.
vector21 31 days ago | flag as AI [–]

We ran into this with static analysis at a previous job. The exponential blowup is real -- we hit it pretty fast in practice. We capped it at something like 4-6 intervals and merged eagerly when exceeded. Loses precision but stays tractable. The merging heuristic matters a lot though; naive convex hull is often too lossy.
lou1306 31 days ago | flag as AI [–]

Yes, this is well-known (eg. in abstract interpretation). As you said, usually you can set a "cap" to the size of these objects, and start merging intervals when you hit the cap. But at least in abstract interpretation it seems that they simply consider more sophisticated domains than intervals.

That’s neat … I wrote a simple Math::Interval library in Raku https://github.com/librasteve/raku-Math-Interval

This is based Raku’s built-in Junction and Range classes and was an interesting experiment.

JSR_FDED 32 days ago | flag as AI [–]

I just read up on interval arithmetic. I understand its desirable properties. Where in practice have you applied it? What’s a real world application for interval arithmetic?
ngruhn 32 days ago | flag as AI [–]

It can be used in static analysis or type checking. E.g.

    if (x >= 0) {
      x += 10
      if (x =< 9) {
        // unreachable 
      }
    }
By maintaining an interval of possible values of x, you can detect the unreachable branch, because the interval becomes empty:

    initial: [-oo, oo]
    x >= 0 : [0, oo]
    x += 10: [10, oo]
    x =< 9 : [10, 9] (empty)
nicolodev 32 days ago | flag as AI [–]

It’s astonishing how nobody hasn’t mentioned abstract interpretation yet. Under classical static analysis, if you can “prove” that a variable does not have values in some unsound zones, you can e.g. “prove” soundness or apply further optimizations.

The interval abstract domain works under interval analysis with an algebra that’s the same of this calculator. It’s funny to implement something like that on source/binary level :)

harbor51 32 days ago | flag as AI [–]

The clearest use case I've seen is guaranteed root-finding and global optimization - you can subdivide intervals and definitively exclude regions containing no solutions. Moore's original work from the 60s was motivated by exactly this: getting reliable bounds in scientific computation, not floating-point approximations that silently accumulate error.
nickcw 32 days ago | flag as AI [–]

In physics, whenever you make a measurement it has a precision. Usually you represent this as a normal distribution, but for calculations it can be easier to represent this as an interval.

The police measure the distance my car travelled [ 99.9, 100.1 ] m and the time it took [ 3.3, 3.4 ] s - how fast was my car going? [29.38, 30.33] m/s according to the interval calculator.

Physics students learn exactly this method before they move on to more sophisticated analysis with error distributions.

roger_ 31 days ago | flag as AI [–]

I can see valid uses of this but I also feel like a probabilistic calculator would be more useful.

e.g. the result for the 1 / [-1, 2] example doesn’t tell you how likely each value is and it clearly won’t be uniformly distributed (assuming the inputs are).

teiferer 32 days ago | flag as AI [–]

The last point in your intro description can't be stressed enough: this allows for safe handling of rounding errors in floating point operations.

Though you are inherently losing precision: there are values in the output interval which don't have a corresponding input that causes this output.

petters 32 days ago | flag as AI [–]

You could add a feature where it will compute the global optimum of any function of a small number of variables. Branch and bound with interval arithmetic works well for a small number of variables.

Disjoint unions of intervals seems like a nice thing to have

dfgtu 31 days ago | flag as AI [–]

Very nice work. I was wondering if it might be useful to combine this with a library for arbitrary precision arithmetic. How difficult do you think that might be?

Thanks! Arbitrary precision arithmetic is definitely something I'd like to learn more about, yeah. Haven't had time to study it so much yet unfortunately.
ttoinou 32 days ago | flag as AI [–]

Why not use disks / exterior disks in the complex numbers plane instead of intervals ? It might make the mental model easier to reason about
adaptit 31 days ago | flag as AI [–]

This interval calculator is surprisingly robust. The way it handles boundary conditions and asymmetric intervals is clean and efficient.

Interals can be used to model errors and uncertainty and this lets you see how they conpound in calculations like speed = distance over time.
Eric_Xua 31 days ago | flag as AI [–]

Really cool project—turning interval unions into a usable, polished calculator makes the math feel practical.
mbo 31 days ago | flag as AI [–]

Could this support a native datetime type? I shipped a much worse of this for managing repeated events and schedules.
zamadatix 31 days ago | flag as AI [–]

Naively, what breaks by doing datetime -> epoch -> interval -> datetime over some other form of implementation?

I tend to avoid datetimes as much as working with printers because the answer is always "more annoying than you'd first think" :D.

Falimonda 31 days ago | flag as AI [–]

Random example generator would be nice

have you considered implementing a +- operator?

For example a +- b would be [a - b, a + b]


This is great
boobsbr 32 days ago | flag as AI [–]

Neat.
lou1306 31 days ago | flag as AI [–]

Sorry to be a party pooper, the Web app is neat, but I have some reservations about the paper.

Namely, the "powerset of intervals" domain has been known since the '70s [1], and powerset domains have been generalised to arbitrary base domains decades ago [2]. A paper from the mid-2010s on these topics that lacks any engagement with the abstract interpretation literature is a bit disappointing.

As for the interpretation of division suggested here, it makes, say, 1 / S non-distinguishable from 1 / ([0, 0] U S) for any set of intervals S, which sounds suspicious.

[1] Patrick Cousot and Radhia Cousot. 1979. Systematic Design of Program Analysis Frameworks. In 6th ACM Symposium on Principles of Programming Languages (POPL), January 1979. ACM Press, San Antonio, TX, USA, 269–282. https://doi.org/10.1145/567752.567778

[2] Gilberto Filé and Francesco Ranzato. 1999. The Powerset Operator on Abstract Interpretations. Theor. Comput. Sci. 222, 1–2 (1999), 77–111. https://doi.org/10.1016/S0304-3975(98)00007-3


Thank you for creating and sharing something that feels authentic and human made. No sign of AI vibe coded slop at all. It's beautiful.
ember81 31 days ago | flag as AI [–]

Curious how the interval count behaves with depth. Division by an interval containing zero produces two pieces, and each subsequent operation can split those further. Does a moderately complex expression end up with dozens of disjoint intervals in practice? Has anyone benchmarked where this breaks down?

I don't handle it, ahah. You are right that if you take any classical numerical computing algorithm and replace the floating point reals by interval unions, most of the time the number of intervals in the unions in each of your variables will grow very fast. This is one of the problems of unions and as far as I'm aware it's a topic of active academic research.