bigfloat
Status: released v0.1.0.
go get github.com/go-bignum/bigfloat@v0.1.0Correctly 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 valueWhat is provided
| roots | Sqrt, Cbrt, Root(z, x, n), Hypot |
| exponentials and logarithms | Exp, Expm1, Log, Log1p, Log2, Log10, Pow |
| trigonometric | Sin, Cos, Tan, Asin, Acos, Atan, Atan2 |
| hyperbolic | Sinh, Cosh, Tanh, Asinh, Acosh, Atanh |
| constants | Pi, E, Ln2, Ln10, EulerGamma |
| oracle harness | package 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; onlyErrNaNandErrLimitmay 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.
| function | bits | bigfloat | mpmath 1.4.1 | ratio |
|---|---|---|---|---|
| atan (0.7) | 53 | 1.5 µs | 2.0 µs | 0.78 |
| log (1.7) | 1000 | 9.2 µs | 26.0 µs | 0.35 |
| exp (0.7) | 1000 | 13.8 µs | 33.1 µs | 0.42 |
| expm1 (0.7) | 53 | 1.6 µs | 8.7 µs | 0.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 modeoracle.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