Mercury — Arbitrary-Precision Mathematics, From the Inside Out

Mercury is a native C library for arbitrary-precision floating-point arithmetic, with a .NET interface named UltraNumber. It is also an invitation to look inside the arithmetic: how a number is represented, how its pieces move, and how familiar operations emerge from those rules.

Choose a precision, follow the algorithms, and see how machine-level representation connects to addition, multiplication, division, roots, powers, and logarithms.

Conceptual visualization of arbitrary-precision arithmetic,
         with hexadecimal words flowing through computational structures.
Conceptual artwork for Mercury, evoking numerical structure rather than its literal memory layout.

A closer look at high-precision arithmetic

Ordinary floating-point types offer a fixed amount of precision. Arbitrary-precision arithmetic lets a program work with a chosen number of significant binary words instead. That makes it possible to explore calculations whose precision needs exceed the built-in types—and to study the algorithms that make those calculations work.

Mercury makes that process unusually visible. Its native representation and hexadecimal strings expose the relationship between mathematical values and machine-sized pieces. The project pairs a practical arithmetic engine with an educational series that follows the implementation from low-level operations toward powers and logarithms.

How Mercury represents numbers

A Mercury value is stored in a sequence of 32-bit words. The first word contains the sign flag, the next holds a signed exponent measured in base-2^32 word places, and the remaining words hold the mantissa. Each 32-bit limb corresponds to eight hexadecimal digits, so hexadecimal output gives a direct view of the stored precision.

At a glance: sign + word exponent + configurable mantissa limbs

Precision counts the 32-bit mantissa words. For example, 16 words provide 512 bits of mantissa storage; 64 words provide 2048 bits. The canonical reference includes additional precision examples and the exact buffer layout.

Arithmetic routines use a caller-supplied scratch stack for temporary work. The caller allocates the workspace, each operation takes and releases temporary regions in last-in, first-out order, and each thread needs its own stack. This makes temporary memory use explicit; the application must provide a stack large enough for the work it requests.

Explore the algorithms

These articles turn the implementation into a reading path. Start with the overview, then follow how each new operation builds on the previous one.

Mercury has landed

Meet the native engine, its hexadecimal view of numbers, and the role of the .NET wrapper.

Addition, subtraction, and aliasing

See how sign handling is separated from magnitude arithmetic, and why output can safely reuse an input buffer.

Carrying in base 2^32

Connect the familiar carry from grade-school addition to a 32-bit limb and a 64-bit register.

Multiplication and geometric scaling

Follow the multiplicative tier and how the places of two multiword values combine.

Division: preparing the table

Explore how precomputed multiples help turn a large division into structured lookup and subtraction work.

Division: sliding windows

See how the prepared table moves across the dividend as the quotient is constructed.

Squaring, roots, and halving

Explore the symmetry between squaring and square roots, and why successive roots halve an exponent step.

Powers by binary squaring

Learn how exponent bits avoid a long chain of repeated multiplication and how fractional powers fit the same picture.

Roots and logarithms as inverses

Follow root extraction back through powers, then watch logarithms construct the missing exponent.

Explore the implementation

The repository map places Mercury in the native C tier of JWCEssentials and identifies its managed companion as Mercury.net. The native API exposes arithmetic and advanced operations through C functions; the C# UltraNumber class adds familiar operators, parsing, conversion, and precision management.

Learn by experimenting

The documented UltraNumber example estimates Euler’s number by summing terms of its series. At 64 words, the working mantissa is 2048 bits. The result is printed in Mercury’s hexadecimal representation.

using Mercury.net;

UltraNumber.SetPrecisionAndAllocateStack(64, 1024 * 1024);

UltraNumber e = 0;
UltraNumber factorial = 1;

for (int n = 0; n < 200; n++)
{
    if (n > 0) factorial *= (double)n;
    e += 1.0 / factorial;
}

Console.WriteLine(e);

This small program is a useful first experiment: change the precision or number of terms, then compare the hexadecimal output. The example comes from the current Mercury reference; it requires the managed wrapper and the native Mercury library to be built and available to the process.

Why hexadecimal? Every eight hexadecimal digits correspond to one 32-bit word. When you increase Mercury’s precision, you can observe additional numerical detail without hiding the representation behind decimal formatting.

When NewAge is needed: NewAge is needed to build this repository’s projects in their documented arrangement. The native CMake target includes common build macros through the NewAge workspace, and the managed projects use NewAge paths for references and post-build staging. Follow the NewAge environment guide for that setup. Once built, using the library requires the native Mercury library to be discoverable by the process; it does not inherently require the NewAge workspace at runtime.

Follow the number all the way down

Read an algorithm, trace a limb, run an example, and inspect the source. Mercury is a working arithmetic library and a place to explore how mathematical ideas become loops, carries, comparisons, and carefully managed temporary memory.

Explore Mercury’s native code or begin with the Mercury article series.