Skip to content

bigfloat

Correctly rounded elementary functions and constants on math/big.Float, at any precision and in all six rounding modes.

Status: released v0.1.0.

go get github.com/go-bignum/bigfloat@v0.1.0

Correctly rounded elementary functions and constants on Go’s math/big.Float, at any precision and in all six rounding modes. Pure Go, no cgo, no dependencies.

import "github.com/go-bignum/bigfloat"

z := new(big.Float).SetPrec(113).SetMode(big.ToNearestEven)
bigfloat.Exp(z, x)    // e^x, correctly rounded to 113 bits
z.Acc()               // big.Below / big.Exact / big.Above: the side of the exact value

What is provided

rootsSqrt, Cbrt, Root(z, x, n), Hypot
exponentials and logarithmsExp, Expm1, Log, Log1p, Log2, Log10, Pow
trigonometricSin, Cos, Tan, Asin, Acos, Atan, Atan2
hyperbolicSinh, Cosh, Tanh, Asinh, Acosh, Atanh
constantsPi, E, Ln2, Ln10, EulerGamma
oracle harnesspackage oracle: mpmath driven from Go, correctly rounded reference values, golden fixtures; oracle.Self uses this package as the reference

The guarantee

Each function returns the exact result rounded to the receiver’s precision in the receiver’s rounding mode (ToNearestEven, ToNearestAway, ToZero, AwayFromZero, ToNegativeInf, ToPositiveInf) — the MPFR contract — and z.Acc() tells on which side of the exact value it lies, so results are reproducible bit for bit on every architecture and every Go version.

Conventions are math/big’s: a receiver of precision 0 takes the operand’s precision (64 bits for constants); the receiver may alias an operand; overflow gives ±Inf and underflow ±0 as big.Float’s arithmetic does; special values follow C99 Annex F. An operation whose result would be NaN panics with bigfloat.ErrNaN. big.Float.Sqrt itself is not correctly rounded in every mode; bigfloat.Sqrt is.

How: every approximation is a rigorous enclosure (midpoint-radius balls, fixed-point series with bounded error), evaluated by Ziv’s strategy — raise the working precision until the enclosure rounds to a single value. The algorithms and their references are in the library’s design document.

How it is verified

  • Golden fixtures from mpmath 1.4.1, generated by go run ./cmd/oracle: 28 840 cases over the 29 functions and constants, at 24, 53, 64, 113, 200 and 1000 bits (constants at every precision from 2 to 300 and at 500, 1000, 2000). Each case is checked in all six modes, value, sign of zero and accuracy: 173 040 results, all identical to the certified roundings.
  • Fuzzing (FuzzFunctions): every function, mode and precision against the oracle at more than twice the precision; only ErrNaN and ErrLimit may panic.
  • Special values and domain errors by table, unit tests of the error model, 100% statement coverage with -race, and the fixtures on amd64, arm64, 386, arm, riscv64, loong64, ppc64le and s390x in CI.

Resource bounds

Arguments may come from untrusted input: no input makes a function run unbounded. Trigonometric arguments are limited to an exponent of MaxReductionExponent (2^22; beyond it Sin, Cos, Tan panic with bigfloat.ErrLimit), the Ziv loop to 64·(p + argument precision) + 65536 bits, exact integer roots and powers to 2^20 bits of work. Details in the design document.

Performance

Every function is at or below mpmath’s time, bigfloat against mpmath 1.4.1 (pure-Python backend) at the same precision, one thread, interleaved rounds, best of each side (go run ./cmd/bench; Apple M4 Max, Go 1.27.1, measured 2026-10-21 under a one-minute load average of 6.5–8). The ratio bigfloat / mpmath is 0.18–0.97 at 53 to 200 bits and 0.27–0.92 at 1000 bits.

functionbitsbigfloatmpmath 1.4.1ratio
atan (0.7)531.5 µs2.0 µs0.78
log (1.7)10009.2 µs26.0 µs0.35
exp (0.7)100013.8 µs33.1 µs0.42
expm1 (0.7)531.6 µs8.7 µs0.18

For example atan at 53 bits went from 11.5 to 1.5 µs and log at 1000 bits from 76 to 9.2 µs during the performance pass that led to v0.1.0. The results stay correctly rounded against mpmath on 28 840 cases in all six rounding modes. bigfloat returns a certified Acc(); mpmath returns results within its working precision. The full table, every function at 53, 113, 200 and 1000 bits, is docs/perf.md; the benchmark program is cmd/bench.

The oracle, for other packages

m, _ := oracle.StartMpmath(nil) // uv run --with mpmath==1.4.1 …
defer m.Close()
r := &oracle.Rounder{Oracle: m} // or oracle.Self{}: no Python needed
res, _ := r.Round("atan2", 53, y, x) // one correctly rounded result per mode

oracle.Fixture and Case store and check results.

Licence

BSD 3-Clause. mpmath (BSD-3) is used as an oracle only; MPFR (LGPL) was a reference for the contract, not for code.

Created on by tannevaled

Modified on by tannevaled