Constructive Reals

A calculator that never rounds. Every digit it prints is correct — ask for more and it computes them. Compare it against what ordinary 64-bit floating point (the numbers JavaScript uses) produces.

An OCaml implementation of Hans-J. Boehm's Towards an API for the Real Numbers, running in your browser via js_of_ocaml.

Operators + - * / ( ) · functions sin cos tan asin acos atan exp ln sqrt abs max min · constants pi e

What is a constructive real?

A floating-point number has limited precision: 53 bits of mantissa, fixed at the moment each operation rounds. A constructive (or computable) real is a program: a function that, given a precision p, returns an integer n such that n·2p is within 2p of the true value. The digits slider controls how many digits of precision the program should compute.

How results are represented

When you type sqrt(2)*sqrt(2) - 2, the calculator first builds a term graph — multiplication node, square-root nodes, integer leaves — which you can inspect under "How is this represented?" on each result. Evaluation is lazy and demand-driven: asking the root for p bits makes each node ask its children for enough extra precision to keep its own error bound, all the way down to the leaves.

Each node also memoizes the best approximation it has produced so far (shown as ≈ value in the graph). Any time you ask for more digits the cached value deepens, and when you ask for less it reuses the cached answer. Terms that nothing has demanded yet are marked not evaluated — for instance, an expression's structure can be built and displayed without ever computing a single digit.

Where floats go wrong

Every float operation rounds to 53 bits, and the errors compound in characteristic ways, all reproducible above:

The float column isn't a simulation, by the way: this page compiles the calculator to JavaScript, so the float result is computed with actual JavaScript numbers — the same IEEE 754 doubles nearly every language uses.

The catch: equality

The price of never rounding is that equality of two constructive reals is undecidable. If two computations happen to denote the same number, comparing them digit-by-digit produces agreement forever and never terminates — you can't distinguish "equal" from "differs at some digit you haven't reached yet". So the API offers comparison up to a tolerance, and an equality that is only safe when the numbers are known to be unequal. Hans-J. Boehm's paper, which this library implements, shows how to recover decidable equality for the common cases by additionally tracking numbers symbolically — the trick that makes a real-number type practical for a calculator, where sqrt(2)*sqrt(2) - 2 should display exactly 0. (Relatedly: dividing by an exact zero here doesn't hang searching for a nonzero digit — it gives up with a precision overflow once the sign search passes a depth bound.)

This isn't just a demo trick

This representation ships in Google's Android calculator app, with over a billion installs: there, scrolling a result sideways drives the precision demand, and users never see a wrong digit. The design is described in Towards an API for the Real Numbers (Boehm, PLDI 2020); there's also a nice Twitter exposition of the main ideas. This page runs an OCaml implementation of the paper, compiled to JavaScript with js_of_ocaml (bignums via zarith_stubs_js), with all evaluation in a Web Worker so the page stays responsive while you ask π for 10,000 digits.