decimal

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 10, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

README

Decimal

CI Go Reference

Exact, arbitrary-precision decimal arithmetic for Go, in pure Go with no dependencies outside the standard library.

Go has no decimal type. Binary floating point cannot represent 0.1, and the systems Go programs talk to (SQL DECIMAL columns, JSON, financial protocols) are decimal. decimal provides immutable, finite decimal values whose semantics follow the General Decimal Arithmetic model and IEEE 754 decimal rounding:

  • Exact by default. Add, Sub and Mul never round; Div returns a terminating quotient exactly and otherwise refuses. Rounding happens only where the code asks for it, once, under a named mode, and every rounding reports what it did.
  • No panics on input. Every failure is a returned *Error; only MustParse, meant for literals, panics.
  • Resource-bounded. Coefficients are unbounded, so every operation whose work depends on input size has a budgeted form that refuses before allocating. Untrusted text, JSON and database values cannot make a call do unbounded work.
  • Allocation-disciplined. Values below 2^128 are stored inline: arithmetic, parsing and formatting into a caller's buffer (AppendText, AppendFixed, …) allocate nothing on them; the string-returning forms allocate only their result.
  • Portable. CGO_ENABLED=0, no unsafe, no assembly. Building with GOEXPERIMENT=simd adds a portable-SIMD digit scanner for []byte input; both builds pass the same suite, and results are bit-identical on every platform, including 386, arm64 and js/wasm.

Install

go get github.com/0xCarbon/decimal

Requires Go 1.27.1 or newer.

Quick start

package main

import (
	"fmt"

	"github.com/0xCarbon/decimal"
)

func main() {
	price := decimal.MustParse("19.99")
	quantity := decimal.FromInt64(3)
	subtotal, err := price.Mul(quantity) // exact: 59.97
	if err != nil {
		panic(err)
	}
	rate := decimal.MustParse("0.0825")
	tax, err := subtotal.Mul(rate) // exact: 4.947525
	if err != nil {
		panic(err)
	}
	tax, _, err = tax.Quantize(-2, decimal.TiesAwayFromZero) // round to cents
	if err != nil {
		panic(err)
	}
	total, err := subtotal.Add(tax)
	if err != nil {
		panic(err)
	}
	fmt.Println(subtotal, tax, total) // 59.97 4.95 64.92
}

Rounding with a context, and reading what the rounding did:

ctx := decimal.Decimal64Context() // 16 digits, TiesToEven
q, conditions, err := decimal.MustParse("1").DivWithContext(decimal.MustParse("3"), ctx)
fmt.Println(q, conditions, err) // 0.3333333333333333 Inexact|Rounded|Decreased <nil>

_, err = decimal.MustParse("1").Div(decimal.MustParse("3"))
fmt.Println(errors.Is(err, decimal.ErrInexact)) // true: 1/3 does not terminate

More runnable examples are in example_test.go and on pkg.go.dev.

Features

  • Values keep their scale. A Decimal is a coefficient and an int32 exponent. 1.10 and 1.1 are equal numbers (Equal, Compare, Hasher) but keep their own text and Exponent(). Reduce normalizes explicitly. Decimal is deliberately not comparable with ==, so two spellings of one number can never become two map keys by accident.
  • Seven rounding modes plus Exact. TiesToEven (the zero value), TiesAwayFromZero, TiesTowardZero, TowardZero, AwayFromZero, TowardPositiveInfinity and TowardNegativeInfinity; Exact refuses any rounding that changes the value. Each rounding returns Conditions (Inexact, Rounded, guard events) and its direction.
  • Contexts. A Context carries precision, rounding mode, optional exponent guards, traps and a resource budget. It is an immutable value passed to each call; there is no global state. Decimal32Context, Decimal64Context and Decimal128Context give the IEEE 754 precisions.
  • Rounding to a target. Quantize, RoundToPrecision, RoundToIntegral, RoundToMultiple (cash increments), DivToExponent and ParseToExponent (SQL CAST(text AS DECIMAL(p,s))) round exactly once.
  • Integer division and fused multiply-add. Quo, Rem and RemNear are exact; FMAWithContext rounds x·y + z once.
  • Correctly rounded functions. Sqrt, Pow, Exp, Ln, Log10, PowDecimal, Sin, Cos, Tan, Asin, Acos, Atan, Atan2, Sinh, Cosh, Tanh, Asinh, Acosh and Atanh are correctly rounded in every mode under a context: the exact result, rounded once. The bare forms return the exact value or refuse. The argument and the tests behind each claim are in docs/reference/correct-rounding.md.
  • Display. Text/String (canonical, round-trips), Fixed, Scientific, Engineering, Append… forms and the fmt verbs %v %s %f %e with width and precision.
  • Interoperation. encoding.TextMarshaler/TextUnmarshaler/ TextAppender; JSON as a bare number out and a number or string in, never through float64; database/sql Valuer and Scanner, NullDecimal and the decompose-based SQLDecimal; exact conversion to and from int64, uint64, big.Int, big.Rat and 128-bit or two's-complement coefficients (Parquet, Arrow); float64 conversion that treats a double as the exact binary rational it is, with FromFloat64 for shortest digits and CompareFloat64 for ordering without conversion.

API overview

Operations that may round come in two forms:

Form Returns Meaning
x.Add(y) (Decimal, error) the exact result, or an error
x.AddWithContext(y, ctx) (Decimal, Conditions, error) rounded once under ctx, with the conditions it raised

Context{} is exact, so AddWithContext(y, Context{}.WithBudget(b)) is the budgeted exact sum. Operations that round to a fixed target or never round take a Budget in one …WithBudget form (DivToExponentWithBudget, SumWithBudget, ParseJSONWithBudget, ScanWithBudget).

  • Budget caps input bytes, digits, output bytes and work units. A zero field means no limit on that axis; a refusal is an error matching ErrInsufficientStorage, raised before anything is allocated. A budget never changes a result.
  • Estimators. EstimateAdd, EstimateParse, EstimateFixed and their peers compute a call's Cost from operand Shapes before the call; Cost.Budget() builds a budget that admits it. BoundEvaluation turns the budget of an adaptive function (Exp, Ln, Log10, PowDecimal and the trigonometric and hyperbolic functions, whose working precision grows until the rounding is proved) into a heap bound.
  • Error. Every operation failure is an *Error with the operation, an ErrorCode cause for errors.Is (ErrInexact, ErrDivisionByZero, ErrConversionSyntax, ErrInsufficientStorage, …), and the condition, remedy, input or exhausted quota where they apply.

For untrusted input, parse with a budget:

ctx := decimal.Context{}.WithBudget(decimal.Budget{MaxInputBytes: 64, MaxDigits: 40})
d, _, err := decimal.ParseWithContext(input, ctx)

Documentation

  • Semantics reference (docs/reference/semantics.md): value model, cohorts, contexts, conditions, errors and budgets
  • API guide (docs/api-guide.md): naming, choosing a call, handling results
  • Cookbook (docs/cookbook.md): money rounding and map keys
  • Interop guide (docs/interop.md): database/sql and a driver matrix, SQL DECIMAL(p,s) columns, JSON, binary coefficients and float64
  • Correct rounding (docs/reference/correct-rounding.md): the argument and tests behind each correctly rounded operation
  • Design rationale (docs/rationale.md): why the value space, precision model, rounding catalog, budgets and API are what they are
  • Architecture: repository layout and verification
  • The package documentation: go doc -all github.com/0xCarbon/decimal

Performance

The benchmark portfolio (families F1–F8: parsing, aggregation, a money loop, formatting, map keys, tight 19-digit arithmetic, JSON and database/sql) runs the same workloads through decimal and four other Go decimal libraries (the incumbents): shopspring/decimal v1.4.0, cockroachdb/apd v3.2.3, ericlagergren/decimal and govalues/decimal v0.1.36. Every row first checks its results against a math/big oracle; a library that cannot produce the oracle's result for a workload is excluded from that row rather than timed.

The table gives medians of 10 interleaved rounds (AMD Ryzen 9 5900XT, two pinned cores of a shared host, Go 1.27.1 linux/amd64, built with GOEXPERIMENT=simd, 2026-11-10). Speedup is the fastest incumbent's time divided by decimal's time, using the medians shown (above 1.00x is faster).

family workload fastest incumbent decimal time incumbent time speedup
F1 parse "1234.56" govalues 10.9 ns 21.0 ns 1.93x
19-digit integer govalues 12.7 ns 48.2 ns 3.80x
40 digits shopspring 58.9 ns 321 ns 5.45x
exponent form ericlagergren 12.3 ns 56.5 ns 4.59x
F2 aggregate 1000 exact mixed-scale additions govalues 4.60 µs 7.70 µs 1.67x
F3 money loop price × qty, round to cents, fee (256 lines) ericlagergren 3.27 µs 12.8 µs 3.91x
F4 format plain govalues 18.3 ns 19.1 ns 1.04x
fixed, 2 places govalues 24.8 ns 23.4 ns 0.94x
scientific apd 27.6 ns 125 ns 4.53x
F5 map key 1024 string keys govalues 116 µs 133 µs 1.15x
F6 tight arithmetic add, 19 digits ericlagergren 4.60 ns 20.8 ns 4.52x
multiply, 19 digits ericlagergren 3.95 ns 22.0 ns 5.57x
divide to 2 places shopspring 13.1 ns 229 ns 17.48x
divide by 4 apd 12.5 ns 170 ns 13.60x
compare shopspring 2.70 ns 6.05 ns 2.24x
F7 JSON encode + decode, bare number govalues 43.3 ns 49.5 ns 1.14x
encode + decode, quoted number govalues 39.6 ns 49.8 ns 1.26x
F8 database/sql Valuer + Scan govalues 720 ns 733 ns 1.02x
SQLDecimal compose apd 583 ns 601 ns 1.03x
NullDecimal round trip govalues 706 ns 703 ns 1.00x

The speedups of F1 to F3, F4 scientific and F5 to F7 are significant (Mann–Whitney, p < 0.001), and in those rows decimal allocates no more than the best incumbent, usually nothing. In F4 plain and in F8 the samples of decimal and of the fastest incumbent overlap: treat those rows as ties. In F4 fixed, govalues is faster by the margin shown. F8 is the one family where decimal uses more memory: a Decimal is 32 bytes, so the driver.Value round trip and the value-shaped SQLDecimal/NullDecimal wrappers move 32–48 more bytes per row (and one more allocation in compose), which the database round trip itself dwarfs.

To reproduce:

make bench-incumbents BENCH_COUNT=10   # writes dist/incumbents.txt
go run ./tools/benchcmp -dominance -ref decimal dist/incumbents.txt

See benchmarks/incumbents/README.md for the method and what each family measures. Absolute times vary with the host; compare libraries only within one interleaved run on one machine.

Development

make check        # vet, gofmt, checkdeps, checkstate, tests in both profiles
make conformance  # download the decTest corpus and run it
make fuzz-smoke   # 20 s per fuzz target
make bench        # benchmark portfolio

See CONTRIBUTING.md for the workflow and rules.

Support and security

Questions and bug reports go to GitHub issues. Report vulnerabilities privately as described in SECURITY.md. Participation is governed by the code of conduct. Release notes are in CHANGELOG.md.

License

Copyright 2026 0xCarbon. Licensed under Apache-2.0; see LICENSE.

Documentation

Overview

Package decimal provides exact, immutable, finite decimal numbers with arbitrary-size coefficients and int32 base-ten exponents, implemented in pure Go with no dependencies outside the standard library.

A Decimal is a coefficient and an exponent: 1.10 is 110×10⁻² and stays distinct from 1.1 (11×10⁻¹) in text and accessors, while Decimal.Equal, Decimal.Compare and Hasher use numeric equality across such cohorts. Values below 2¹²⁸ are stored inline without allocation; larger coefficients use immutable base-10⁹ limbs that copies share safely. An operation whose operands and result are inline allocates nothing; one whose operands and result stay within 81 digits (every product or sum of two 38-digit values) allocates at most once, and a longer result at least twice (division beyond 48 limbs also allocates its working buffer). The zero value is 0. The value space is finite: there are no NaNs, infinities or negative zero.

Construction and text

Parse, MustParse, New, FromInt64, FromUint64 and FromBigInt preserve the constructed coefficient and exponent. Decimal.Text and Decimal.String emit canonical text for that cohort, Decimal.AppendText appends it without allocating, and Decimal.Reduce makes normalization explicit. Decimal.Exponent and Decimal.CoefficientDigits report the stored scale.

Arithmetic

Decimal.Add, Decimal.Sub and Decimal.Mul are exact and never round: they return the exact result at the ideal exponent or an error. Rounding is always explicit, through a Context (precision, a RoundingMode, optional exponent guards and traps) in the WithContext forms, or through Decimal.Quantize and Decimal.RoundToIntegral. Every context operation reports the GDA Conditions it raised; trapped conditions return an *Error. Every inexact rounding also reports Increased or Decreased, the side of the exact value its result lies on (Conditions.Direction); these two are never trappable. The zero RoundingMode is TiesToEven, and Exact refuses any value-changing round. Monetary code should name its mode, usually TiesAwayFromZero; the RoundingMode documentation has a worked table of every mode, and docs/cookbook.md collects the recipes.

TowardNegativeInfinity never reports Increased and TowardPositiveInfinity never reports Decreased, so the two bracket the exact value, unless Overflow is also reported: a guarded overflow substitutes the finite largest value in every mode (for example TowardPositiveInfinity can return it with Decreased|Overflow), and such a result is no finite bound.

Decimal.Div returns a terminating quotient exactly (1/4 is 0.25) and refuses a non-terminating one such as 1/3 with a remedy instead of choosing a scale. Decimal.DivWithContext rounds the quotient once to the context precision; Decimal.DivToExponent rounds it once to a fixed exponent, the shape of SQL DECIMAL division and AVG. A zero divisor returns ErrDivisionByZero, or ErrDivisionUndefined for 0/0.

Decimal.Quo returns the truncated integer quotient at exponent 0, and Decimal.Rem and Decimal.RemNear the exact remainders x − q·y and x − n·y (n nearest, ties to even) at the smaller operand exponent: 10.5 Rem 3 is 1.5 and 3 Rem 0.29 is 0.10. They never round; a finite context precision refuses a quotient longer than p with ErrDivisionImpossible. A remainder never materializes the quotient, so 1E+2147483647 Rem 7 costs a few hundred limb operations.

Rationals follow the same policy. FromRat converts a terminating *big.Rat exactly (3/40 is 0.075) and refuses 1/3 with the same remedy; FromRatWithContext and FromRatToExponent round it once, and Decimal.Rat returns the value as an exact *big.Rat in lowest terms.

Doubles are exact binary rationals. FromFloat64Exact expands one exactly (0.1 is 0.1000000000000000055511151231257827021181583404541015625), while FromFloat64 keeps strconv's shortest round-trip digits (0.1). FromFloat64ToExponent and FromFloat64WithContext round the exact value once from a stack expansion, without heap allocation. Decimal.Float64 and Decimal.Float64Rounded return the double selected by a mode, together with Conditions that report exactness, direction, and IEEE 754 overflow and underflow, so the floor and ceiling bracket the decimal. Decimal.CompareFloat64 orders a decimal against a double without converting either one. Their work does not grow with the exponent: at most one exact comparison, and only when a rounding boundary lies within 2^−59 of the value, relative to it.

Rounding has two explicit targets and never happens implicitly. Decimal.Quantize rounds to a stored exponent and Decimal.RoundToPrecision to a number of significant digits, each once under a supplied mode. Decimal.RoundToMultiple rounds to a multiple such as a cash increment (2.525 to 0.05 is 2.50 under TiesToEven), deciding on the exact quotient so it never double-rounds.

Decimal.FMAWithContext rounds the exact x·y + z once, so it can differ from MulWithContext then AddWithContext, which round twice; with Context{} it returns the exact sum, as Mul then Add would.

Decimal.Sqrt returns an exact root or refuses, as Div does for a non-terminating quotient; Decimal.SqrtWithContext rounds the root once, correctly in every mode, deciding ties from the exact remainder (docs/reference/correct-rounding.md).

Decimal.Pow takes an int32 exponent and returns the exact power, the repeated-multiplication cohort (1.10² is 1.2100), or refuses a non-terminating reciprocal; Decimal.PowWithContext rounds x^n once, correctly in every mode (docs/reference/correct-rounding.md). 0⁰ is 1, the empty product, where GDA's power gives NaN (a documented deviation).

Decimal.Exp, Decimal.Ln, Decimal.Log10 and Decimal.PowDecimal (a Decimal exponent) are correctly rounded: their context forms round once, correctly in every mode (docs/reference/correct-rounding.md): the value is enclosed between certified directed bounds at a working precision that doubles until the bounds prove the rounding, with no guard-digit guess or iteration cap. Mathematical exactness alone decides Inexact: Exp(0) is 1, Ln(1) is 0, Log10(1000) is 3 and 4^0.5 is exactly 2, and an exact tie such as 2.25 = (81/16)^0.5 at two digits rounds as a tie. The bare forms return exact values or refuse as Div does. A negative Ln or Log10 operand, and a negative base with a noninteger exponent, are invalid; zero is ErrDivisionByZero. Their Budget bounds a whole attempt, success or refusal, and BoundEvaluation turns it into a heap bound.

The trigonometric and hyperbolic functions (Decimal.Sin, Decimal.Cos, Decimal.Tan, Decimal.Asin, Decimal.Acos, Decimal.Atan, Decimal.Atan2, Decimal.Sinh, Decimal.Cosh, Decimal.Tanh, Decimal.Asinh, Decimal.Acosh, Decimal.Atanh) use the same machinery, in radians: exact at their zero or one arguments, correctly rounded in every mode otherwise (docs/reference/correct-rounding.md). Reducing a huge argument modulo π/2 needs π to about as many digits as the argument's exponent; that work is charged, so a finite budget refuses it first.

Each correctly rounded operation's argument, the test that checks its reduction or enclosure, and its validating named cases are listed in docs/reference/correct-rounding.md.

ParseToExponent and ParseWithContext round a literal once while parsing it, the shape of SQL CAST(text AS DECIMAL(p,s)): only the result's digits are stored, so a long literal rounded to a short result allocates nothing, and an exponent far below int32 rounds by value (1e-99999999999 at exponent −2 is 0.00). The parse family is generic, so a string or a []byte is parsed in place.

Resource budgets

Decimal coefficients can grow without bound, so every operation whose cost depends on its inputs takes a Budget. An operation that rounds to a precision reads it from its Context (Context.WithBudget; with Context{} the computation stays exact), and an operation with an explicit target or no rounding takes it as a parameter (Decimal.DivToExponentWithBudget, ParseJSONWithBudget, Decimal.FixedWithOptions and so on). A budget only refuses work before allocating; it never changes a result. Zero fields mean no caller limit.

To charge its own meter before calling, a caller asks an estimator: EstimateMul, EstimateDiv, EstimateFromRat, EstimateParse and their peers take operand Shape values (from Decimal.Shape) or sizes and return a Cost: the work units, digits, bytes and heap allocation the call can consume, without allocating. A budget built from a Cost (for example Cost.Budget) always admits the call, and within a family time is affine in charged units, so a work cap bounds latency. The adaptive functions have no completion estimate: their Budget caps evaluation units shared by every phase of one attempt, and BoundEvaluation bounds its cumulative heap.

Display and interoperation

Decimal.Fixed, Decimal.Scientific and Decimal.Engineering render with explicit digits and rounding; Decimal.Format supports the %v, %s, %f and %e verbs; %+v is %v and %#v is decimal.MustParse("text"). Decimal implements encoding.TextMarshaler, encoding.TextUnmarshaler, encoding.TextAppender, json.Marshaler, json.Unmarshaler and driver.Valuer. NewInt128, Decimal.CoefficientInt128, NewTwosComplement and Decimal.AppendTwosComplement exchange the exact coefficient with 128-bit storage lanes and Parquet or Arrow two's-complement bytes, the exponent carried separately. With database/sql, a Decimal binds as canonical text and Decimal.Scan reads text, every int and uint type, float64 and float32 (as their exact binary value) and any engine's exact decimal through the decompose convention; NullDecimal carries SQL NULL. SQLDecimal opts a value into decompose binding for drivers that type parameters by value. JSON emits bare numbers and accepts numbers or strings. Decimal.Int64, Decimal.Uint64 and Decimal.BigInt convert exactly or fail; FromBigIntWithBudget and Decimal.BigIntWithBudget bound the work with a Budget.

Equality and keys

Decimal is deliberately not comparable: == and map[Decimal]V do not compile, because two cohorts of one number would otherwise differ. Use Decimal.Equal, a text key from d.Reduce().Text(0), or Hasher with a caller-owned maphash.Hash for hash tables.

Errors

Every operation failure is an *Error: errors.Is matches its ErrorCode, or for a trapped condition set the code of each trapped condition; the Estimate functions and BoundEvaluation return a bare ErrorCode. An Error's Op names the exported function (Text for every text encoder), Condition the GDA condition, Input the text of a parse failure, Remedy the instruction that avoids a refusal, and Resource and Limit an exhausted elementary-function quota. Values are immutable and safe for concurrent use.

Documentation

The repository's docs directory holds the rest of the documentation set: docs/reference/semantics.md (the value model, cohorts, contexts, conditions, errors and budgets), docs/api-guide.md (how the API is organized and which call fits a task), docs/cookbook.md (recipes, including map keys that span Decimal and float64), docs/interop.md (database/sql, SQL DECIMAL(p,s) columns, JSON and binary lanes), docs/reference/correct-rounding.md (the correctly rounded operations and how each is verified) and docs/rationale.md (why the design is what it is). Their Go examples are the runnable examples of this package.

Example
package main

import (
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	price := decimal.MustParse("19.99")
	quantity := decimal.FromInt64(3)
	subtotal, err := price.Mul(quantity) // exact: 59.97
	if err != nil {
		panic(err)
	}
	rate := decimal.MustParse("0.0825")
	tax, err := subtotal.Mul(rate) // exact: 4.947525
	if err != nil {
		panic(err)
	}
	tax, _, err = tax.Quantize(-2, decimal.TiesAwayFromZero) // round to cents
	if err != nil {
		panic(err)
	}
	total, err := subtotal.Add(tax)
	if err != nil {
		panic(err)
	}
	fmt.Println(subtotal, tax, total)
}
Output:
59.97 4.95 64.92

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func FromFloat64ToExponent

func FromFloat64ToExponent(f float64, exponent int32, mode RoundingMode) (Decimal, Conditions, error)

FromFloat64ToExponent rounds the exact value of a finite f once to the given exponent under mode, the shape of SQL CAST(DOUBLE AS DECIMAL(p,s)): FromFloat64ToExponent(2.675, -2, TiesToEven) is 2.67 because the double lies below the tie. Results, Conditions and error identities equal FromRatToExponent of the double's exact rational, except physical admission, which is path-specific. The exact expansion (at most 767 digits) lives on the stack, so 1e-300 at exponent −2 is a 0.00 without heap allocation, and results of at most 38 digits allocate nothing.

func FromFloat64ToExponentWithBudget

func FromFloat64ToExponentWithBudget(f float64, exponent int32, mode RoundingMode, budget Budget) (Decimal, Conditions, error)

FromFloat64ToExponentWithBudget is FromFloat64ToExponent with copied quotas: the charge B is 87 work units per expansion pass plus one per padded limb, the whole tariff is W = B + 2N + 1 for an N-digit result, and MaxDigits caps N. Every quota is checked before the result is allocated.

func FromFloat64WithContext

func FromFloat64WithContext(f float64, ctx Context) (Decimal, Conditions, error)

FromFloat64WithContext rounds the exact value of a finite f once to the context precision with its guards and traps: the IEEE 754 convertFormat from binary64 to a decimal format such as Decimal64Context. Results, Conditions and error identities equal FromRatWithContext of the double's exact rational, except physical admission, which is path-specific. The expansion is bounded by 767 digits, but a guarded overflow publishes the context's largest value, whose p digits are bounded only by the precision; a budget on the context caps them. Precision 0 converts exactly.

func FromRatToExponent

func FromRatToExponent(r *big.Rat, targetExponent int32, mode RoundingMode) (Decimal, Conditions, error)

FromRatToExponent rounds the rational once to exactly targetExponent under mode, with unlimited precision and no guards or traps.

func FromRatToExponentWithBudget

func FromRatToExponentWithBudget(r *big.Rat, targetExponent int32, mode RoundingMode, budget Budget) (Decimal, Conditions, error)

FromRatToExponentWithBudget is FromRatToExponent with checked quotas.

func FromRatWithContext

func FromRatWithContext(r *big.Rat, ctx Context) (Decimal, Conditions, error)

FromRatWithContext rounds the rational once to the context precision under its mode, guards and traps, as DivWithContext rounds a quotient.

Example
package main

import (
	"errors"
	"fmt"
	"math/big"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	third := big.NewRat(1, 3)
	down, _ := decimal.NewContext(7, decimal.TowardNegativeInfinity, nil, 0)
	up, _ := decimal.NewContext(7, decimal.TowardPositiveInfinity, nil, 0)
	lo, lc, _ := decimal.FromRatWithContext(third, down)
	hi, hc, _ := decimal.FromRatWithContext(third, up)
	fmt.Println(lo, lc, hi, hc)
	_, err := decimal.FromRat(third)
	fmt.Println(errors.Is(err, decimal.ErrInexact))
	exact, _ := decimal.FromRat(big.NewRat(3, 40))
	back, _ := exact.Rat(nil)
	fmt.Println(exact, back)
}
Output:
0.3333333 Inexact|Rounded|Decreased 0.3333334 Inexact|Rounded|Increased
true
0.075 3/40

func ParseToExponent

func ParseToExponent[T Literal](s T, exponent int32, mode RoundingMode) (Decimal, Conditions, error)

ParseToExponent rounds the literal's exact value once to the given exponent under mode, the shape of SQL CAST(text AS DECIMAL(p,s)). Whenever Parse succeeds it equals Parse followed by Quantize in value, cohort, Conditions and error identity; it also rounds literals whose effective exponent lies below int32 (1e-99999999999 at −2 is 0.00). A nonzero literal whose effective exponent exceeds int32 returns ErrExponentRange. Work is O(len(s) + result digits) and only the result's digits are stored, so a long literal rounded to a short result allocates nothing when the result is inline. Untrusted text should use ParseToExponentWithBudget: a far target pads up to 2^32 zeros.

Example
package main

import (
	"errors"
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	price, conditions, _ := decimal.ParseToExponent("19.995", -2, decimal.TiesToEven)
	fmt.Println(price, conditions)
	tiny, _, _ := decimal.ParseToExponent([]byte("1e-99999999999"), -2, decimal.TowardPositiveInfinity)
	fmt.Println(tiny)
	_, err := decimal.Parse("1e-99999999999")
	fmt.Println(errors.Is(err, decimal.ErrExponentRange))
}
Output:
20.00 Inexact|Rounded|Increased
0.01
true

func ParseToExponentWithBudget

func ParseToExponentWithBudget[T Literal](s T, exponent int32, mode RoundingMode, budget Budget) (Decimal, Conditions, error)

ParseToExponentWithBudget is ParseToExponent with Budget quotas: MaxInputBytes counts len(s) before scanning, and MaxDigits caps the result's coefficient digits before it is allocated.

func ParseWithContext

func ParseWithContext[T Literal](s T, ctx Context) (Decimal, Conditions, error)

ParseWithContext rounds the literal's exact value once to the context precision with its guards and traps (GDA to-number in a non-clamping context): a value that fits the precision keeps its written exponent unless guards raise it to Etiny, precision 0 converts exactly, and guards resolve out-of-range exponents by Subnormal, Underflow or Overflow. A zero keeps its written exponent unclamped. Work is O(len(s)) plus the result's digits.

Types

type Budget

type Budget struct {
	// MaxInputBytes caps the source bytes of text, JSON and Scan input.
	MaxInputBytes uint64
	// MaxInputDigits caps the source digits of an integer conversion.
	MaxInputDigits uint64
	// MaxDigits caps the result coefficient digits.
	MaxDigits uint64
	// MaxOutputBytes caps rendered text.
	MaxOutputBytes uint64
	// MaxWork caps the family's work units.
	MaxWork uint64
}

Budget caps the resources of one call; each Estimate function returns the Cost whose Budget admits it. Operations that round to a precision read it from their Context (Context.WithBudget); operations with an explicit target exponent or no rounding take it as a parameter. Zero on an axis means no caller limit on that axis, and a family ignores the axes it does not read:

  • Context arithmetic, FromRat, FromFloat64, Sum and the target forms DivToExponent, RoundToMultiple, FromRatToExponent and FromFloat64ToExponent read MaxDigits (result coefficient digits) and MaxWork.
  • Parse, ParseToExponent and ParseJSON read MaxInputBytes and MaxDigits; parsing has no work axis, its time being linear in input bytes plus result digits.
  • Scan reads MaxInputBytes, MaxDigits and MaxWork.
  • Display (Fixed, Scientific, Engineering and their Append forms, AppendEngineering among them) reads MaxOutputBytes and MaxWork (source digits plus output bytes).
  • Integer conversion (FromBigInt, BigInt, Rat, Compose, NewTwosComplement) reads MaxInputDigits, MaxDigits (result digits) and MaxWork.
  • The elementary functions read MaxDigits and MaxWork in evaluation units; see BoundEvaluation.

Work units differ by family: a digit visit for Add, Sub and Quantize; a nine-digit tile interaction plus one per input digit for Mul; a base-10⁹ limb operation or digit read for the Div family; a 64-bit word operation for the FromRat family; 87 per exact-expansion pass for binary64 conversion; one base-10⁹ limb step of the radix conversion for integer conversion; and the dispatch, envelope and allocation charges of BoundEvaluation for the elementary functions. Context forms add 2N+1 for an N-digit result. Within a family, time is at most affine in charged units, a + b·W, so a work cap also bounds latency; a call served in machine words takes less time and is admitted or refused as the general path decides. A refusal of byte input for resources never copies the input.

The Estimate documentation writes each family's tariff, its formula for work units, in one notation: B is the base charge admitted before any work (the precharge), C a path charge, N the result digits, W the total (context forms: W = B + 2N + 1), t(d) = 1+(d−1)/9 the base-10⁹ limbs of d digits, and L the aligned digit span. The adaptive functions (Exp, Ln, Log10, PowDecimal and the trigonometric and hyperbolic functions) charge the evaluation units described above, over every stage of one call.

type Conditions

type Conditions uint16

Conditions is the set of GDA-named conditions returned by an operation, plus the two result-direction attributes Increased and Decreased, which are not exceptional and cannot be trapped. Mask them with c &^ (Increased|Decreased) before reusing a returned set as traps.

const (
	// Clamped is reserved: it can be selected as a trap, but no operation
	// reports it, because the library never clamps an exponent.
	Clamped Conditions = 1 << iota
	// ConversionSyntax identifies text or a source that is not a decimal
	// literal; it is the Condition of an error wrapping ErrConversionSyntax.
	ConversionSyntax
	// DivisionByZero identifies a nonzero dividend divided by zero, or the
	// logarithm of zero; it is the Condition of an ErrDivisionByZero error.
	DivisionByZero
	// DivisionImpossible identifies an integer quotient longer than a finite
	// context precision; it is the Condition of an ErrDivisionImpossible
	// error.
	DivisionImpossible
	// DivisionUndefined identifies 0/0; it is the Condition of an
	// ErrDivisionUndefined error.
	DivisionUndefined
	// Inexact reports that a rounding discarded digits that were not all
	// zero, so the result differs from the exact value. Exactly one of
	// Increased and Decreased accompanies it.
	Inexact
	// InsufficientStorage identifies a refusal for resources: a budget or
	// an addressability limit; it is the Condition of an
	// ErrInsufficientStorage error.
	InsufficientStorage
	// InvalidContext identifies an invalid Context configuration; it is the
	// Condition of an *Error.
	InvalidContext
	// InvalidOperation identifies an operand outside an operation's domain,
	// such as the square root of a negative value; it is the Condition of
	// an ErrInvalidOperation error.
	InvalidOperation
	// Overflow reports a result above the context's Emax, replaced by the
	// context's largest finite value. Binary64 conversion reports it for a
	// magnitude beyond MaxFloat64, replaced by MaxFloat64 or an infinity
	// according to the rounding mode.
	Overflow
	// Rounded reports that a rounding discarded digits, possibly all zero.
	Rounded
	// Subnormal reports a nonzero result below the context's Emin, rounded
	// at the subnormal quantum; binary64 conversion reports it for a
	// nonzero result below 2^-1022.
	Subnormal
	// Underflow reports a Subnormal result that is also Inexact, in context
	// arithmetic and in binary64 conversion alike.
	Underflow
	// Increased and Decreased are result-direction attributes, not
	// exceptional conditions: exactly one accompanies an emitted
	// Inexact and reports whether the returned value is greater or less than
	// the exact result. They are never trappable and never appear in an
	// error's Condition field. TowardNegativeInfinity never
	// reports Increased and TowardPositiveInfinity never reports Decreased
	// unless Overflow is also reported: guarded overflow substitutes the
	// finite largest value in every mode, which is then no finite bound.
	Increased
	// Decreased reports that the returned value is less than the exact
	// result; see Increased.
	Decreased
)

The GDA conditions, in the bit order Conditions.String uses.

func (Conditions) Direction

func (c Conditions) Direction() int

Direction returns +1 when the set reports Increased, −1 when it reports Decreased and 0 otherwise, including for a set with both bits, which no operation emits: the sign of the returned value minus the exact result.

func (Conditions) String

func (c Conditions) String() string

String names the set conditions in ascending bit order, joined by "|". The empty set is "0"; undeclared bits are shown in hexadecimal.

type Context

type Context struct {
	// contains filtered or unexported fields
}

Context is an immutable, explicit decimal arithmetic configuration: a precision, rounding mode, optional exponent guards, traps and a resource Budget. Its zero value has unlimited precision, TiesToEven, no exponent guards, no traps and no budget, so every XWithContext form called with Context{} computes what the bare exact X computes; Context{}.WithBudget(b) is that exact computation under a quota. Constructors and derivation return values with private scalar state; Context is safe to copy and share across goroutines.

Example (SqlDecimal)

ExampleContext_sqlDecimal stores values in a NUMERIC(5,2) column: Quantize to the column's exponent under a context whose precision is the column's, so one call rounds to the scale and refuses a value that needs more digits.

package main

import (
	"errors"
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	// NUMERIC(5,2): five digits, two after the point, ties away from zero.
	column, err := decimal.NewContext(5, decimal.TiesAwayFromZero, nil, 0)
	if err != nil {
		panic(err)
	}
	for _, text := range []string{"123.456", "7", "-0.005", "999.995", "1234.5"} {
		stored, conditions, err := decimal.MustParse(text).QuantizeWithContext(-2, column)
		if err != nil {
			fmt.Println(text, "->", err, errors.Is(err, decimal.ErrInvalidOperation))
			continue
		}
		fmt.Println(text, "->", stored, conditions)
	}

	// Arithmetic is exact; the assignment rounds once.
	price, quantity := decimal.MustParse("19.99"), decimal.MustParse("0.333")
	line, _ := price.Mul(quantity) // exact: 6.65667
	stored, conditions, _ := line.QuantizeWithContext(-2, column)
	fmt.Println(line, "->", stored, conditions)

	// A quotient at MySQL's division scale (the dividend's scale 2 plus
	// div_precision_increment 4), then assigned to the column: two roundings,
	// as the engine performs them.
	sum, _ := decimal.Sum(decimal.MustParse("10.00"), decimal.MustParse("20.00"), decimal.MustParse("20.00"))
	quotient, conditions, _ := sum.DivToExponent(decimal.FromInt64(3), -2-4, decimal.TiesAwayFromZero)
	fmt.Println(sum, "/ 3 ->", quotient, conditions)
	stored, conditions, _ = quotient.QuantizeWithContext(-2, column)
	fmt.Println(quotient, "->", stored, conditions)
}
Output:
123.456 -> 123.46 Inexact|Rounded|Increased
7 -> 7.00 0
-0.005 -> -0.01 Inexact|Rounded|Decreased
999.995 -> decimal: QuantizeWithContext: invalid operation true
1234.5 -> decimal: QuantizeWithContext: invalid operation true
6.65667 -> 6.66 Inexact|Rounded|Increased
50.00 / 3 -> 16.666667 Inexact|Rounded|Increased
16.666667 -> 16.67 Inexact|Rounded|Increased

func Decimal32Context

func Decimal32Context() Context

Decimal32Context returns a fresh 7-digit numerical context with Emin -95 and Emax 96, TiesToEven and no traps. It does not impose an IEEE encoding, exceptional value set or clamping.

func Decimal64Context

func Decimal64Context() Context

Decimal64Context returns a fresh 16-digit numerical context with Emin -383 and Emax 384, TiesToEven and no traps. It adds no encoding or clamping.

func Decimal128Context

func Decimal128Context() Context

Decimal128Context returns a fresh 34-digit numerical context with Emin -6143 and Emax 6144, TiesToEven and no traps. It adds no encoding or clamping.

func NewContext

func NewContext(precision uint32, rounding RoundingMode, guards *ExponentGuards, traps Conditions) (Context, error)

NewContext constructs an explicit decimal context. Precision zero means exact, unlimited working precision and requires absent guards. A nonnil guard pair must have Emin <= Emax and Etiny = Emin-(precision-1) within the int32 stored-exponent domain. Unknown modes or trap bits are invalid. Failure returns Context{} and *Error with InvalidContext identity.

func (Context) Budget

func (c Context) Budget() Budget

Budget returns the context's resource budget: the MaxInputBytes, MaxDigits and MaxWork axes, the ones context operations read. The zero Budget is unlimited.

func (Context) ExponentGuards

func (c Context) ExponentGuards() (ExponentGuards, bool)

ExponentGuards returns the copied guard pair and whether it is present.

func (Context) Precision

func (c Context) Precision() uint32

Precision returns the working significant-digit precision.

func (Context) Rounding

func (c Context) Rounding() RoundingMode

Rounding returns the context's rounding mode.

func (Context) Traps

func (c Context) Traps() Conditions

Traps returns the selected condition trap set.

func (Context) WithBudget

func (c Context) WithBudget(b Budget) Context

WithBudget derives a context whose operations refuse, with ErrInsufficientStorage and before allocating, any call the budget does not admit. It keeps the MaxInputBytes, MaxDigits and MaxWork axes; MaxInputDigits and MaxOutputBytes bound only integer conversion and display, which take a Budget directly. Every budget is valid; the receiver is not mutated.

func (Context) WithGuards

func (c Context) WithGuards(g ExponentGuards) (Context, error)

WithGuards derives a context with the adjusted-exponent guards g, validated as NewContext validates them.

func (Context) WithPrecision

func (c Context) WithPrecision(p uint32) (Context, error)

WithPrecision derives a context with precision p, validated as NewContext validates it against the guards; 0 is unlimited and needs no guards. The receiver is not mutated; failure returns Context{} and an ErrInvalidContext error.

func (Context) WithRounding

func (c Context) WithRounding(m RoundingMode) (Context, error)

WithRounding derives a context with rounding mode m. An unknown mode returns Context{} and an ErrInvalidContext error.

func (Context) WithTraps

func (c Context) WithTraps(traps Conditions) (Context, error)

WithTraps derives a context with an independently selected trap set. It never mutates the receiver. Unknown condition bits return Context{} and a typed InvalidContext error; any GDA exceptional condition bit is permitted, but the result-direction attributes Increased and Decreased are not.

func (Context) WithoutGuards

func (c Context) WithoutGuards() Context

WithoutGuards derives a context with no exponent guards; it cannot fail.

type Cost

type Cost struct {
	WorkUnits   uint64 // Budget.MaxWork
	Digits      uint64 // Budget.MaxDigits
	InputDigits uint64 // Budget.MaxInputDigits
	InputBytes  uint64 // Budget.MaxInputBytes
	OutputBytes uint64 // Budget.MaxOutputBytes
	HeapBytes   uint64 // cumulative allocated bytes, allocator-rounded
}

Cost bounds one budgeted call before it is made. Each field is an upper bound on what the call can need of the matching budget axis for every input of the estimated shape, attained by that shape's worst case within the family's documented slack, or zero when the family does not consult that axis. HeapBytes bounds the cumulative bytes the call allocates, garbage included, as the Go allocator rounds them.

The Budget of a Cost always admits the call. A refusal the shape cannot decide may still occur and is not predicted: a division by zero is predicted only for a zero-divisor shape, while a non-integral or non-terminating value, an invalid rounding mode, an Exact-mode refusal, and an exponent that leaves int32 only after rounding or stripping are not. Such a refusal never does more work than the estimate.

func EstimateAdd

func EstimateAdd(x, y Shape, ctx Context) (Cost, error)

EstimateAdd bounds AddWithContext: the base charge B over the shapes as the context planner reduces them (a remote nonzero operand becomes one sticky digit, and a zero's exponent is clamped just below the rounding position), the finisher 2N+1, and N result digits. B is 1 for two zeros, the nonzero's aligned span for one zero (a zero is not part of that span), and the Add tariff for two nonzero shapes. N is min(p, the reduced exact sum's digits), or p when guards make an overflow reachable for these shapes (the overflow publishes p nines).

At precision 0 it bounds the exact Add for operands of shapes x and y. The relation of the signs decides the tariff; a caller that does not know the signs takes the Max of the estimates for equal and opposite signs. A shape of one digit covers zero.

func EstimateBigInt

func EstimateBigInt(x Shape) (Cost, error)

EstimateBigInt bounds BigIntWithBudget for x: an integral result of d−drop digits (exponent −drop) or d+e digits (exponent e ≥ 0), work T² + T with T = t(d) + t(result), and the result's words and header. A negative exponent that drops every digit is the operation's ErrNonIntegral.

func EstimateCompose

func EstimateCompose(coefficientBytes uint64) (Cost, error)

EstimateCompose bounds ComposeWithBudget for a coefficient of n bytes (0 is zero, which consults no budget): the envelope U and work W over the raw bits on every axis, and the published result.

func EstimateDiv

func EstimateDiv(x, y Shape, ctx Context) (Cost, error)

EstimateDiv bounds DivWithContext: the division runs at t′ = (dx−dy)+ideal−p (raised to Etiny under guards) and the result has at most p digits.

At precision 0 it bounds the exact Div: the exact quotient is divided at ideal − ⌈3.322·dy⌉ and has at most dn − dy + 1 digits there before trailing zeros are stripped (a non-terminating quotient is refused, which the estimate does not predict). Exponents that leave int32 are ErrExponentRange.

func EstimateDivToExponent

func EstimateDivToExponent(x, y Shape, target int32) (Cost, error)

EstimateDivToExponent bounds DivToExponentWithBudget at target: the quotient at the target has at most dn − dy + 2 digits (one for a rounding carry, whatever the mode), or 1 when the plan shows without dividing that the quotient is below one unit of the target.

func EstimateEngineering

func EstimateEngineering(x Shape) (Cost, error)

EstimateEngineering bounds EngineeringWithBudget and AppendEngineering.

func EstimateFMA

func EstimateFMA(x, y, z Shape, ctx Context) (Cost, error)

EstimateFMA bounds FMAWithContext: Mul's charge plus the context Add/Sub estimate over the product and addend as the context planner reduces them, the product being a span of dx+dy−1 or dx+dy digits at the int64 exponent ex+ey and planned at dx+dy; the finisher 2N+1; and HeapBytes for the product scratch (unless the planner replaces the product, which is then never built) and an N-digit result. Precision 0 is the exact x·y + z. An exact zero whose exponent min(ex+ey, ez) leaves int32 is the operation's ErrExponentRange.

func EstimateFixed

func EstimateFixed(x Shape, fractionalDigits uint64, mode RoundingMode) (Cost, error)

EstimateFixed bounds FixedWithOptions and AppendFixed for x with fractionalDigits places under the rounding mode: the output bytes of the worst layout (the sign kept and a rounding carry wherever the mode can raise the magnitude), work = source digits + output bytes, and the string's allocation.

func EstimateFromBigInt

func EstimateFromBigInt(bitLen uint64) (Cost, error)

EstimateFromBigInt bounds FromBigIntWithBudget for a value of bitLen bits (0 is zero): the digit envelope U = ⌊n·log10 2⌋ + 1 on both digit axes, work (2⌈U/9⌉)² + 2⌈U/9⌉, and the published result.

func EstimateFromFloat64

func EstimateFromFloat64(f float64, ctx Context) (Cost, error)

EstimateFromFloat64 bounds FromFloat64WithContext for the float f: 87 work units per exact-expansion pass and the finisher 2N+1, where N is the expansion's D digits at precision 0, else at most min(D, p), or p when a guarded overflow substitutes the context's largest value. A non-finite f is ErrConversionSyntax.

func EstimateFromFloat64ToExponent

func EstimateFromFloat64ToExponent(f float64, target int32) (Cost, error)

EstimateFromFloat64ToExponent bounds FromFloat64ToExponentWithBudget for the float f at target: 87 work units per exact-expansion pass plus one per padded limb, and the finisher 2N+1. The expansion runs on the stack without allocating, so N is exact when the target pads it (D + pad) and at most D − drop + 1 when it rounds (one for a carry, whatever the mode). A non-finite f is ErrConversionSyntax.

func EstimateFromRat

func EstimateFromRat(numBits, denBits uint64, ctx Context) (Cost, error)

EstimateFromRat bounds FromRatWithContext: when the precision exceeds numBits+denBits, the exact attempt (its worst case) and then the division for a non-terminating value, else the division alone, at t′ = a_lo − p + 1 raised to Etiny; the result has at most p digits.

At precision 0 it bounds the exact FromRat for a numerator of numBits and a denominator of denBits bits (numBits 0 is zero). The tariff's maximum over every denominator of that size is used; a non-terminating value, or one whose twos exceed 2^31, is refused and not estimated.

func EstimateFromRatToExponent

func EstimateFromRatToExponent(numBits, denBits uint64, target int32) (Cost, error)

EstimateFromRatToExponent bounds FromRatToExponentWithBudget at target: the shared division plan, and a result of at most Uq + 1 digits (one for a rounding carry), or one digit when the value lies far below the target.

func EstimateMul

func EstimateMul(x, y Shape, ctx Context) (Cost, error)

EstimateMul bounds MulWithContext: base t(d1)·t(d2) + d1 + d2, the finisher 2N+1, N = min(p, d1+d2), or p when guards make an overflow reachable.

At precision 0 it bounds the exact Mul: digits d1+d2, work t(d1)·t(d2) nine-digit tile interactions plus d1+d2, and the publication of a physical buffer of t(d1)+t(d2) limbs. There an exponent sum outside int32 is the operation's ErrExponentRange; at a finite precision the rounded result decides, which the shapes alone do not determine.

func EstimateNewTwosComplement

func EstimateNewTwosComplement(bytes uint64) (Cost, error)

EstimateNewTwosComplement bounds NewTwosComplementWithBudget for an input of the given byte length; empty input is the operation's ErrConversionSyntax.

func EstimateParse

func EstimateParse(inputBytes uint64, ctx Context) (Cost, error)

EstimateParse bounds ParseWithContext for inputBytes of text under the context's budget. At precision 0 (Parse) every byte may be a significant digit, so the result has at most inputBytes digits, or the budget's digit cap, beyond which the call refuses before allocating; parsing has no work axis, its time being O(input bytes + result digits). At precision p the result has at most min(p, inputBytes) digits from at most that many retained digits, or p digits under guards, whose overflow publishes p nines. HeapBytes also covers a refusal's error value, including the copy a syntax error of byte input makes.

func EstimateParseJSON

func EstimateParseJSON(rawBytes uint64, budget Budget) (Cost, error)

EstimateParseJSON bounds ParseJSONWithBudget for rawBytes of JSON: the quoted form's decode buffer (only when it has escapes), at most rawBytes digits, and a refusal's error value.

func EstimateParseToExponent

func EstimateParseToExponent(inputBytes uint64, target int32, budget Budget) (Cost, error)

EstimateParseToExponent bounds ParseToExponentWithBudget at target. The text decides the pad, so the retained digits are bounded by the input (inputBytes) plus the largest pad an int32 exponent allows (MaxInt32 − target), or by the budget's digit cap; a rounding carry adds one digit. HeapBytes covers the retained scratch above the 48-limb stack and the published copy.

func EstimatePow

func EstimatePow(x Shape, n int32, ctx Context) (Cost, error)

EstimatePow bounds PowWithContext: the worst case is the scan to find z (t(d)), every truncated level from w = p+1+⌈log10(2|n|)⌉+2, doubling while w < |n|·d, then the exact fallback (the plan at k·d digits per partial power, plus one reciprocal division for n < 0) and the finisher's 2p+1, with N = p. It is attained by the all-nines coefficient of the shape when every level fails to decide, but for the scan's slack t(d) − 1; a typical call decides at the first level. A zero x costs one digit and W = 4, as does n = 0 unless guards with Emax < 0 make 1 overflow to the largest finite value, which costs p digits and W = 2p + 2; |n| = 1 is EstimateRoundToPrecision or EstimateDiv.

At precision 0 it bounds the exact Pow. For n ≥ 2 the digits are bounded by n·d, d the shape's full digit count (trailing zeros included), which is at least Dhi + n·z; the work is the exact plan with every partial power c^k at k·d digits, which covers the n·z zeros because the last step alone grows by n·z; t(d) more bounds the ⌊z/9⌋+1 limbs read to find z. The digits are attained by the all-nines coefficient of the shape, and so is the work but for its one-limb scan (slack t(d) − 1). For n ≤ −2 the value is 5^(a·|n|) or 2^(b·|n|) when the reciprocal terminates, so the bound is the test's charge plus the plan of 5^(a_max·|n|), a_max = ⌊d·3.322⌋, whose digits exceed |n|·d (8⁻² = 0.015625); a non-terminating value is refused, which the estimate does not predict; the scan adds t(d). |n| ≤ 1 is EstimateRoundToPrecision with Context{} (n = 1) or EstimateDiv of one by x (n = −1), n = 0 costs one digit and one unit, and a zero x is ErrDivisionByZero for n < 0.

func EstimateQuantize

func EstimateQuantize(x Shape, target int32, ctx Context) (Cost, error)

EstimateQuantize bounds QuantizeWithContext (and, with a zero or unguarded precision-0 Context carrying the mode, Quantize) through the Quantize tariff. The all-nines carry digit is counted only when ctx's rounding can raise the magnitude for the operand's sign. A target outside a guarded context's [Etiny, Emax], or a result that cannot fit the precision or Emax even without that carry, is the operation's ErrInvalidOperation.

func EstimateQuo

func EstimateQuo(x, y Shape, ctx Context) (Cost, error)

EstimateQuo bounds QuoWithContext. It predicts ErrDivisionImpossible when δ exceeds the precision and ErrInvalidOperation for a guard that every such quotient fails.

At precision 0 it bounds the exact Quo: W = B + C + 2Q + 1 with Q = δ+1 for δ = (dx+ex) − (dy+ey) ≥ 0, where the quotient has δ or δ+1 digits.

func EstimateRat

func EstimateRat(x Shape) (Cost, error)

EstimateRat bounds RatWithBudget for x. An integral x is BigInt plus the Rat header. Otherwise the tariff is the maximum over the coefficient's stripped trailing zeros z: every term decreases in z except the limb strip d added for any z > 0, so the maximum is at z = 0 or z = 1; the heap covers the math/big scratch envelope, the numerator conversion, the loop's two reused integers, 10^j, the Rat and the strip's published coefficient.

func EstimateRem

func EstimateRem(x, y Shape, ctx Context) (Cost, error)

EstimateRem bounds RemWithContext.

At precision 0 it bounds the exact Rem: its N is the path's result-digit envelope, since the remainder's length depends on its value.

func EstimateRemNear

func EstimateRemNear(x, y Shape, ctx Context) (Cost, error)

EstimateRemNear bounds RemNearWithContext.

At precision 0 it bounds the exact RemNear.

func EstimateRoundToIntegral

func EstimateRoundToIntegral(x Shape, ctx Context) (Cost, error)

EstimateRoundToIntegral bounds RoundToIntegralWithContext, a quantization to exponent 0.

func EstimateRoundToMultiple

func EstimateRoundToMultiple(x, m Shape) (Cost, error)

EstimateRoundToMultiple bounds RoundToMultipleWithBudget of x to the multiple m: the DivToExponent estimate of x by m's coefficient at m's exponent, completed with N_r quotient digits, plus the Mul charge of r·m over the digit envelope N_r + digits(m). A zero, negative or zero-digit m is the operation's ErrInvalidOperation.

func EstimateRoundToPrecision

func EstimateRoundToPrecision(x Shape, ctx Context) (Cost, error)

EstimateRoundToPrecision bounds RoundToPrecisionWithContext, which is context addition of a zero at the value's exponent: the one-nonzero Add base B = d with the finisher's 2N + 1, N = min(p, d) (or p when guards make an overflow reachable). A zero value charges as one digit.

func EstimateScan

func EstimateScan(src any, budget Budget) (Cost, error)

EstimateScan bounds ScanWithBudget for src, which the caller already holds (src does not escape): text by its length (work = bytes, as text parsing charges), any integer kind by its digits, float64 and float32 by their exact expansion, math/big integers and rationals by their existing conversion plans and minimal magnitude-byte counts, and a decompose source by budget.MaxInputBytes; a decompose source without a byte cap has no finite bound, because its own Decompose decides the length, and foreign Decompose work and allocation are outside every Decimal bound. SQL NULL costs nothing; an unsupported kind or a non-finite float is ErrConversionSyntax.

func EstimateScientific

func EstimateScientific(x Shape, significantDigits uint64, mode RoundingMode) (Cost, error)

EstimateScientific bounds ScientificWithOptions and AppendScientific for significantDigits under the rounding mode.

func EstimateSqrt

func EstimateSqrt(x Shape, ctx Context) (Cost, error)

EstimateSqrt bounds SqrtWithContext: the precharge B = d + I·D + t(p+1)² (I Newton iterations, each one division of charge D) with W = B + 2p + 1 and N = p, attained by every inexact root; HeapBytes covers the Newton scratch of the call's own plan beyond the stack and a p-digit result. zero costs one digit and W = 4.

At precision 0 it bounds the exact Sqrt: with d′ the digits of the parity-adjusted coefficient (one more than x's for an odd exponent) and R = ⌈d′/2⌉, W = B = d′ + I·D + t(R)² and N = R, attained by every perfect square of the shape; HeapBytes covers the Newton scratch beyond the stack and the published root. A negative nonzero shape is the operation's ErrInvalidOperation, and zero costs one digit and one unit.

func EstimateSub

func EstimateSub(x, y Shape, ctx Context) (Cost, error)

EstimateSub bounds SubWithContext.

At precision 0 it bounds the exact Sub; the effective sign relation is that of x + (−y).

func EstimateSum

func EstimateSum(s SumShape) (Cost, error)

EstimateSum bounds SumWithBudget over operands of the given aggregate shape (ShapeOfSum builds it in one pass): W = k + Σdᵢ + 2·t(L) and N = L, the digit envelope amax − emin + 1 + ⌈log10 k⌉ (1 when every operand is zero), with the accumulators' scratch beyond the stack and the published result in HeapBytes. It is O(1).

func (Cost) Budget

func (c Cost) Budget() Budget

Budget returns the Budget that always admits the estimated call.

func (Cost) Max

func (c Cost) Max(o Cost) Cost

Max returns the per-axis maximum of two estimates, for a caller that does not know which of several shapes (for example which sign relation) it will meet.

type Decimal

type Decimal struct {
	// contains filtered or unexported fields
}

Decimal is a finite, immutable decimal coefficient and base-ten exponent. Its zero value is zero at exponent zero. It is deliberately non-comparable; numeric equality is defined by the Equal method.

Example (MapKeys)
package main

import (
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	entries := make(map[string]int)
	for i, value := range []decimal.Decimal{decimal.MustParse("1.2300"), decimal.MustParse("1.23")} {
		key, err := value.Reduce().Text(0)
		if err != nil {
			panic(err) // handle refusal before inserting or querying a key
		}
		entries[key] = i
	}
	fmt.Println(len(entries), entries["1.23"])
}
Output:
1 1
Example (NumericKey)

ExampleDecimal_numericKey builds a map key that a Decimal and a float64 share exactly when they are equal as rationals. Every finite nonzero decimal c·10^e and binary m·2^k is uniquely sign·u·2^a·5^b with u coprime to 10; the key spells that form.

package main

import (
	"fmt"
	"math"
	"math/big"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	key := func(negative bool, magnitude *big.Int, a, b int64) string {
		if magnitude.Sign() == 0 {
			return "0" // every zero, including a negative zero float64
		}
		u := new(big.Int).Rsh(magnitude, magnitude.TrailingZeroBits())
		a += int64(magnitude.TrailingZeroBits())
		five, q, r := big.NewInt(5), new(big.Int), new(big.Int)
		for q.QuoRem(u, five, r); r.Sign() == 0; q.QuoRem(u, five, r) {
			u.Set(q)
			b++
		}
		sign := "+"
		if negative {
			sign = "-"
		}
		return fmt.Sprintf("%s%s*2^%d*5^%d", sign, u, a, b)
	}
	decimalKey := func(d decimal.Decimal) string {
		// The reduced sign, coefficient and exponent; Reduce keeps the
		// coefficient short and changes no key.
		_, negative, coefficient, exponent := decimal.SQLDecimal{Decimal: d.Reduce()}.Decompose(nil)
		return key(negative, new(big.Int).SetBytes(coefficient), int64(exponent), int64(exponent))
	}
	floatKey := func(f float64) string { // finite f only
		r := new(big.Rat).SetFloat64(f) // exact: numerator / 2^t
		return key(r.Sign() < 0, new(big.Int).Abs(r.Num()), -int64(r.Denom().BitLen()-1), 0)
	}

	fmt.Println(decimalKey(decimal.MustParse("1.00")), floatKey(1))
	fmt.Println(decimalKey(decimal.MustParse("-2.50E+2")), floatKey(-250))
	fmt.Println(decimalKey(decimal.MustParse("0.375")), floatKey(0.375))
	fmt.Println(decimalKey(decimal.MustParse("0.1")) == floatKey(0.1))
	fmt.Println(decimalKey(decimal.MustParse("0.00")), floatKey(math.Copysign(0, -1)))
}
Output:
+1*2^0*5^0 +1*2^0*5^0
-1*2^1*5^3 -1*2^1*5^3
+3*2^-3*5^0 +3*2^-3*5^0
false
0 0

func FromBigInt

func FromBigInt(value *big.Int) (Decimal, error)

FromBigInt constructs the exact integer value at exponent zero. A nil source, or one whose Bits view has a zero highest word after raw mutation, returns ErrConversionSyntax; a source beyond the platform's addressable allocation returns ErrInsufficientStorage. The result never aliases the source, which must not be mutated concurrently.

func FromBigIntWithBudget

func FromBigIntWithBudget(value *big.Int, budget Budget) (Decimal, error)

FromBigIntWithBudget has FromBigInt's semantics and refuses with ErrInsufficientStorage, before reading coefficient words or allocating, when the conservative digit or work envelope exceeds a positive quota.

func FromFloat64

func FromFloat64(f float64) (Decimal, error)

FromFloat64 returns the shortest-round-trip decimal of a finite f: the shortest digits that strconv formats for f, which parse back to f, placed at the largest exponent not above 0 at which they are exact, so FromFloat64(100) is 100 and FromFloat64(0.1) is 0.1. ±0 gives the unsigned zero. NaN and ±Inf return ErrConversionSyntax.

func FromFloat64Exact

func FromFloat64Exact(f float64) (Decimal, error)

FromFloat64Exact returns the exact decimal value of a finite f, its full binary expansion (up to 767 significant digits), at the largest exponent not above 0 at which it is exact: FromFloat64Exact(0.1) is 0.1000000000000000055511151231257827021181583404541015625. ±0 gives the unsigned zero. NaN and ±Inf return ErrConversionSyntax.

func FromInt64

func FromInt64(value int64) Decimal

FromInt64 constructs an exact decimal integer at exponent zero.

func FromRat

func FromRat(r *big.Rat) (Decimal, error)

FromRat converts a rational exactly. A terminating rational (reduced denominator 2^a·5^b) is returned at the largest exponent not above zero that holds it (5/2 is 2.5, 100/1 is 100); a non-terminating rational returns a *Error with Condition Inexact and a remedy. A nil r or a source whose raw words are malformed returns ErrConversionSyntax.

func FromUint64

func FromUint64(value uint64) Decimal

FromUint64 constructs an exact decimal integer at exponent zero.

func MustParse

func MustParse[T Literal](s T) Decimal

MustParse is for trusted literals. It panics with the Error returned by Parse, including checked resource refusal for a valid literal.

func New

func New(coefficient int64, exponent int32) Decimal

New constructs a decimal from a signed 64-bit coefficient and an int32 exponent, preserving the requested exponent even for zero.

Example (MinorUnits)

ExampleNew_minorUnits moves between integer minor units (cents) and Decimal: New places the exponent, and Int64 of the value scaled by 100 returns the cents exactly or fails instead of truncating.

package main

import (
	"errors"
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	price := decimal.New(1999, -2) // 1999 cents
	total, err := price.Mul(decimal.FromInt64(3))
	if err != nil {
		panic(err)
	}
	cents, err := total.Mul(decimal.FromInt64(100)) // exact: 5997.00
	if err != nil {
		panic(err)
	}
	n, err := cents.Int64()
	fmt.Println(price, total, n, err)

	third, _, _ := total.DivToExponent(decimal.FromInt64(7), -4, decimal.TiesToEven) // 8.5671
	scaled, _ := third.Mul(decimal.FromInt64(100))
	_, err = scaled.Int64() // 856.7100 is not integral
	fmt.Println(third, errors.Is(err, decimal.ErrNonIntegral))
}
Output:
19.99 59.97 5997 <nil>
8.5671 true

func NewInt128

func NewInt128(hi int64, lo uint64, exponent int32) Decimal

NewInt128 constructs coefficient·10^exponent from a signed 128-bit two's-complement coefficient split into its high and low 64-bit words, the layout of a 128-bit integer column. It never allocates.

func NewTwosComplement

func NewTwosComplement(b []byte, order binary.ByteOrder, exponent int32) (Decimal, error)

NewTwosComplement constructs coefficient·10^exponent from a two's-complement coefficient of any width with sign extension, in the given byte order (binary.BigEndian as in Parquet, binary.LittleEndian as in Arrow and storage lanes, or binary.NativeEndian). Empty input returns ErrConversionSyntax; any other ByteOrder returns ErrInvalidOperation; an input beyond the addressable window returns ErrInsufficientStorage. The input is neither mutated nor retained.

Example
package main

import (
	"encoding/binary"
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	// A Parquet FIXED_LEN_BYTE_ARRAY(16) DECIMAL(38,2) value: big-endian
	// two's complement coefficient, scale out of band.
	lane := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x2e}
	d, _ := decimal.NewTwosComplement(lane, binary.BigEndian, -2)
	fmt.Println(d)
	out, _ := d.AppendTwosComplement(nil, 4, binary.LittleEndian)
	fmt.Printf("% x\n", out)
}
Output:
-12.34
2e fb ff ff

func NewTwosComplementWithBudget

func NewTwosComplementWithBudget(b []byte, order binary.ByteOrder, exponent int32, budget Budget) (Decimal, error)

NewTwosComplementWithBudget is NewTwosComplement with the copied quotas of a Budget, checked against the conservative envelope of the raw input length before any conversion.

func One

func One() Decimal

One returns one at exponent zero.

func Parse

func Parse[T Literal](s T) (Decimal, error)

Parse accepts one liberal decimal grammar with no caller-imposed budget. Checked resource refusals and invalid literals return a typed Error. A string or a []byte is parsed in place, without a copy. Parse is generic: as an untyped function value write Parse[string] (or Parse[[]byte]).

Example
package main

import (
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	for _, text := range []string{"1.10", "-0.005", "12E+3", "1e-7", "abc"} {
		d, err := decimal.Parse(text)
		if err != nil {
			fmt.Println(text, "->", err)
			continue
		}
		fmt.Println(text, "->", d, d.Exponent())
	}
}
Output:
1.10 -> 1.10 -2
-0.005 -> -0.005 -3
12E+3 -> 1.2E+4 3
1e-7 -> 1E-7 -7
abc -> decimal: Parse: conversion syntax: abc

func ParseJSONWithBudget

func ParseJSONWithBudget(raw []byte, budget Budget) (Decimal, error)

ParseJSONWithBudget charges raw input bytes before framing and significant decoded coefficient digits after decimal syntax and range checks.

func Sum

func Sum(values ...Decimal) (Decimal, error)

Sum returns the exact sum of values: the fold of Add, at the smallest operand exponent (the largest scale), with no rounding. The empty sum is zero (0E0). It fails only on a checked resource refusal, as Add does.

func SumWithBudget

func SumWithBudget(values []Decimal, budget Budget) (Decimal, error)

SumWithBudget is Sum under an operation budget. The envelope bounds the exact sum before any operand is added, so operands that cancel still cost the span they cover: 1E+10000000 − 1E+10000000 + 1E−10000000 plans twenty million digits for a one-digit result, where a fold of Add would not.

A header scan charges one unit per operand; the digit envelope L = amax − emin + 1 + ⌈log10 k⌉ (the largest adjusted exponent over the smallest exponent, plus carries from k operands) must fit the digit cap before anything is allocated; and the full charge is k + Σdᵢ + 2·t(L), t(L) = 1+(L−1)/9.

func Zero

func Zero() Decimal

Zero returns the zero value at exponent zero.

func (Decimal) Abs

func (d Decimal) Abs() Decimal

Abs returns the magnitude of d without changing its coefficient or exponent.

func (Decimal) Acos

func (d Decimal) Acos() (Decimal, error)

Acos returns arccos d in [0, π] exactly: Acos(1) is 0, other d in [−1, 1] return a *Error with Condition Inexact and a remedy naming AcosWithContext, and |d| > 1 returns ErrInvalidOperation.

func (Decimal) AcosWithContext

func (d Decimal) AcosWithContext(ctx Context) (Decimal, Conditions, error)

AcosWithContext rounds acos d once to the context precision in the context's mode, with guards and traps; the exact case keeps exponent 0 and every other result is inexact. Context{} behaves as Acos.

func (Decimal) Acosh

func (d Decimal) Acosh() (Decimal, error)

Acosh returns acosh d ≥ 0 exactly: Acosh(1) is 0, other d ≥ 1 return a *Error with Condition Inexact and a remedy naming AcoshWithContext, and d < 1 returns ErrInvalidOperation.

func (Decimal) AcoshWithContext

func (d Decimal) AcoshWithContext(ctx Context) (Decimal, Conditions, error)

AcoshWithContext rounds acosh d once to the context precision in the context's mode, with guards and traps; the exact case keeps exponent 0 and every other result is inexact. Context{} behaves as Acosh.

func (Decimal) Add

func (d Decimal) Add(other Decimal) (Decimal, error)

Add returns the exact sum at the minimum operand exponent, or Decimal{} with a checked resource error. It uses no caller quota and never rounds.

func (Decimal) AddWithContext

func (d Decimal) AddWithContext(other Decimal, ctx Context) (Decimal, Conditions, error)

AddWithContext applies an explicit arithmetic context to addition.

Example
package main

import (
	"errors"
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	ctx := decimal.Decimal64Context() // 16 digits, TiesToEven
	third := decimal.MustParse("0.3333333333333333")
	sum, conditions, err := third.AddWithContext(decimal.MustParse("0.00000000000000005"), ctx)
	fmt.Println(sum, conditions, err)

	trapping, _ := ctx.WithTraps(decimal.Inexact)
	_, _, err = third.AddWithContext(decimal.MustParse("0.00000000000000005"), trapping)
	fmt.Println(err, errors.Is(err, decimal.ErrInexact))
}
Output:
0.3333333333333334 Inexact|Rounded|Increased <nil>
decimal: AddWithContext: condition Inexact true

func (Decimal) AppendEngineering

func (d Decimal) AppendEngineering(dst []byte, budget Budget) ([]byte, error)

AppendEngineering appends EngineeringWithBudget's text to dst; Budget{} is Engineering. On refusal it returns dst unchanged and the error.

func (Decimal) AppendFixed

func (d Decimal) AppendFixed(dst []byte, fractionalDigits uint64, options DisplayOptions) ([]byte, error)

AppendFixed appends FixedWithOptions's text to dst; DisplayOptions{} is Fixed. On refusal it returns dst unchanged and the error.

func (Decimal) AppendScientific

func (d Decimal) AppendScientific(dst []byte, significantDigits uint64, options DisplayOptions) ([]byte, error)

AppendScientific appends ScientificWithOptions's text to dst; DisplayOptions{} is Scientific. On refusal it returns dst unchanged and the error.

func (Decimal) AppendText

func (d Decimal) AppendText(b []byte) ([]byte, error)

AppendText implements encoding.TextAppender. It appends the checked canonical text to b; on refusal it returns b unchanged and the error.

func (Decimal) AppendTwosComplement

func (d Decimal) AppendTwosComplement(dst []byte, width int, order binary.ByteOrder) ([]byte, error)

AppendTwosComplement appends the coefficient (not the value; the exponent is separate) as exactly width sign-extended two's-complement bytes in the given byte order. width < 1 or an unknown order returns ErrInvalidOperation; a width beyond the addressable window returns ErrInsufficientStorage; a coefficient outside [−2^(8w−1), 2^(8w−1)−1] returns ErrIntegerRange. dst is returned unchanged on every error.

func (Decimal) Asin

func (d Decimal) Asin() (Decimal, error)

Asin returns arcsin d in [−π/2, π/2] exactly: Asin(0) is 0, other d in [−1, 1] return a *Error with Condition Inexact and a remedy naming AsinWithContext, and |d| > 1 returns ErrInvalidOperation.

func (Decimal) AsinWithContext

func (d Decimal) AsinWithContext(ctx Context) (Decimal, Conditions, error)

AsinWithContext rounds asin d once to the context precision in the context's mode, with guards and traps; the exact case keeps exponent 0 and every other result is inexact. Context{} behaves as Asin.

func (Decimal) Asinh

func (d Decimal) Asinh() (Decimal, error)

Asinh returns asinh d exactly: Asinh(0) is 0; every other finite d returns a *Error with Condition Inexact and a remedy naming AsinhWithContext.

func (Decimal) AsinhWithContext

func (d Decimal) AsinhWithContext(ctx Context) (Decimal, Conditions, error)

AsinhWithContext rounds asinh d once to the context precision in the context's mode, with guards and traps; the exact case keeps exponent 0 and every other result is inexact. Context{} behaves as Asinh.

func (Decimal) Atan

func (d Decimal) Atan() (Decimal, error)

Atan returns arctan d in (−π/2, π/2) exactly: Atan(0) is 0; every other finite d returns a *Error with Condition Inexact and a remedy naming AtanWithContext.

func (Decimal) Atan2

func (d Decimal) Atan2(x Decimal) (Decimal, error)

Atan2 returns the angle of the point (x, d) in (−π, π], with the receiver d first as in math.Atan2(d, x). Atan2(0, x > 0) is 0; every other point but the origin returns a *Error with Condition Inexact and a remedy naming Atan2WithContext; the origin returns ErrInvalidOperation. There is one unsigned zero, so the negative x-axis gives +π.

func (Decimal) Atan2WithContext

func (d Decimal) Atan2WithContext(x Decimal, ctx Context) (Decimal, Conditions, error)

Atan2WithContext rounds atan2(d, x) once to the context precision in the context's mode, with guards and traps. Context{} behaves as Atan2.

func (Decimal) AtanWithContext

func (d Decimal) AtanWithContext(ctx Context) (Decimal, Conditions, error)

AtanWithContext rounds atan d once to the context precision in the context's mode, with guards and traps; the exact case keeps exponent 0 and every other result is inexact. Context{} behaves as Atan.

func (Decimal) Atanh

func (d Decimal) Atanh() (Decimal, error)

Atanh returns atanh d exactly: Atanh(0) is 0, other d in (−1, 1) return a *Error with Condition Inexact and a remedy naming AtanhWithContext; d = ±1 returns ErrDivisionByZero and |d| > 1 ErrInvalidOperation.

func (Decimal) AtanhWithContext

func (d Decimal) AtanhWithContext(ctx Context) (Decimal, Conditions, error)

AtanhWithContext rounds atanh d once to the context precision in the context's mode, with guards and traps; the exact case keeps exponent 0 and every other result is inexact. Context{} behaves as Atanh.

func (Decimal) BigInt

func (d Decimal) BigInt(z *big.Int) (*big.Int, error)

BigInt sets z to the exact numeric integer and returns z, reusing z's words when they have room; a nil z allocates a new *big.Int, as big.Float.Int does. A fractional value returns ErrNonIntegral; checked growth may return ErrInsufficientStorage before allocating the result. On a refusal z is not modified.

Example
package main

import (
	"errors"
	"fmt"
	"math/big"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	d, _ := decimal.FromBigInt(new(big.Int).Lsh(big.NewInt(1), 100))
	n, err := d.BigInt(nil)
	fmt.Println(d, n, err)
	_, err = decimal.MustParse("0.5").BigInt(nil)
	fmt.Println(errors.Is(err, decimal.ErrNonIntegral))
}
Output:
1267650600228229401496703205376 1267650600228229401496703205376 <nil>
true

func (Decimal) BigIntWithBudget

func (d Decimal) BigIntWithBudget(z *big.Int, budget Budget) (*big.Int, error)

BigIntWithBudget has BigInt's exact semantics and applies independent input-digit, output-digit and work quotas. Zero means no caller quota.

func (Decimal) CoefficientDigits

func (d Decimal) CoefficientDigits() uint64

CoefficientDigits returns the number of decimal digits in the stored coefficient, counting written trailing zeros. Zero reports one digit.

func (Decimal) CoefficientInt128

func (d Decimal) CoefficientInt128() (hi int64, lo uint64, ok bool)

CoefficientInt128 returns the coefficient as signed 128-bit two's-complement words. ok is false, with zero words, exactly when the coefficient lies outside [−2^127, 2^127−1]. The exponent is reported separately by Exponent. It never allocates.

func (Decimal) Compare

func (d Decimal) Compare(other Decimal) int

Compare returns -1, 0, or +1 according to numeric order.

func (Decimal) CompareFloat64

func (d Decimal) CompareFloat64(f float64) (int, error)

CompareFloat64 orders d against the exact binary rational of f without converting either: −1, 0 or +1 as d is less than, equal to or greater than f. ±0 equals every zero, +Inf exceeds every Decimal and −Inf is below every Decimal; NaN is unordered and returns ErrInvalidOperation. The float nearest 0.1 exceeds the decimal 0.1.

func (*Decimal) Compose

func (d *Decimal) Compose(form byte, negative bool, coefficient []byte, exponent int32) error

Compose sets the receiver from the database/sql decompose convention: form 0 with a big-endian magnitude and the exponent. The non-finite forms 1 and 2 and unknown forms return ErrConversionSyntax, as non-finite text does. The receiver changes only on success and never aliases coefficient.

func (*Decimal) ComposeWithBudget

func (d *Decimal) ComposeWithBudget(form byte, negative bool, coefficient []byte, exponent int32, budget Budget) error

ComposeWithBudget is Compose with the copied digit and work quotas of a Budget, applied to the conservative envelope of the raw coefficient length.

func (Decimal) Cos

func (d Decimal) Cos() (Decimal, error)

Cos returns cos d (radians) exactly: Cos(0) is 1; every other finite d returns a *Error with Condition Inexact and a remedy naming CosWithContext.

func (Decimal) CosWithContext

func (d Decimal) CosWithContext(ctx Context) (Decimal, Conditions, error)

CosWithContext rounds cos d once to the context precision in the context's mode, with guards and traps; the exact case keeps exponent 0 and every other result is inexact. Context{} behaves as Cos.

func (Decimal) Cosh

func (d Decimal) Cosh() (Decimal, error)

Cosh returns cosh d exactly: Cosh(0) is 1; every other finite d returns a *Error with Condition Inexact and a remedy naming CoshWithContext.

func (Decimal) CoshWithContext

func (d Decimal) CoshWithContext(ctx Context) (Decimal, Conditions, error)

CoshWithContext rounds cosh d once to the context precision in the context's mode, with guards and traps; the exact case keeps exponent 0 and every other result is inexact. Context{} behaves as Cosh.

func (Decimal) Div

func (d Decimal) Div(other Decimal) (Decimal, error)

Div returns the exact quotient at the ideal exponent (the dividend's exponent minus the divisor's), or the nearest exponent below it that holds a terminating quotient: 2.400/2.0 is 1.20 and 1/4 is 0.25. A non-terminating quotient such as 1/3 returns a *Error with Condition Inexact and a remedy, never a silently chosen scale. A zero divisor returns ErrDivisionByZero, or ErrDivisionUndefined for 0/0.

func (Decimal) DivToExponent

func (d Decimal) DivToExponent(other Decimal, targetExponent int32, mode RoundingMode) (Decimal, Conditions, error)

DivToExponent rounds the exact quotient once to exactly targetExponent under mode, with unlimited precision and no guards or traps. It is not DivWithContext followed by Quantize, which could round twice.

Example
package main

import (
	"errors"
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	total := decimal.MustParse("100.00")
	count := decimal.FromInt64(3)
	avg, conditions, _ := total.DivToExponent(count, -6, decimal.TiesToEven)
	fmt.Println(avg, conditions)
	_, err := total.Div(count)
	fmt.Println(errors.Is(err, decimal.ErrInexact))
}
Output:
33.333333 Inexact|Rounded|Decreased
true

func (Decimal) DivToExponentWithBudget

func (d Decimal) DivToExponentWithBudget(other Decimal, targetExponent int32, mode RoundingMode, budget Budget) (Decimal, Conditions, error)

DivToExponentWithBudget is DivToExponent with checked quotas.

func (Decimal) DivWithContext

func (d Decimal) DivWithContext(other Decimal, ctx Context) (Decimal, Conditions, error)

DivWithContext rounds the exact quotient once to the context precision under its mode, guards and traps. An exact quotient keeps the exponent closest to the ideal exponent that fits the precision. A context with unlimited precision behaves as Div.

func (Decimal) Engineering

func (d Decimal) Engineering() (string, error)

Engineering renders a numerically equal value with an exponent divisible by three. It never rounds.

func (Decimal) EngineeringWithBudget

func (d Decimal) EngineeringWithBudget(budget Budget) (string, error)

EngineeringWithBudget renders engineering notation under a per-call budget.

func (Decimal) Equal

func (d Decimal) Equal(other Decimal) bool

Equal reports whether two Decimals have the same numeric value.

Example
package main

import (
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	a, b := decimal.MustParse("1.10"), decimal.MustParse("1.1")
	fmt.Println(a.Equal(b), a.Compare(b), a, b, a.Reduce())
}
Output:
true 0 1.10 1.1 1.1

func (Decimal) Exp

func (d Decimal) Exp() (Decimal, error)

Exp returns e^d exactly: Exp(0) is 1. Every other finite d has an irrational power and returns a *Error with Condition Inexact and a remedy naming ExpWithContext.

func (Decimal) ExpWithContext

func (d Decimal) ExpWithContext(ctx Context) (Decimal, Conditions, error)

ExpWithContext rounds e^d once to the context precision in the context's mode, with guards and traps. Exp(0) is exactly 1E0; every other result is inexact, so the Exact mode refuses it. A result beyond the stored exponent range without guards returns ErrExponentRange; guards overflow or underflow as the context arithmetic does. Context{} behaves as Exp.

func (Decimal) Exponent

func (d Decimal) Exponent() int32

Exponent returns the stored base-ten exponent as constructed: the value is coefficient × 10^Exponent. It is never normalized, so 1.10 reports -2; Reduce is the explicit normalization.

func (Decimal) FMAWithContext

func (d Decimal) FMAWithContext(y, z Decimal, ctx Context) (Decimal, Conditions, error)

FMAWithContext returns d·y + z rounded once under ctx: the exact product is added to z and only the sum is rounded, so the result can differ from MulWithContext then AddWithContext, which round twice. The product's exponent ex+ey is internal and carried in int64; only the published exponent must fit int32. The operands are reduced as AddWithContext reduces them, before the product is built: a nonzero z far below the product, or a product far below z, contributes one sticky digit, and a zero product or zero z far below the other is clamped to just below the rounding position, so the work does not grow with the exponent gap. Context{} returns the exact d·y + z at the preferred exponent min(ex+ey, ez) with zero Conditions: Mul then Add's value, cohort and ErrExponentRange when ex+ey leaves int32. There is no bare FMA: with unlimited precision, Mul then Add already computes d·y + z exactly.

func (Decimal) Fixed

func (d Decimal) Fixed(fractionalDigits uint64) (string, error)

Fixed renders exactly fractionalDigits decimal places, rounding once with TiesToEven. Zero fractional digits renders an integer.

Example
package main

import (
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	d := decimal.MustParse("-1234.5678")
	fixed, _ := d.Fixed(2)
	scientific, _ := d.Scientific(3)
	engineering, _ := decimal.MustParse("12345").Engineering()
	fmt.Println(fixed, scientific, engineering)
	fmt.Printf("%v|%.1f|%.2e|%12s|\n", d, d, d, d)
}
Output:
-1234.57 -1.23E+3 12.345E+3
-1234.5678|-1234.6|-1.2E+3|  -1234.5678|

func (Decimal) FixedWithOptions

func (d Decimal) FixedWithOptions(fractionalDigits uint64, options DisplayOptions) (string, error)

FixedWithOptions renders a fixed number of decimal places with the selected rounding mode and per-call budget.

func (Decimal) Float64

func (d Decimal) Float64() (float64, Conditions)

Float64 returns the double nearest d (ties to even) with its exactness and direction: Conditions is 0 when the double equals d exactly (an exact subnormal reports Subnormal alone), and otherwise Inexact|Rounded with Increased or Decreased, plus Overflow for ±Inf and Underflow|Subnormal for an inexact result below 2^−1022 (tininess before rounding). A nonzero d that rounds to zero returns a zero with d's sign.

func (Decimal) Float64Rounded

func (d Decimal) Float64Rounded(mode RoundingMode) (float64, Conditions, error)

Float64Rounded returns the double selected from d by mode, with the Conditions of Float64. Overflow follows IEEE 754 §7.4: TowardZero gives ±MaxFloat64, TowardPositiveInfinity gives +Inf or −MaxFloat64, TowardNegativeInfinity gives +MaxFloat64 or −Inf, and the nearest modes and AwayFromZero give ±Inf. So TowardNegativeInfinity and TowardPositiveInfinity always bracket d with adjacent doubles. Exact returns the double only when it equals d, and otherwise a *Error trapping Inexact.

Example
package main

import (
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	d := decimal.MustParse("0.1")
	lo, lc, _ := d.Float64Rounded(decimal.TowardNegativeInfinity)
	hi, hc, _ := d.Float64Rounded(decimal.TowardPositiveInfinity)
	fmt.Println(lo, lc)
	fmt.Println(hi, hc)
	cmp, _ := d.CompareFloat64(0.1)
	fmt.Println(cmp)
	exact, _ := decimal.FromFloat64Exact(0.1)
	cast, _, _ := decimal.FromFloat64ToExponent(2.675, -2, decimal.TiesToEven)
	fmt.Println(exact, cast)
}
Output:
0.09999999999999999 Inexact|Rounded|Decreased
0.1 Inexact|Rounded|Increased
-1
0.1000000000000000055511151231257827021181583404541015625 2.67

func (Decimal) Format

func (d Decimal) Format(state fmt.State, verb rune)

Format implements the closed %v/%s, %f, and %e fmt verb set. An explicit %e precision counts total significant digits, unlike float formatting. %+v is %v, and %#v is the Go expression decimal.MustParse("text") that rebuilds the value and its cohort, because fmt passes those flags to every field of a struct printed with them. A *Decimal field prints the same expression, which then has the value's type, not the pointer's.

func (Decimal) Int64

func (d Decimal) Int64() (int64, error)

Int64 returns the exact numeric integer. A fractional or out-of-range value returns zero and a typed error without materializing a large integer.

Example
package main

import (
	"errors"
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	n, err := decimal.MustParse("4.200E+2").Int64()
	fmt.Println(n, err)
	_, err = decimal.MustParse("4.2").Int64()
	fmt.Println(err, errors.Is(err, decimal.ErrNonIntegral))
}
Output:
420 <nil>
decimal: Int64: nonintegral value true

func (Decimal) IsZero

func (d Decimal) IsZero() bool

IsZero reports whether d is a zero at any exponent.

func (Decimal) Ln

func (d Decimal) Ln() (Decimal, error)

Ln returns the natural logarithm of d exactly: Ln(1) is 0. Every other positive d has an irrational logarithm and returns a *Error with Condition Inexact and a remedy naming LnWithContext. A negative d returns ErrInvalidOperation and zero returns ErrDivisionByZero, since the finite value space has no infinite pole.

func (Decimal) LnWithContext

func (d Decimal) LnWithContext(ctx Context) (Decimal, Conditions, error)

LnWithContext rounds ln d once to the context precision in the context's mode, with guards and traps. Ln(1) is exactly 0E0; every other result is inexact, so the Exact mode refuses it. Context{} behaves as Ln.

func (Decimal) Log10

func (d Decimal) Log10() (Decimal, error)

Log10 returns the base-ten logarithm of d exactly. For a power of ten 10^k it is the integer k at exponent 0; every other positive d has an irrational logarithm and returns a *Error with Condition Inexact and a remedy naming Log10WithContext. A negative d returns ErrInvalidOperation and zero returns ErrDivisionByZero.

func (Decimal) Log10WithContext

func (d Decimal) Log10WithContext(ctx Context) (Decimal, Conditions, error)

Log10WithContext rounds log10 d once to the context precision in the context's mode, with guards and traps. The exact integer of a power of ten keeps exponent 0 when it fits the precision and otherwise loses only zeros (Rounded) or rounds as any other value.

func (Decimal) MarshalJSON

func (d Decimal) MarshalJSON() ([]byte, error)

MarshalJSON emits checked canonical text as a bare JSON number.

Example
package main

import (
	"encoding/json"
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	var order struct {
		Amount decimal.Decimal `json:"amount"`
		Fee    decimal.Decimal `json:"fee"`
	}
	if err := json.Unmarshal([]byte(`{"amount": 10.50, "fee": "0.25"}`), &order); err != nil {
		panic(err)
	}
	out, _ := json.Marshal(order)
	fmt.Println(string(out))
}
Output:
{"amount":10.50,"fee":0.25}

func (Decimal) MarshalText

func (d Decimal) MarshalText() ([]byte, error)

MarshalText returns the checked canonical decimal text as owned bytes.

func (Decimal) Max

func (d Decimal) Max(other Decimal) Decimal

Max returns the numerically larger operand. For equal values it returns the larger-exponent positive or zero cohort, or smaller-exponent negative cohort.

func (Decimal) Min

func (d Decimal) Min(other Decimal) Decimal

Min returns the numerically smaller operand. For equal values it returns the smaller-exponent positive or zero cohort, or larger-exponent negative cohort.

func (Decimal) Mul

func (d Decimal) Mul(other Decimal) (Decimal, error)

Mul returns the exact product at the checked exponent sum. An out-of-int32 sum returns Decimal{} and ErrExponentRange, including for a zero operand. Checked resource refusal returns Decimal{} and ErrInsufficientStorage.

func (Decimal) MulWithContext

func (d Decimal) MulWithContext(other Decimal, ctx Context) (Decimal, Conditions, error)

MulWithContext applies an explicit arithmetic context to multiplication.

func (Decimal) Neg

func (d Decimal) Neg() Decimal

Neg returns d with its sign reversed. Zero remains unsigned, and the coefficient and exponent are preserved.

func (Decimal) Pow

func (d Decimal) Pow(n int32) (Decimal, error)

Pow returns x^n exactly. For n ≥ 0 the result is the repeated-multiplication cohort: C^n at exponent n·e, so 1.10² is 1.2100. 0⁰ is 1, the empty product (GDA's power gives NaN; a documented deviation). For n < 0 the result is the reciprocal of x^|n| when it terminates, at the reciprocal-then-multiply exponent (2⁻³ is 0.125); otherwise, as for 3⁻¹, Pow returns a *Error with Condition Inexact and a remedy naming PowWithContext. 0ⁿ with n < 0 returns ErrDivisionByZero, and an exponent outside int32 returns ErrExponentRange.

func (Decimal) PowDecimal

func (d Decimal) PowDecimal(y Decimal) (Decimal, error)

PowDecimal returns d^y exactly for a Decimal exponent y. An int32-valued y is Pow(y): the repeated-multiplication cohort, or the reciprocal cohort for y < 0, and 0⁰ = 1. Other integral y extend the same cohorts to the full exponent domain. A noninteger y whose power is a finite decimal gives its shortest representable cohort: 4^0.5 is exactly 2. A power that is irrational or not a finite decimal, such as 2^0.5 or (9/4)^−0.5 = 2/3, returns a *Error with Condition Inexact and a remedy naming PowDecimalWithContext. A negative d with a noninteger y returns ErrInvalidOperation, even where a real odd root exists; zero to a negative power returns ErrDivisionByZero, and zero to a positive noninteger power is 0.

func (Decimal) PowDecimalWithContext

func (d Decimal) PowDecimalWithContext(y Decimal, ctx Context) (Decimal, Conditions, error)

PowDecimalWithContext rounds d^y once to the context precision in the context's mode, with guards and traps. Exact powers keep the cohort nearest the ideal one that fits; mathematical exactness alone decides Inexact, so (81/16)^0.5 = 2.25 at two digits is an exact tie.

func (Decimal) PowWithContext

func (d Decimal) PowWithContext(n int32, ctx Context) (Decimal, Conditions, error)

PowWithContext rounds x^n once to the context precision in the context's mode, with guards and traps. An exact power keeps the exponent nearest the cohort's that fits the precision, reporting Rounded when only zeros are dropped. n = 1 is RoundToPrecisionWithContext and n = −1 is DivWithContext of one by x. Context{} behaves as Pow.

func (Decimal) Quantize

func (d Decimal) Quantize(targetExponent int32, mode RoundingMode) (Decimal, Conditions, error)

Quantize rounds to an explicit stored exponent under the selected mode.

Example
package main

import (
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	for _, mode := range []decimal.RoundingMode{decimal.TiesToEven, decimal.TiesAwayFromZero, decimal.TowardZero} {
		d, conditions, err := decimal.MustParse("2.345").Quantize(-2, mode)
		fmt.Println(mode, d, conditions, err)
	}
	_, _, err := decimal.MustParse("2.345").Quantize(-2, decimal.Exact)
	fmt.Println(err)
}
Output:
TiesToEven 2.34 Inexact|Rounded|Decreased <nil>
TiesAwayFromZero 2.35 Inexact|Rounded|Increased <nil>
TowardZero 2.34 Inexact|Rounded|Decreased <nil>
decimal: Quantize: condition Inexact

func (Decimal) QuantizeWithContext

func (d Decimal) QuantizeWithContext(targetExponent int32, ctx Context) (Decimal, Conditions, error)

QuantizeWithContext rounds to an explicit stored exponent under ctx.

func (Decimal) Quo

func (d Decimal) Quo(other Decimal) (Decimal, error)

Quo returns the truncated integer quotient trunc(x/y) at exponent 0, exactly. It never rounds and has no precision limit. A zero divisor returns ErrDivisionByZero, or ErrDivisionUndefined for 0/0.

func (Decimal) QuoWithContext

func (d Decimal) QuoWithContext(other Decimal, ctx Context) (Decimal, Conditions, error)

QuoWithContext is Quo under a context: a finite precision p refuses a quotient of more than p digits with ErrDivisionImpossible, and exponent guards refuse an out-of-range result with ErrInvalidOperation. The integer result never depends on the rounding mode.

func (Decimal) Rat

func (d Decimal) Rat(z *big.Rat) (*big.Rat, error)

Rat sets z to the exactly equal value in lowest terms and returns z; a nil z allocates a new *big.Rat, as big.Float.Rat does. On a refusal z is not modified.

func (Decimal) RatWithBudget

func (d Decimal) RatWithBudget(z *big.Rat, budget Budget) (*big.Rat, error)

RatWithBudget is Rat with copied quotas: MaxInputDigits caps the coefficient digits, MaxDigits caps the numerator's and the denominator's decimal lengths, and MaxWork caps the conversion and reduction work, all checked before allocating.

func (Decimal) Reduce

func (d Decimal) Reduce() Decimal

Reduce returns the unique in-domain member of d's numeric cohort. It leaves d and any values sharing d's slow coefficient untouched.

func (Decimal) Rem

func (d Decimal) Rem(other Decimal) (Decimal, error)

Rem returns the exact remainder x − q·y of the truncated quotient at exponent min(ex, ey): 10.5 Rem 3 is 1.5 and 3 Rem 0.29 is 0.10. A nonzero remainder has the dividend's sign; zero is unsigned. The quotient is never materialized, so a large exponent gap costs O(log gap).

Example
package main

import (
	"errors"
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	x, y := decimal.MustParse("10.5"), decimal.MustParse("3")
	q, _ := x.Quo(y)
	r, _ := x.Rem(y)
	near, _ := x.RemNear(y)
	fmt.Println(q, r, near)
	p2, _ := decimal.NewContext(2, decimal.TiesToEven, nil, 0)
	_, _, err := decimal.MustParse("1234").RemWithContext(y, p2)
	fmt.Println(errors.Is(err, decimal.ErrDivisionImpossible))
}
Output:
3 1.5 -1.5
true

func (Decimal) RemNear

func (d Decimal) RemNear(other Decimal) (Decimal, error)

RemNear returns the exact x − n·y for the nearest integer n to x/y, a tie selecting the even n, at exponent min(ex, ey): 10 RemNear 6 is −2. A nonzero result may have either sign; zero is unsigned.

func (Decimal) RemNearWithContext

func (d Decimal) RemNearWithContext(other Decimal, ctx Context) (Decimal, Conditions, error)

RemNearWithContext is RemNear under a context. Its precision limits the truncated quotient q, as for Rem; a nearest n of p+1 digits is not a failure.

func (Decimal) RemWithContext

func (d Decimal) RemWithContext(other Decimal, ctx Context) (Decimal, Conditions, error)

RemWithContext is Rem under a context: a finite precision refuses a truncated quotient of more than p digits with ErrDivisionImpossible, even when the remainder is zero; the remainder itself is never rounded.

func (Decimal) RoundToIntegral

func (d Decimal) RoundToIntegral(mode RoundingMode) (Decimal, Conditions, error)

RoundToIntegral rounds to stored exponent zero under the selected mode.

func (Decimal) RoundToIntegralWithContext

func (d Decimal) RoundToIntegralWithContext(ctx Context) (Decimal, Conditions, error)

RoundToIntegralWithContext rounds to stored exponent zero under ctx.

func (Decimal) RoundToMultiple

func (d Decimal) RoundToMultiple(m Decimal, mode RoundingMode) (Decimal, Conditions, error)

RoundToMultiple rounds to the multiple of m nearest the value under the mode: r·m where the integer r is decided once on the exact rational d/m, never on a truncated quotient, so there is no double rounding. The result has m's exponent. It is exact with no Conditions when d/m is integral, and otherwise reports Inexact|Rounded and the direction. m must be positive; zero or negative m is ErrInvalidOperation. Cash rounding of 2.525 to 0.05 is 2.50 under TiesToEven and 2.55 under TiesAwayFromZero.

func (Decimal) RoundToMultipleWithBudget

func (d Decimal) RoundToMultipleWithBudget(m Decimal, mode RoundingMode, budget Budget) (Decimal, Conditions, error)

RoundToMultipleWithBudget adds an operation-local budget: the DivToExponent charge of d/m at exponent 0 with W = B + 2N_r + 1 for the quotient's N_r digits, plus the Mul charge of r·m. The digit cap bounds the result, which has at most N_r + digits(m) digits.

func (Decimal) RoundToPrecision

func (d Decimal) RoundToPrecision(precision uint32, mode RoundingMode) (Decimal, Conditions, error)

RoundToPrecision rounds to at most precision significant digits under the selected mode. A value that already fits returns unchanged, cohort included, with no Conditions (GDA plus); precision 0 is the identity. Otherwise the value is rounded once, with Inexact|Rounded and the direction, or Rounded alone for a zero-only discard, which Exact permits. RoundToPrecision(3, TiesToEven) of 12345 is 1.23E+4; of 1.20 it is 1.20.

func (Decimal) RoundToPrecisionWithContext

func (d Decimal) RoundToPrecisionWithContext(ctx Context) (Decimal, Conditions, error)

RoundToPrecisionWithContext rounds to ctx's precision under its mode, guards and traps. A value that fits within the precision and guards returns unchanged; Context{} is the identity.

func (*Decimal) Scan

func (d *Decimal) Scan(src any) error

Scan implements sql.Scanner. It accepts exactly: string and []byte text in the one decimal grammar, keeping the written scale (1.10 stays 1.10); every int and uint type (not uintptr), uint64 included, at exponent 0; float64 and float32 as their exact binary expansion (0.1 scans as 0.1000000000000000055511151231257827021181583404541015625: upstream float loss is reflected, not repaired); and any value with a Decompose method, whose coefficient and exponent transfer exactly. big.Int and *big.Int sources are exact at exponent 0. big.Rat and *big.Rat sources must terminate in decimal and use the largest exponent not above 0; they carry no column scale (11/10 becomes 1.1). Non-terminating rationals return an *Error that unwraps to ErrInexact: scan into a *big.Rat variable or any and use FromRatWithContext or FromRatToExponent instead. big.Float and *big.Float are refused by kind as an unsupported source with a remedy, including typed nils: choose the driver's decimal text mode or convert explicitly. Typed-nil integer and rational pointers are conversion syntax errors. Accepted sources are never retained or mutated and must not be mutated concurrently. Driver-specific types without Decompose need a caller-side wrapper; see ExampleNullDecimal_driverDecimal. SQL NULL is refused, because Decimal has no NULL state; scan nullable columns into NullDecimal. Non-finite text or forms, a nil-pointer decompose source (refused before it is called) and every other source kind are errors that unwrap to ErrConversionSyntax; text whose exponent leaves the int32 domain unwraps to ErrExponentRange. The receiver changes only on success.

func (*Decimal) ScanWithBudget

func (d *Decimal) ScanWithBudget(src any, budget Budget) error

ScanWithBudget is Scan with a Budget, for direct calls.

func (Decimal) Scientific

func (d Decimal) Scientific(significantDigits uint64) (string, error)

Scientific renders exactly significantDigits coefficient digits, one before the point, an uppercase E, and an explicitly signed exponent.

func (Decimal) ScientificWithOptions

func (d Decimal) ScientificWithOptions(significantDigits uint64, options DisplayOptions) (string, error)

ScientificWithOptions renders significantDigits coefficient digits with explicit rounding and display budget.

func (Decimal) Shape

func (d Decimal) Shape() Shape

Shape returns d's shape in O(1) without allocating.

func (Decimal) Sign

func (d Decimal) Sign() int

Sign returns -1, 0, or +1 according to the numeric sign of d.

func (Decimal) Sin

func (d Decimal) Sin() (Decimal, error)

Sin returns sin d (radians) exactly: Sin(0) is 0; every other finite d has a transcendental sine and returns a *Error with Condition Inexact and a remedy naming SinWithContext.

func (Decimal) SinWithContext

func (d Decimal) SinWithContext(ctx Context) (Decimal, Conditions, error)

SinWithContext rounds sin d once to the context precision in the context's mode, with guards and traps; the exact case keeps exponent 0 and every other result is inexact. Context{} behaves as Sin.

func (Decimal) Sinh

func (d Decimal) Sinh() (Decimal, error)

Sinh returns sinh d exactly: Sinh(0) is 0; every other finite d returns a *Error with Condition Inexact and a remedy naming SinhWithContext.

func (Decimal) SinhWithContext

func (d Decimal) SinhWithContext(ctx Context) (Decimal, Conditions, error)

SinhWithContext rounds sinh d once to the context precision in the context's mode, with guards and traps; the exact case keeps exponent 0 and every other result is inexact. Context{} behaves as Sinh.

func (Decimal) Sqrt

func (d Decimal) Sqrt() (Decimal, error)

Sqrt returns the exact square root at the ideal exponent ⌊e/2⌋: √4 is 2 and √0.25 is 0.5. A root that is not a finite decimal, such as √2, returns a *Error with Condition Inexact and a remedy naming SqrtWithContext, never a silently rounded value. A negative nonzero operand returns ErrInvalidOperation; zero returns an unsigned zero at ⌊e/2⌋.

func (Decimal) SqrtWithContext

func (d Decimal) SqrtWithContext(ctx Context) (Decimal, Conditions, error)

SqrtWithContext rounds the square root once to the context precision in the context's mode, with guards and traps. An exact root keeps the exponent nearest ⌊e/2⌋ that fits the precision; one that needs a higher exponent reports Rounded but not Inexact, which Exact permits: √1E+10 at precision 3 is 1.00E+5. A negative nonzero operand returns ErrInvalidOperation in every mode. Context{} behaves as Sqrt.

func (Decimal) String

func (d Decimal) String() string

String returns canonical text, or a nonnumeric resource diagnostic when the checked output size is not addressable.

func (Decimal) Sub

func (d Decimal) Sub(other Decimal) (Decimal, error)

Sub returns the exact difference at the minimum operand exponent, or Decimal{} with a checked resource error. Exact zero is unsigned.

func (Decimal) SubWithContext

func (d Decimal) SubWithContext(other Decimal, ctx Context) (Decimal, Conditions, error)

SubWithContext applies an explicit arithmetic context to subtraction.

func (Decimal) Tan

func (d Decimal) Tan() (Decimal, error)

Tan returns tan d (radians) exactly: Tan(0) is 0; every other finite d returns a *Error with Condition Inexact and a remedy naming TanWithContext. No finite decimal is a pole.

func (Decimal) TanWithContext

func (d Decimal) TanWithContext(ctx Context) (Decimal, Conditions, error)

TanWithContext rounds tan d once to the context precision in the context's mode, with guards and traps; the exact case keeps exponent 0 and every other result is inexact. Context{} behaves as Tan.

func (Decimal) Tanh

func (d Decimal) Tanh() (Decimal, error)

Tanh returns tanh d exactly: Tanh(0) is 0; every other finite d returns a *Error with Condition Inexact and a remedy naming TanhWithContext.

func (Decimal) TanhWithContext

func (d Decimal) TanhWithContext(ctx Context) (Decimal, Conditions, error)

TanhWithContext rounds tanh d once to the context precision in the context's mode, with guards and traps; the exact case keeps exponent 0 and every other result is inexact. Context{} behaves as Tanh.

func (Decimal) Text

func (d Decimal) Text(maxBytes uint64) (string, error)

Text returns the canonical text for d. A zero maxBytes imposes no caller quota; a positive value limits the exact output byte count.

func (Decimal) Uint64

func (d Decimal) Uint64() (uint64, error)

Uint64 returns the exact numeric integer or an error if the value is fractional or outside the unsigned 64-bit range.

func (*Decimal) UnmarshalJSON

func (d *Decimal) UnmarshalJSON(raw []byte) error

UnmarshalJSON accepts one JSON number or string and assigns only on success. JSON null is refused as ErrConversionSyntax, because Decimal has no null state: decode nullable fields into NullDecimal.

func (*Decimal) UnmarshalText

func (d *Decimal) UnmarshalText(text []byte) error

UnmarshalText parses raw decimal bytes and replaces d only on success. It owns the parsed coefficient, never retains the caller's byte slice and copies it only into an *Error.

func (Decimal) Value

func (d Decimal) Value() (driver.Value, error)

Value returns the checked canonical decimal text as a string driver value.

type DisplayOptions

type DisplayOptions struct {
	// Mode rounds the displayed digits.
	Mode RoundingMode
	// Budget bounds the call.
	Budget Budget
}

DisplayOptions selects rounding and a per-call budget. The zero value uses TiesToEven with no caller limits.

type Error

type Error struct {
	// Op names the exported function or method that failed. The text
	// encoders (MarshalText, AppendText, MarshalJSON and Value) report
	// the Text operation they share.
	Op string
	// Input is the complete input text of a parse failure, else empty.
	Input string
	// Remedy names the instruction or source that avoids the refusal, such
	// as a rounding target for a non-terminating quotient or the dynamic
	// type of an unsupported Scan source. It affects only the message.
	Remedy string
	// Limit is the supplied cap of the exhausted Resource.
	Limit uint64
	// Code is the cause; it is zero for a trapped condition set.
	Code ErrorCode
	// Resource names the exhausted quota of an elementary function; it is
	// zero otherwise.
	Resource EvaluationResource
	// Condition is the GDA condition of the cause, or the trapped set, or
	// Inexact for an Exact-mode or non-terminating refusal.
	Condition Conditions
}

Error is every error an operation returns; the Estimate functions and BoundEvaluation return a bare ErrorCode instead. errors.Is matches its Code, or for a trapped condition set the code of each trapped condition, without allocating; errors.As(&e) with e *Error reads the details. The owning function defines its result on failure.

func (*Error) Error

func (e *Error) Error() string

Error returns "decimal: Op: cause", followed by the remedy and the input when they are set. A trapped set reads "condition Inexact|Rounded".

func (*Error) Is

func (e *Error) Is(target error) bool

Is reports whether a trapped condition set includes the condition of the ErrorCode target, so errors.Is matches each trapped condition's code (Inexact, Overflow, Rounded, Subnormal, Underflow) without allocating.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns Code, or nil for a trapped condition set.

type ErrorCode

type ErrorCode uint8

ErrorCode identifies a decimal failure without mutable package sentinels.

const (
	// ErrConversionSyntax: input that is not a decimal literal, or a source
	// that cannot be converted.
	ErrConversionSyntax ErrorCode = iota + 1
	// ErrExponentRange: a result or literal whose exponent does not fit
	// int32.
	ErrExponentRange
	// ErrInsufficientStorage: work refused by a budget or by an
	// addressability limit, before allocating.
	ErrInsufficientStorage
	// ErrInvalidContext: an invalid Context configuration.
	ErrInvalidContext
	// ErrInexact: a trapped Inexact condition, an Exact-mode or
	// non-terminating refusal, or a display or conversion that cannot be
	// exact.
	ErrInexact
	// ErrRounded: a trapped Rounded condition.
	ErrRounded
	// ErrSubnormal: a trapped Subnormal condition.
	ErrSubnormal
	// ErrOverflow: a trapped Overflow condition.
	ErrOverflow
	// ErrUnderflow: a trapped Underflow condition.
	ErrUnderflow
	// ErrInvalidOperation: an operand or argument outside the operation's
	// domain.
	ErrInvalidOperation
	// ErrNonIntegral: an integer conversion of a value with a nonzero
	// fraction.
	ErrNonIntegral
	// ErrIntegerRange: an integer conversion whose value does not fit the
	// target type or width.
	ErrIntegerRange
	// ErrDivisionByZero: a nonzero value divided by zero, or the logarithm
	// of zero.
	ErrDivisionByZero
	// ErrDivisionUndefined: zero divided by zero.
	ErrDivisionUndefined
	// ErrDivisionImpossible: an integer quotient longer than a finite
	// context precision.
	ErrDivisionImpossible
	// ErrEvaluationBudgetRequired: BoundEvaluation received no finite
	// positive unit quota. Bound-query failures are returned bare and do not
	// wrap ErrInsufficientStorage.
	ErrEvaluationBudgetRequired
	// ErrEvaluationBoundOverflow: the permitted-attempt bound cannot fit
	// uint64. The budget remains valid and may admit an easy call.
	ErrEvaluationBoundOverflow
)

The error codes. An *Error wraps one for errors.Is; a trapped condition set matches the code of each trapped condition through Error.Is.

func (ErrorCode) Error

func (c ErrorCode) Error() string

Error returns the code's message, prefixed "decimal: ".

type EvaluationBound

type EvaluationBound struct {
	// Units bounds the evaluation units the attempt can charge.
	Units uint64
	// HeapBytes bounds the attempt's cumulative library allocation.
	HeapBytes uint64
}

EvaluationBound bounds one adaptive attempt under a supplied finite unit quota. It bounds success or refusal, not the cost of convergence. It has no attainment guarantee or admitting-budget helper and is not Cost. HeapBytes bounds cumulative library allocation, including discarded scratch and one outer error object, not RSS or later caller formatting of the error.

func BoundEvaluation

func BoundEvaluation(budget Budget) (EvaluationBound, error)

BoundEvaluation bounds one attempt of any adaptive function (Exp, Ln, Log10, PowDecimal and the trigonometric and hyperbolic functions) under budget. For positive W=budget.MaxWork it returns Units W and HeapBytes W+E, where E bounds the one *Error a refusal allocates on this target/toolchain. Result storage, nested calls and all retries belong in W. A digit cap without a positive unit quota supplies no finite attempt bound.

The query allocates nothing. Zero units returns ErrEvaluationBudgetRequired; unrepresentable W+E returns ErrEvaluationBoundOverflow. Neither error predicts an operand's outcome or invalidates a supplied operation budget.

type EvaluationResource

type EvaluationResource uint8

EvaluationResource identifies the supplied quota exhausted by an adaptive call. It is not a numerical condition or a physical addressability limit.

const (
	// EvaluationUnits is the evaluation-unit quota, Budget.MaxWork.
	EvaluationUnits EvaluationResource = iota + 1
	// EvaluationCoefficientDigits is the result-digit quota,
	// Budget.MaxDigits.
	EvaluationCoefficientDigits
)

type ExponentGuards

type ExponentGuards struct {
	// Emin is the smallest normal adjusted exponent.
	Emin int32
	// Emax is the largest adjusted exponent; a larger result overflows.
	Emax int32
}

ExponentGuards gives optional adjusted-exponent bounds to NewContext. Emin and Emax are inclusive bounds on adjusted exponents; a nonnil pointer selects guards even when both endpoints are zero. NewContext copies the pair.

type Hasher

type Hasher struct{}

Hasher supplies Decimal's numeric equality and seeded hash to consumers. It has no seed or mutable state; the caller owns the maphash.Hash.

Example (MapKeys)
package main

import (
	"fmt"
	"hash/maphash"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	seed := maphash.MakeSeed() // one seed per consumer-owned table
	pair := decimal.Hasher{}
	digest := func(value decimal.Decimal) uint64 {
		var h maphash.Hash
		h.SetSeed(seed)
		pair.Hash(&h, value)
		return h.Sum64()
	}
	left, right := decimal.MustParse("1.2300"), decimal.MustParse("1.23")
	fmt.Println(digest(left) == digest(right), pair.Equal(left, right))
}
Output:
true true

func (Hasher) Equal

func (Hasher) Equal(x, y Decimal) bool

Equal reports numeric equality, independent of cohort scale.

func (Hasher) Hash

func (Hasher) Hash(h *maphash.Hash, value Decimal)

Hash appends a canonical binary encoding of value to h.

type Literal

type Literal interface{ ~string | ~[]byte }

Literal is the text type Parse and its forms accept: any string or byte slice type. Both carriers share one implementation, and byte input is never copied on success. Generic wrappers can name it to forward either.

type NullDecimal

type NullDecimal struct {
	// Decimal is the value when Valid is true, and Decimal{} otherwise.
	Decimal Decimal
	// Valid is false for SQL NULL.
	Valid bool
}

NullDecimal carries SQL NULL beside a Decimal. Scan of NULL sets Valid to false and clears Decimal; Value returns nil for an invalid value and the canonical text otherwise. NullDecimal deliberately has no Decompose or Compose method: a NULL is never encoded as a finite zero. To bind a nullable value through the decompose convention, pass SQLDecimal{d} when valid and nil otherwise.

Example
package main

import (
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	var price decimal.NullDecimal
	_ = price.Scan([]byte("19.90")) // a NUMERIC column as a driver delivers it
	fmt.Println(price.Decimal, price.Valid)
	_ = price.Scan(nil) // SQL NULL
	v, _ := price.Value()
	fmt.Println(price.Valid, v)
	var d decimal.Decimal
	_ = d.Scan(0.1) // a float column scans as its exact binary value
	fmt.Println(d)
}
Output:
19.90 true
false <nil>
0.1000000000000000055511151231257827021181583404541015625
Example (DriverDecimal)
package main

import (
	"errors"
	"fmt"
	"math/big"
	"strings"

	decimal "github.com/0xCarbon/decimal"
)

// driverDecimal models a driver value that keeps a coefficient and scale.
type driverDecimal struct {
	Width, Scale uint8
	Value        *big.Int
}

// String models a driver's convenience conversion that discards scale.
func (v driverDecimal) String() string {
	text := new(big.Rat).SetFrac(v.Value, new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(v.Scale)), nil)).FloatString(int(v.Scale))
	if strings.Contains(text, ".") {
		text = strings.TrimRight(strings.TrimRight(text, "0"), ".")
	}
	return text
}

type driverDecimalScanner struct{ decimal.NullDecimal }

func (n *driverDecimalScanner) Scan(src any) error {
	if src == nil {
		n.NullDecimal = decimal.NullDecimal{}
		return nil
	}
	v, ok := src.(driverDecimal)
	if !ok {
		return n.NullDecimal.Scan(src)
	}
	if v.Value == nil {
		return errors.New("driver decimal has nil coefficient")
	}
	var d decimal.Decimal
	if err := d.Compose(0, v.Value.Sign() < 0, new(big.Int).Abs(v.Value).Bytes(), -int32(v.Scale)); err != nil {
		return err
	}
	n.NullDecimal = decimal.NullDecimal{Decimal: d, Valid: true}
	return nil
}

func main() {
	var value driverDecimalScanner
	for _, src := range []any{
		driverDecimal{Width: 3, Scale: 2, Value: big.NewInt(110)},
		driverDecimal{Width: 10, Scale: 10, Value: big.NewInt(-5000000000)},
	} {
		if err := value.Scan(src); err != nil {
			panic(err)
		}
		fmt.Println(value.Decimal)
	}
	fmt.Println(value.Scan(driverDecimal{}) != nil, value.Decimal)
	_ = value.Scan(nil)
	fmt.Println(value.Valid)
	_ = value.Scan("2.00")
	fmt.Println(value.Decimal)
}
Output:
1.10
-0.5000000000
true -0.5000000000
false
2.00

func (NullDecimal) MarshalJSON

func (n NullDecimal) MarshalJSON() ([]byte, error)

MarshalJSON emits null for an invalid value and the Decimal's bare JSON number otherwise.

func (*NullDecimal) Scan

func (n *NullDecimal) Scan(src any) error

Scan implements sql.Scanner with Decimal.Scan's source rules, plus SQL NULL. On error both fields are unchanged.

func (*NullDecimal) ScanWithBudget

func (n *NullDecimal) ScanWithBudget(src any, budget Budget) error

ScanWithBudget is Scan with a Budget, for direct calls.

func (*NullDecimal) UnmarshalJSON

func (n *NullDecimal) UnmarshalJSON(raw []byte) error

UnmarshalJSON sets Valid false and clears Decimal for JSON null, and otherwise decodes as Decimal.UnmarshalJSON does with Valid true. On error both fields are unchanged.

func (NullDecimal) Value

func (n NullDecimal) Value() (driver.Value, error)

Value implements driver.Valuer: nil when invalid, otherwise the Decimal's canonical text.

type RoundingMode

type RoundingMode uint8

RoundingMode selects a decimal rounding rule for instructed operations. The zero value is TiesToEven, so Context{} and every preset round ties to even unless a mode is chosen. Monetary rounding should name its mode explicitly, usually TiesAwayFromZero, the commercial rounding of prices and invoices. Exact refuses a value-changing round.

Worked table: each operand rounded to one decimal place, as d.Quantize(-1, mode) returns it. The ties are 2.35, 2.45, −2.35 and −2.45; "refused" is Exact's *Error.

mode                      2.30   2.34   2.35   2.45   2.36  -2.34  -2.35  -2.45  -2.36
TiesToEven                 2.3    2.3    2.4    2.4    2.4   -2.3   -2.4   -2.4   -2.4
TiesAwayFromZero           2.3    2.3    2.4    2.5    2.4   -2.3   -2.4   -2.5   -2.4
TiesTowardZero             2.3    2.3    2.3    2.4    2.4   -2.3   -2.3   -2.4   -2.4
TowardZero                 2.3    2.3    2.3    2.4    2.3   -2.3   -2.3   -2.4   -2.3
AwayFromZero               2.3    2.4    2.4    2.5    2.4   -2.4   -2.4   -2.5   -2.4
TowardPositiveInfinity     2.3    2.4    2.4    2.5    2.4   -2.3   -2.3   -2.4   -2.3
TowardNegativeInfinity     2.3    2.3    2.3    2.4    2.3   -2.4   -2.4   -2.5   -2.4
Exact                      2.3 refused refused refused refused refused refused refused refused
Example (Monetary)

ExampleRoundingMode_monetary rounds an invoice line to cents. The zero RoundingMode is TiesToEven, so monetary code names TiesAwayFromZero explicitly instead of relying on the default.

package main

import (
	"fmt"

	decimal "github.com/0xCarbon/decimal"
)

func main() {
	line, _ := decimal.MustParse("0.715").Mul(decimal.FromInt64(3)) // exact: 2.145

	var unset decimal.RoundingMode // the default mode
	even, _, _ := line.Quantize(-2, unset)
	fmt.Println(line, unset, even)

	cents, conditions, err := line.Quantize(-2, decimal.TiesAwayFromZero)
	fmt.Println(cents, conditions, err)

	refund, _, _ := line.Neg().Quantize(-2, decimal.TiesAwayFromZero)
	fmt.Println(refund)
}
Output:
2.145 TiesToEven 2.14
2.15 Inexact|Rounded|Increased <nil>
-2.15
const (
	// TiesToEven rounds to the nearest value and a tie to the even digit
	// (banker's rounding is TiesToEven): 2.35 → 2.4, 2.45 → 2.4,
	// −2.35 → −2.4. It is the zero value and the default of every context.
	TiesToEven RoundingMode = iota
	// TiesAwayFromZero rounds to the nearest value and a tie away from zero
	// (commercial rounding is TiesAwayFromZero): 2.45 → 2.5, −2.35 → −2.4,
	// −2.45 → −2.5. Select it explicitly for monetary rounding.
	TiesAwayFromZero
	// TiesTowardZero rounds to the nearest value and a tie toward zero:
	// 2.35 → 2.3, 2.36 → 2.4, −2.35 → −2.3.
	TiesTowardZero
	// TowardZero truncates: 2.36 → 2.3, −2.35 → −2.3, −2.36 → −2.3.
	TowardZero
	// AwayFromZero rounds any discarded nonzero digit away from zero:
	// 2.34 → 2.4, −2.34 → −2.4, −2.35 → −2.4.
	AwayFromZero
	// TowardPositiveInfinity rounds up (ceiling): 2.34 → 2.4, −2.35 → −2.3,
	// −2.36 → −2.3.
	TowardPositiveInfinity
	// TowardNegativeInfinity rounds down (floor): 2.36 → 2.3, −2.34 → −2.4,
	// −2.35 → −2.4.
	TowardNegativeInfinity
	// Exact refuses a value-changing round with a *Error trapping
	// Inexact: 2.30 → 2.3, while 2.35 and −2.35 are refused.
	Exact
)

func (RoundingMode) String

func (m RoundingMode) String() string

String returns the mode's identifier, or RoundingMode(n) for an unknown mode.

type SQLDecimal

type SQLDecimal struct{ Decimal Decimal }

SQLDecimal binds a Decimal through the database/sql decimal decompose convention, for drivers that recognize it (for example drivers that type parameters by value). The default parameter converter hands a type with Decompose to the driver instead of calling Value, so drivers without decompose support reject SQLDecimal; pass the Decimal itself to those drivers, which receive canonical text through Value. A NamedValueChecker sees SQLDecimal before the default converter. Bind SQL NULL as nil, never as a nil *SQLDecimal: database/sql calls Decompose on any decompose value it is given.

func (SQLDecimal) Decompose

func (v SQLDecimal) Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32)

Decompose returns form 0 (finite), the sign, the minimal big-endian coefficient magnitude (empty for zero) and the exponent. The magnitude is written into buf[:0] when its capacity suffices.

type Shape

type Shape struct {
	// Digits is the coefficient digit count, 0 exactly for zero.
	Digits uint64
	// Exponent is the stored exponent.
	Exponent int32
	// Negative is the sign.
	Negative bool
}

Shape is what a cost estimator needs of a Decimal operand: its coefficient digit count, exponent and sign. Digits is 0 exactly for zero, whose operations take cheaper paths; a refusal an estimator predicts for a nonzero shape (Digits ≥ 1) holds for every nonzero value of it. A caller that cannot rule out zero takes the Max of both estimates.

type SumShape

type SumShape struct {
	// Count is the number of operands.
	Count int
	// Digits is the total of their coefficient digits.
	Digits uint64
	// MinExponent is the smallest operand exponent.
	MinExponent int32
	// MaxAdjusted is the largest adjusted exponent of a nonzero operand.
	MaxAdjusted int64
	// Nonzero reports whether any operand is nonzero.
	Nonzero bool
}

SumShape describes a Sum's operands for EstimateSum without the values: their count, their total coefficient digits, the smallest exponent, the largest adjusted exponent of a nonzero operand, and whether any operand is nonzero. ShapeOfSum builds it.

func ShapeOfSum

func ShapeOfSum(values ...Decimal) SumShape

ShapeOfSum reads the SumShape of values in one pass over their headers.

Directories

Path Synopsis
Package benchmarks holds the F1–F8 benchmark portfolio for github.com/0xCarbon/decimal and its supplemental families (value operations, display extras, the Catalogue and Conversion families, the multiply family and others).
Package benchmarks holds the F1–F8 benchmark portfolio for github.com/0xCarbon/decimal and its supplemental families (value operations, display extras, the Catalogue and Conversion families, the multiply family and others).
tools
benchcmp command
Command benchcmp compares and aggregates `go test -bench` results using only the standard library.
Command benchcmp compares and aggregates `go test -bench` results using only the standard library.
checkdeps command
Command checkdeps audits every module of the repository.
Command checkdeps audits every module of the repository.
checkstate command
Command checkstate audits the library package for hidden state and unplanned panics.
Command checkstate audits the library package for hidden state and unplanned panics.
dectestconv command
Command dectestconv runs the decTest corpus workflow: provisioning, conversion and classification of the General Decimal Arithmetic testcases.
Command dectestconv runs the decTest corpus workflow: provisioning, conversion and classification of the General Decimal Arithmetic testcases.
float64table command
Command float64table writes float64_table.go:
Command float64table writes float64_table.go:
oracle command
Command oracle is the seeded rational differential: every rounding operation of the library is run through the public API on seeded random and constructed-tie inputs in every mode, and each result, its exponent or digit count, and its Inexact, Rounded and direction bits are compared with an exact math/big reference (reference.go).
Command oracle is the seeded rational differential: every rounding operation of the library is run through the public API on seeded random and constructed-tie inputs in every mode, and each result, its exponent or digit count, and its Inexact, Rounded and direction bits are compared with an exact math/big reference (reference.go).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL