decimal package - github.com/govalues/decimal - Go Packages

Package decimal implements decimal floating-point numbers with correct rounding. It is specifically designed for transactional financial systems and adheres to the principles set by ANSI X3.274-1996.

Internal Representation

Decimal is a struct with three fields:

  • Sign: A boolean indicating whether the decimal is negative.
  • Coefficient: An unsigned integer representing the numeric value of the decimal without the decimal point.
  • Scale: A non-negative integer indicating the position of the decimal point within the coefficient. For example, a decimal with a coefficient of 12345 and a scale of 2 represents the value 123.45. Conceptually, the scale can be understood as the inverse of the exponent in scientific notation. For example, a scale of 2 corresponds to an exponent of -2. The range of allowed values for the scale is from 0 to 19.

The numerical value of a decimal is calculated as follows:

  • -Coefficient / 10^Scale if Sign is true.
  • Coefficient / 10^Scale if Sign is false.

This approach allows the same numeric value to have multiple representations, for example, 1, 1.0, and 1.00, which represent the same value but have different scales and coefficients.

Constraints Overview

The range of a decimal is determined by its scale. Here are the ranges for frequently used scales:

| Example      | Scale | Minimum                              | Maximum                             |
| ------------ | ----- | ------------------------------------ | ----------------------------------- |
| Japanese Yen | 0     | -9,999,999,999,999,999,999           | 9,999,999,999,999,999,999           |
| US Dollar    | 2     |    -99,999,999,999,999,999.99        |    99,999,999,999,999,999.99        |
| Omani Rial   | 3     |     -9,999,999,999,999,999.999       |     9,999,999,999,999,999.999       |
| Bitcoin      | 8     |            -99,999,999,999.99999999  |            99,999,999,999.99999999  |
| Ethereum     | 9     |             -9,999,999,999.999999999 |             9,999,999,999.999999999 |

Subnormal numbers are not supported to ensure peak performance. Consequently, decimals between -0.00000000000000000005 and 0.00000000000000000005 inclusive, are rounded to 0.

Special values such as NaN, Infinity, or negative zeros are not supported. This ensures that arithmetic operations always produce either valid decimals or errors.

Arithmetic Operations

Each arithmetic operation occurs in two steps:

  1. The operation is initially performed using uint64 arithmetic. If no overflow occurs, the exact result is immediately returned. If overflow occurs, the operation proceeds to step 2.

  2. The operation is repeated with at least double precision using big.Int arithmetic. The result is then rounded to 19 digits. If no significant digits are lost during rounding, the inexact result is returned. If any significant digit is lost, an overflow error is returned.

Step 1 improves performance by avoiding the performance impact associated with big.Int arithmetic. It is expected that, in transactional financial systems, most arithmetic operations will compute an exact result during step 1.

The following rules determine the significance of digits during step 2:

Transcendental Functions

All transcendental functions are always computed with at least double precision using big.Int arithmetic. The result is then rounded to 19 digits. If no significant digits are lost during rounding, the inexact result is returned. If any significant digit is lost, an overflow error is returned.

The following rules determine the significance of digits:

Rounding Methods

For all operations, the result is the one that would be obtained by computing the exact result with infinite precision and then rounding it to 19 digits using half-to-even rounding. This method ensures that the result is as close as possible to the true mathematical value and that rounding errors are evenly distributed between rounding up and down.

In addition to implicit rounding, the package provides several methods for explicit rounding:

See the documentation for each method for more details.

Error Handling

All methods are panic-free and pure. Errors are returned in the following cases:

  • Division by Zero: Unlike Go's standard library, Decimal.Quo, Decimal.QuoRem, Decimal.Inv, Decimal.AddQuo, Decimal.SubQuo, do not panic when dividing by 0. Instead, they return an error.

  • Invalid Operation: Sum, Mean and Prod return an error if no arguments are provided. Decimal.PowInt returns an error if 0 is raised to a negative power. Decimal.Sqrt returns an error if the square root of a negative decimal is requested. Decimal.Log, Decimal.Log2, Decimal.Log10 return an error when calculating a logarithm of a non-positive decimal. Decimal.Log1p returns an error when calculating a logarithm of a decimal equal to or less than negative one. Decimal.Pow returns an error if 0 is raised to a negative powere or a negative decimal is raised to a fractional power.

  • Overflow: Unlike standard integers, decimals do not "wrap around" when exceeding their maximum value. For out-of-range values, methods return an error.

Errors are not returned in the following cases:

  • Underflow: Methods do not return an error for decimal underflow. If the result is a decimal between -0.00000000000000000005 and 0.00000000000000000005 inclusive, it will be rounded to 0.

Data Conversion

A. JSON

The package integrates with standard encoding/json through the implementation of json.Marshaler and json.Unmarshaler interfaces. Below is an example structure:

type Object struct {
  Number decimal.Decimal `json:"some_number"`
  // Other fields...
}

This package marshals decimals as quoted strings, ensuring the preservation of the exact numerical value. Below is an example OpenAPI schema:

Decimal:
  type: string
  format: decimal
  pattern: '^(\-|\+)?((\d+(\.\d*)?)|(\.\d+))$'

B. BSON

The package integrates with mongo-driver/bson via the implementation of v2/bson.ValueMarshaler and v2/bson.ValueUnmarshaler interfaces. Below is an example structure:

type Record struct {
  Number decimal.Decimal `bson:"some_number"`
  // Other fields...
}

This package marshals decimals as Decimal128, ensuring the preservation of the exact numerical value.

C. XML

The package integrates with standard encoding/xml via the implementation of encoding.TextMarshaller and encoding.TextUnmarshaler interfaces. Below is an example structure:

type Entity struct {
  Number decimal.Decimal `xml:"SomeNumber"`
  // Other fields...
}

"xs:decimal" type can represent decimals in XML schema. It is possible to impose restrictions on the length of the decimals using the following type:

<xs:simpleType name="Decimal">
  <xs:restriction base="xs:decimal">
    <xs:totalDigits value="19"/>
  </xs:restriction>
</xs:simpleType>

D. Protocol Buffers

Protocol Buffers provide two formats to represent decimals. The first format represents decimals as numerical strings. The main advantage of this format is that it preserves trailing zeros. To convert between this format and decimals, use Parse and Decimal.String. Below is an example of a proto definition:

message Decimal {
  string value = 1;
}

The second format represents decimals as a pair of integers: one for the integer part and another for the fractional part. This format does not preserve trailing zeros and rounds decimals with more than nine digits in the fractional part. For conversion between this format and decimals, use NewFromInt64 and Decimal.Int64 with a scale argument of "9". Below is an example of a proto definition:

message Decimal {
  int64 units = 1;
  int32 nanos = 2;
}

E. SQL

The package integrates with the standard database/sql via the implementation of sql.Scanner and driver.Valuer interfaces. To ensure accurate preservation of decimal scales, it is essential to choose appropriate column types:

| Database   | Type                          |
| ---------- | ----------------------------- |
| PostgreSQL | DECIMAL                       |
| SQLite     | TEXT                          |
| MySQL      | DECIMAL(19, d) or VARCHAR(22) |

Below are the reasons for these preferences:

  • PostgreSQL: Always use DECIMAL without precision or scale specifications, that is, avoid DECIMAL(p) or DECIMAL(p, s). DECIMAL accurately preserves the scale of decimals.

  • SQLite: Prefer TEXT, since DECIMAL is just an alias for binary floating-point numbers. TEXT accurately preserves the scale of decimals.

  • MySQL: Use DECIMAL(19, d), as DECIMAL is merely an alias for DECIMAL(10, 0). The downside of this format is that MySQL automatically rescales all decimals: it rounds values with more than d digits in the fractional part (using half away from zero) and pads with trailing zeros those with fewer than d digits in the fractional part. To prevent automatic rescaling, consider using VARCHAR(22), which accurately preserves the scale of decimals.

Mathematical Context

Unlike many other decimal libraries, this package does not provide an explicit mathematical context. Instead, the context is implicit and can be approximately equated to the following settings:

| Attribute               | Value                                           |
| ----------------------- | ----------------------------------------------- |
| Precision               | 19                                              |
| Maximum Exponent (Emax) | 18                                              |
| Minimum Exponent (Emin) | -19                                             |
| Tiny Exponent (Etiny)   | -19                                             |
| Rounding Method         | Half To Even                                    |
| Enabled Traps           | Division by Zero, Invalid Operation, Overflow   |
| Disabled Traps          | Inexact, Clamped, Rounded, Subnormal, Underflow |

The equality of Etiny and Emin implies that this package does not support subnormal numbers.

This example demonstrates the advantage of decimals for financial calculations. It computes the sum 0.1 + 0.2 using both decimal and float64 arithmetic. In decimal arithmetic, the result is exactly 0.3, as expected. In float64 arithmetic, the result is 0.30000000000000004 due to floating-point inaccuracy.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	a := decimal.MustParse("0.1")
	b := decimal.MustParse("0.2")
	fmt.Println(a.Add(b))

	x := 0.1
	y := 0.2
	fmt.Println(x + y)
}
Output:

0.3 <nil>
0.30000000000000004

This example calculates an approximate value of π using the Leibniz formula. The Leibniz formula is an infinite series that converges to π/4, and is given by the equation: 1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + ... = π/4. This example computes the series up to the 500,000th term using decimal arithmetic and returns the approximate value of π.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	fmt.Println(approximate(500_000))
	fmt.Println(decimal.Pi)
}

func approximate(terms int) (decimal.Decimal, error) {
	pi := decimal.Zero
	denominator := decimal.One
	increment := decimal.Two
	multiplier := decimal.MustParse("4")

	var err error
	for range terms {
		pi, err = pi.AddQuo(multiplier, denominator)
		if err != nil {
			return decimal.Decimal{}, err
		}
		denominator, err = denominator.Add(increment)
		if err != nil {
			return decimal.Decimal{}, err
		}
		multiplier = multiplier.Neg()
	}
	return pi, nil
}
Output:

3.141590653589793192 <nil>
3.141592653589793238

This example implements a simple calculator that evaluates mathematical expressions written in postfix notation. The calculator can handle basic arithmetic operations such as addition, subtraction, multiplication, and division.

package main

import (
	"fmt"
	"strings"

	"github.com/govalues/decimal"
)

func main() {
	fmt.Println(evaluate("1.23 4.56 + 10 *"))
}

func evaluate(input string) (decimal.Decimal, error) {
	tokens := strings.Fields(input)
	if len(tokens) == 0 {
		return decimal.Decimal{}, fmt.Errorf("no tokens")
	}
	stack := make([]decimal.Decimal, 0, len(tokens))
	for i, token := range tokens {
		var err error
		var result decimal.Decimal
		if token == "+" || token == "-" || token == "*" || token == "/" {
			if len(stack) < 2 {
				return decimal.Decimal{}, fmt.Errorf("not enough operands")
			}
			left := stack[len(stack)-2]
			right := stack[len(stack)-1]
			stack = stack[:len(stack)-2]
			switch token {
			case "+":
				result, err = left.Add(right)
			case "-":
				result, err = left.Sub(right)
			case "*":
				result, err = left.Mul(right)
			case "/":
				result, err = left.Quo(right)
			}
		} else {
			result, err = decimal.Parse(token)
		}
		if err != nil {
			return decimal.Decimal{}, fmt.Errorf("processing token %q at position %v: %w", token, i, err)
		}
		stack = append(stack, result)
	}
	if len(stack) != 1 {
		return decimal.Decimal{}, fmt.Errorf("stack contains %v, expected exactly one item", stack)
	}
	return stack[0], nil
}
Output:

57.90 <nil>

View Source

const (
	MaxPrec  = 19 
	MinScale = 0  
	MaxScale = 19 

)

View Source

var (
	NegOne   = MustNew(-1, 0)                         
	Zero     = MustNew(0, 0)                          
	One      = MustNew(1, 0)                          
	Two      = MustNew(2, 0)                          
	Ten      = MustNew(10, 0)                         
	Hundred  = MustNew(100, 0)                        
	Thousand = MustNew(1_000, 0)                      
	E        = MustNew(2_718_281_828_459_045_235, 18) 
	Pi       = MustNew(3_141_592_653_589_793_238, 18) 

)

This section is empty.

Decimal represents a finite floating-point decimal number. Its zero value corresponds to the numeric value of 0. Decimal is designed to be safe for concurrent use by multiple goroutines.

Mean returns the (possibly rounded) mean of decimals. It computes (d1 + d2 + ... + dn) / n with at least double precision during the intermediate rounding.

Mean returns an error if:

  • no arguments are provided;
  • the integer part of the result has more than MaxPrec digits.
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.67")
	e := decimal.MustParse("-8")
	f := decimal.MustParse("23")
	fmt.Println(decimal.Mean(d, e, f))
}
Output:

6.89 <nil>

MustNew is like New but panics if the decimal cannot be constructed. It simplifies safe initialization of global variables holding decimals.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	fmt.Println(decimal.MustNew(567, 0))
	fmt.Println(decimal.MustNew(567, 1))
	fmt.Println(decimal.MustNew(567, 2))
	fmt.Println(decimal.MustNew(567, 3))
	fmt.Println(decimal.MustNew(567, 4))
}
Output:

567
56.7
5.67
0.567
0.0567

MustParse is like Parse but panics if the string cannot be parsed. It simplifies safe initialization of global variables holding decimals.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	fmt.Println(decimal.MustParse("-1.23"))
}
Output:

-1.23

New returns a decimal equal to value / 10^scale. New keeps trailing zeros in the fractional part to preserve scale.

New returns an error if the scale is negative or greater than MaxScale.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	fmt.Println(decimal.New(567, 0))
	fmt.Println(decimal.New(567, 1))
	fmt.Println(decimal.New(567, 2))
	fmt.Println(decimal.New(567, 3))
	fmt.Println(decimal.New(567, 4))
}
Output:

567 <nil>
56.7 <nil>
5.67 <nil>
0.567 <nil>
0.0567 <nil>

NewFromFloat64 converts a float to a (possibly rounded) decimal. See also method Decimal.Float64.

NewFromFloat64 returns an error if:

  • the float is a special value (NaN or Inf);
  • the integer part of the result has more than MaxPrec digits.
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	fmt.Println(decimal.NewFromFloat64(5.67e-2))
	fmt.Println(decimal.NewFromFloat64(5.67e-1))
	fmt.Println(decimal.NewFromFloat64(5.67e0))
	fmt.Println(decimal.NewFromFloat64(5.67e1))
	fmt.Println(decimal.NewFromFloat64(5.67e2))
}
Output:

0.0567 <nil>
0.567 <nil>
5.67 <nil>
56.7 <nil>
567 <nil>

NewFromInt64 converts a pair of integers, representing the whole and fractional parts, to a (possibly rounded) decimal equal to whole + frac / 10^scale. NewFromInt64 removes all trailing zeros from the fractional part. This method is useful for converting amounts from protobuf format. See also method Decimal.Int64.

NewFromInt64 returns an error if:

  • the whole and fractional parts have different signs;
  • the scale is negative or greater than MaxScale;
  • frac / 10^scale is not within the range (-1, 1).
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	fmt.Println(decimal.NewFromInt64(5, 6, 1))
	fmt.Println(decimal.NewFromInt64(5, 6, 2))
	fmt.Println(decimal.NewFromInt64(5, 6, 3))
	fmt.Println(decimal.NewFromInt64(5, 6, 4))
	fmt.Println(decimal.NewFromInt64(5, 6, 5))
}
Output:

5.6 <nil>
5.06 <nil>
5.006 <nil>
5.0006 <nil>
5.00006 <nil>

Parse converts a string to a (possibly rounded) decimal. The input string must be in one of the following formats:

1.234
-1234
+0.000001234
1.83e5
0.22e-9

The formal EBNF grammar for the supported format is as follows:

sign           ::= '+' | '-'
digits         ::= { '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' }
significand    ::= digits '.' digits | '.' digits | digits '.' | digits
exponent       ::= ('e' | 'E') [sign] digits
numeric-string ::= [sign] significand [exponent]

Parse removes leading zeros from the integer part of the input string, but tries to maintain trailing zeros in the fractional part to preserve scale.

Parse returns an error if:

  • the string contains any whitespaces;
  • the string is longer than 330 bytes;
  • the exponent is less than -330 or greater than 330;
  • the string does not represent a valid decimal number;
  • the integer part of the result has more than MaxPrec digits.
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	fmt.Println(decimal.Parse("5.67"))
}
Output:

5.67 <nil>

ParseExact is similar to Parse, but it allows you to specify how many digits after the decimal point should be considered significant. If any of the significant digits are lost during rounding, the method will return an error. This method is useful for parsing monetary amounts, where the scale should be equal to or greater than the currency's scale.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	fmt.Println(decimal.ParseExact("5.67", 0))
	fmt.Println(decimal.ParseExact("5.67", 1))
	fmt.Println(decimal.ParseExact("5.67", 2))
	fmt.Println(decimal.ParseExact("5.67", 3))
	fmt.Println(decimal.ParseExact("5.67", 4))
}
Output:

5.67 <nil>
5.67 <nil>
5.67 <nil>
5.670 <nil>
5.6700 <nil>

Prod returns the (possibly rounded) product of decimals. It computes d1 * d2 * ... * dn with at least double precision during the intermediate rounding.

Prod returns an error if:

  • no arguments are provided;
  • the integer part of the result has more than MaxPrec digits.
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.67")
	e := decimal.MustParse("-8")
	f := decimal.MustParse("23")
	fmt.Println(decimal.Prod(d, e, f))
}
Output:

-1043.28 <nil>

Sum returns the (possibly rounded) sum of decimals. It computes d1 + d2 + ... + dn without intermediate rounding.

Sum returns an error if:

  • no argements are provided;
  • the integer part of the result has more than MaxPrec digits.
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.67")
	e := decimal.MustParse("-8")
	f := decimal.MustParse("23")
	fmt.Println(decimal.Sum(d, e, f))
}
Output:

20.67 <nil>
func (d Decimal) Abs() Decimal

Abs returns the absolute value of the decimal.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-5.67")
	fmt.Println(d.Abs())
}
Output:

5.67

Add returns the (possibly rounded) sum of decimals d and e.

Add returns an error if the integer part of the result has more than MaxPrec digits.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.67")
	e := decimal.MustParse("8")
	fmt.Println(d.Add(e))
}
Output:

13.67 <nil>

AddExact is similar to Decimal.Add, but it allows you to specify the number of digits after the decimal point that should be considered significant. If any of the significant digits are lost during rounding, the method will return an error. This method is useful for financial calculations where the scale should be equal to or greater than the currency's scale.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.67")
	e := decimal.MustParse("8")
	fmt.Println(d.AddExact(e, 0))
	fmt.Println(d.AddExact(e, 1))
	fmt.Println(d.AddExact(e, 2))
	fmt.Println(d.AddExact(e, 3))
	fmt.Println(d.AddExact(e, 4))
}
Output:

13.67 <nil>
13.67 <nil>
13.67 <nil>
13.670 <nil>
13.6700 <nil>

AddMul returns the (possibly rounded) fused multiply-addition of decimals d, e, and f. It computes d + e * f without any intermediate rounding. This method is useful for improving the accuracy and performance of algorithms that involve the accumulation of products, such as daily interest accrual.

AddMul returns an error if the integer part of the result has more than MaxPrec digits.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("2")
	e := decimal.MustParse("3")
	f := decimal.MustParse("4")
	fmt.Println(d.AddMul(e, f))
}
Output:

14 <nil>

AddMulExact is similar to Decimal.AddMul, but it allows you to specify the number of digits after the decimal point that should be considered significant. If any of the significant digits are lost during rounding, the method will return an error. This method is useful for financial calculations where the scale should be equal to or greater than the currency's scale.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("2")
	e := decimal.MustParse("3")
	f := decimal.MustParse("4")
	fmt.Println(d.AddMulExact(e, f, 0))
	fmt.Println(d.AddMulExact(e, f, 1))
	fmt.Println(d.AddMulExact(e, f, 2))
	fmt.Println(d.AddMulExact(e, f, 3))
	fmt.Println(d.AddMulExact(e, f, 4))
}
Output:

14 <nil>
14.0 <nil>
14.00 <nil>
14.000 <nil>
14.0000 <nil>

AddQuo returns the (possibly rounded) fused quotient-addition of decimals d, e, and f. It computes d + e / f with at least double precision during the intermediate rounding. This method is useful for improving the accuracy and performance of algorithms that involve the accumulation of quotients, such as internal rate of return.

AddQuo returns an error if:

  • the divisor is 0;
  • the integer part of the result has more than MaxPrec digits.
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("2")
	e := decimal.MustParse("3")
	f := decimal.MustParse("4")
	fmt.Println(d.AddQuo(e, f))
}
Output:

2.75 <nil>

AddQuoExact is similar to Decimal.AddQuo, but it allows you to specify the number of digits after the decimal point that should be considered significant. If any of the significant digits are lost during rounding, the method will return an error. This method is useful for financial calculations where the scale should be equal to or greater than the currency's scale.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("2")
	e := decimal.MustParse("3")
	f := decimal.MustParse("4")
	fmt.Println(d.AddQuoExact(e, f, 0))
	fmt.Println(d.AddQuoExact(e, f, 1))
	fmt.Println(d.AddQuoExact(e, f, 2))
	fmt.Println(d.AddQuoExact(e, f, 3))
	fmt.Println(d.AddQuoExact(e, f, 4))
}
Output:

2.75 <nil>
2.75 <nil>
2.75 <nil>
2.750 <nil>
2.7500 <nil>

AppendBinary implements the encoding.BinaryAppender interface. AppendBinary always appends a numeric string. See also method Decimal.String.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.67")
	var data []byte
	data = append(data, 0x04)
	data, err := d.AppendBinary(data)
	data = append(data, 0x00)
	fmt.Printf("% x %v\n", data, err)
}
Output:

04 35 2e 36 37 00 <nil>

AppendText implements the encoding.TextAppender interface. AppendText always appends a numeric string. See also method Decimal.String.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	var text []byte
	d := decimal.MustParse("5.67")
	text = append(text, "<Decimal>"...)
	text, err := d.AppendText(text)
	text = append(text, "</Decimal>"...)
	fmt.Printf("%s %v\n", text, err)
}
Output:

<Decimal>5.67</Decimal> <nil>
func (d Decimal) Ceil(scale int) Decimal

Ceil returns a decimal rounded up to the given number of digits after the decimal point using rounding toward positive infinity. If the given scale is negative, it is redefined to zero. For financial calculations, the scale should be equal to or greater than the scale of the currency. See also method Decimal.Floor.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.678")
	fmt.Println(d.Ceil(0))
	fmt.Println(d.Ceil(1))
	fmt.Println(d.Ceil(2))
	fmt.Println(d.Ceil(3))
	fmt.Println(d.Ceil(4))
}
Output:

6
5.7
5.68
5.678
5.678
func (d Decimal) Clamp(min, max Decimal) (Decimal, error)

Clamp compares decimals and returns:

min if d < min
max if d > max
  d otherwise

See also method Decimal.CmpTotal.

Clamp returns an error if min is greater than max numerically.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	min := decimal.MustParse("-20")
	max := decimal.MustParse("20")
	d := decimal.MustParse("-5.67")
	e := decimal.MustParse("0")
	f := decimal.MustParse("23")
	fmt.Println(d.Clamp(min, max))
	fmt.Println(e.Clamp(min, max))
	fmt.Println(f.Clamp(min, max))
}
Output:

-5.67 <nil>
0 <nil>
20 <nil>

Cmp compares decimals and returns:

-1 if d < e
 0 if d = e
+1 if d > e

See also methods Decimal.CmpAbs, Decimal.CmpTotal.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-23")
	e := decimal.MustParse("5.67")
	fmt.Println(d.Cmp(e))
	fmt.Println(d.Cmp(d))
	fmt.Println(e.Cmp(d))
}
Output:

-1
0
1
package main

import (
	"fmt"
	"slices"

	"github.com/govalues/decimal"
)

func main() {
	s := []decimal.Decimal{
		decimal.MustParse("-5.67"),
		decimal.MustParse("23"),
		decimal.MustParse("0"),
	}
	fmt.Println(slices.CompareFunc(s, s, decimal.Decimal.Cmp))
	fmt.Println(slices.MaxFunc(s, decimal.Decimal.Cmp))
	fmt.Println(slices.MinFunc(s, decimal.Decimal.Cmp))
	fmt.Println(s, slices.IsSortedFunc(s, decimal.Decimal.Cmp))
	slices.SortFunc(s, decimal.Decimal.Cmp)
	fmt.Println(s, slices.IsSortedFunc(s, decimal.Decimal.Cmp))
	fmt.Println(slices.BinarySearchFunc(s, decimal.MustParse("1"), decimal.Decimal.Cmp))
}
Output:

0
23
-5.67
[-5.67 23 0] false
[-5.67 0 23] true
2 false
func (d Decimal) CmpAbs(e Decimal) int

CmpAbs compares absolute values of decimals and returns:

-1 if |d| < |e|
 0 if |d| = |e|
+1 if |d| > |e|

See also method Decimal.Cmp.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-23")
	e := decimal.MustParse("5.67")
	fmt.Println(d.CmpAbs(e))
	fmt.Println(d.CmpAbs(d))
	fmt.Println(e.CmpAbs(d))
}
Output:

1
0
-1
package main

import (
	"fmt"
	"slices"

	"github.com/govalues/decimal"
)

func main() {
	s := []decimal.Decimal{
		decimal.MustParse("-5.67"),
		decimal.MustParse("23"),
		decimal.MustParse("0"),
	}
	fmt.Println(slices.CompareFunc(s, s, decimal.Decimal.CmpAbs))
	fmt.Println(slices.MaxFunc(s, decimal.Decimal.CmpAbs))
	fmt.Println(slices.MinFunc(s, decimal.Decimal.CmpAbs))
	fmt.Println(s, slices.IsSortedFunc(s, decimal.Decimal.CmpAbs))
	slices.SortFunc(s, decimal.Decimal.CmpAbs)
	fmt.Println(s, slices.IsSortedFunc(s, decimal.Decimal.CmpAbs))
	fmt.Println(slices.BinarySearchFunc(s, decimal.MustParse("1"), decimal.Decimal.CmpAbs))
}
Output:

0
23
0
[-5.67 23 0] false
[0 -5.67 23] true
1 false
func (d Decimal) CmpTotal(e Decimal) int

CmpTotal compares decimal representations and returns:

-1 if d < e
-1 if d = e and d.scale > e.scale
 0 if d = e and d.scale = e.scale
+1 if d = e and d.scale < e.scale
+1 if d > e

See also method Decimal.Cmp.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("2.0")
	e := decimal.MustParse("2.00")
	fmt.Println(d.CmpTotal(e))
	fmt.Println(d.CmpTotal(d))
	fmt.Println(e.CmpTotal(d))
}
Output:

1
0
-1
package main

import (
	"fmt"
	"slices"

	"github.com/govalues/decimal"
)

func main() {
	s := []decimal.Decimal{
		decimal.MustParse("-5.67"),
		decimal.MustParse("23"),
		decimal.MustParse("0"),
	}
	fmt.Println(slices.CompareFunc(s, s, decimal.Decimal.CmpTotal))
	fmt.Println(slices.MaxFunc(s, decimal.Decimal.CmpTotal))
	fmt.Println(slices.MinFunc(s, decimal.Decimal.CmpTotal))
	fmt.Println(s, slices.IsSortedFunc(s, decimal.Decimal.CmpTotal))
	slices.SortFunc(s, decimal.Decimal.CmpTotal)
	fmt.Println(s, slices.IsSortedFunc(s, decimal.Decimal.CmpTotal))
	fmt.Println(slices.BinarySearchFunc(s, decimal.MustParse("10"), decimal.Decimal.CmpTotal))
}
Output:

0
23
-5.67
[-5.67 23 0] false
[-5.67 0 23] true
2 false

Coef returns the coefficient of the decimal. See also method Decimal.Prec.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-123")
	e := decimal.MustParse("5.7")
	f := decimal.MustParse("0.4")
	fmt.Println(d.Coef())
	fmt.Println(e.Coef())
	fmt.Println(f.Coef())
}
Output:

123
57
4
func (d Decimal) CopySign(e Decimal) Decimal

CopySign returns a decimal with the same sign as decimal e. CopySign treates 0 as positive. See also method Decimal.Sign.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("23.00")
	e := decimal.MustParse("-5.67")
	fmt.Println(d.CopySign(e))
	fmt.Println(e.CopySign(d))
}
Output:

-23.00
5.67

Equal compares decimals and returns:

 true if d = e
false otherwise

See also method Decimal.Cmp.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-23")
	e := decimal.MustParse("5.67")
	fmt.Println(d.Equal(e))
	fmt.Println(d.Equal(d))
}
Output:

false
true
package main

import (
	"fmt"
	"slices"

	"github.com/govalues/decimal"
)

func main() {
	s := []decimal.Decimal{
		decimal.MustParse("-5.67"),
		decimal.MustParse("0"),
		decimal.MustParse("0"),
	}
	fmt.Println(slices.EqualFunc(s, s, decimal.Decimal.Equal))
	fmt.Println(slices.CompactFunc(s, decimal.Decimal.Equal))
}
Output:

true
[-5.67 0]

Exp returns the (possibly rounded) exponential of a decimal.

Exp returns an error if the integer part of the result has more than MaxPrec digits.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-2.302585092994045684")
	e := decimal.MustParse("0")
	f := decimal.MustParse("2.302585092994045684")
	fmt.Println(d.Exp())
	fmt.Println(e.Exp())
	fmt.Println(f.Exp())
}
Output:

0.1000000000000000000 <nil>
1 <nil>
10.00000000000000000 <nil>

Expm1 returns the (possibly rounded) shifted exponential of a decimal.

Expm1 returns an error if the integer part of the result has more than MaxPrec digits.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-2.302585092994045684")
	e := decimal.MustParse("0")
	f := decimal.MustParse("2.302585092994045684")
	fmt.Println(d.Expm1())
	fmt.Println(e.Expm1())
	fmt.Println(f.Expm1())
}
Output:

-0.9000000000000000000 <nil>
0 <nil>
9.000000000000000000 <nil>

Float64 returns the nearest binary floating-point number rounded using rounding half to even (banker's rounding). See also constructor NewFromFloat64.

This conversion may lose data, as float64 has a smaller precision than the decimal type.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("0.1")
	e := decimal.MustParse("123.456")
	f := decimal.MustParse("1234567890.123456789")
	fmt.Println(d.Float64())
	fmt.Println(e.Float64())
	fmt.Println(f.Float64())
}
Output:

0.1 true
123.456 true
1.2345678901234567e+09 true
func (d Decimal) Floor(scale int) Decimal

Floor returns a decimal rounded down to the specified number of digits after the decimal point using rounding toward negative infinity. If the given scale is negative, it is redefined to zero. For financial calculations, the scale should be equal to or greater than the scale of the currency. See also method Decimal.Ceil.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.678")
	fmt.Println(d.Floor(0))
	fmt.Println(d.Floor(1))
	fmt.Println(d.Floor(2))
	fmt.Println(d.Floor(3))
	fmt.Println(d.Floor(4))
}
Output:

5
5.6
5.67
5.678
5.678

Format implements the fmt.Formatter interface. The following format verbs are available:

| Verb       | Example | Description    |
| ---------- | ------- | -------------- |
| %f, %s, %v | 5.67    | Decimal        |
| %q         | "5.67"  | Quoted decimal |
| %k         | 567%    | Percentage     |

The following format flags can be used with all verbs: '+', ' ', '0', '-'.

Precision is only supported for %f and %k verbs. For %f verb, the default precision is equal to the actual scale of the decimal, whereas, for verb %k the default precision is the actual scale of the decimal minus 2.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.67")
	fmt.Printf("%f\n", d)
	fmt.Printf("%k\n", d)
}
Output:

5.67
567%

Int64 returns a pair of integers representing the whole and (possibly rounded) fractional parts of the decimal. If given scale is greater than the scale of the decimal, then the fractional part is zero-padded to the right. If given scale is smaller than the scale of the decimal, then the fractional part is rounded using rounding half to even (banker's rounding). The relationship between the decimal and the returned values can be expressed as d = whole + frac / 10^scale. This method is useful for converting amounts to protobuf format. See also constructor NewFromInt64.

If the result cannot be represented as a pair of int64 values, then false is returned.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.67")
	fmt.Println(d.Int64(0))
	fmt.Println(d.Int64(1))
	fmt.Println(d.Int64(2))
	fmt.Println(d.Int64(3))
	fmt.Println(d.Int64(4))
}
Output:

6 0 true
5 7 true
5 67 true
5 670 true
5 6700 true

Inv returns the (possibly rounded) inverse of the decimal.

Inv returns an error if:

  • the integer part of the result has more than MaxPrec digits;
  • the decimal is 0.
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("2")
	fmt.Println(d.Inv())
}
Output:

0.5 <nil>

IsInt returns true if there are no significant digits after the decimal point.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("1.00")
	e := decimal.MustParse("1.01")
	fmt.Println(d.IsInt())
	fmt.Println(e.IsInt())
}
Output:

true
false
package main

import (
	"fmt"
	"slices"

	"github.com/govalues/decimal"
)

func main() {
	s := []decimal.Decimal{
		decimal.MustParse("-5.67"),
		decimal.MustParse("23"),
		decimal.MustParse("0"),
	}
	fmt.Println(slices.ContainsFunc(s, decimal.Decimal.IsInt))
	fmt.Println(slices.IndexFunc(s, decimal.Decimal.IsInt))
	fmt.Println(slices.DeleteFunc(s, decimal.Decimal.IsInt))
}
Output:

true
1
[-5.67]

IsNeg returns:

true  if d < 0
false otherwise
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-5.67")
	e := decimal.MustParse("23")
	f := decimal.MustParse("0")
	fmt.Println(d.IsNeg())
	fmt.Println(e.IsNeg())
	fmt.Println(f.IsNeg())
}
Output:

true
false
false
package main

import (
	"fmt"
	"slices"

	"github.com/govalues/decimal"
)

func main() {
	s := []decimal.Decimal{
		decimal.MustParse("-5.67"),
		decimal.MustParse("23"),
		decimal.MustParse("0"),
	}
	fmt.Println(slices.ContainsFunc(s, decimal.Decimal.IsNeg))
	fmt.Println(slices.IndexFunc(s, decimal.Decimal.IsNeg))
	fmt.Println(slices.DeleteFunc(s, decimal.Decimal.IsNeg))
}
Output:

true
0
[23 0]

IsOne returns:

true  if d = -1 or d = 1
false otherwise
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("1")
	e := decimal.MustParse("2")
	fmt.Println(d.IsOne())
	fmt.Println(e.IsOne())
}
Output:

true
false
package main

import (
	"fmt"
	"slices"

	"github.com/govalues/decimal"
)

func main() {
	s := []decimal.Decimal{
		decimal.MustParse("-5.67"),
		decimal.MustParse("23"),
		decimal.MustParse("1"),
	}
	fmt.Println(slices.ContainsFunc(s, decimal.Decimal.IsOne))
	fmt.Println(slices.IndexFunc(s, decimal.Decimal.IsOne))
	fmt.Println(slices.DeleteFunc(s, decimal.Decimal.IsOne))
}
Output:

true
2
[-5.67 23]

IsPos returns:

true  if d > 0
false otherwise
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-5.67")
	e := decimal.MustParse("23")
	f := decimal.MustParse("0")
	fmt.Println(d.IsPos())
	fmt.Println(e.IsPos())
	fmt.Println(f.IsPos())
}
Output:

false
true
false
package main

import (
	"fmt"
	"slices"

	"github.com/govalues/decimal"
)

func main() {
	s := []decimal.Decimal{
		decimal.MustParse("-5.67"),
		decimal.MustParse("23"),
		decimal.MustParse("0"),
	}
	fmt.Println(slices.ContainsFunc(s, decimal.Decimal.IsPos))
	fmt.Println(slices.IndexFunc(s, decimal.Decimal.IsPos))
	fmt.Println(slices.DeleteFunc(s, decimal.Decimal.IsPos))
}
Output:

true
1
[-5.67 0]

IsZero returns:

true  if d = 0
false otherwise
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-5.67")
	e := decimal.MustParse("23")
	f := decimal.MustParse("0")
	fmt.Println(d.IsZero())
	fmt.Println(e.IsZero())
	fmt.Println(f.IsZero())
}
Output:

false
false
true
package main

import (
	"fmt"
	"slices"

	"github.com/govalues/decimal"
)

func main() {
	s := []decimal.Decimal{
		decimal.MustParse("-5.67"),
		decimal.MustParse("23"),
		decimal.MustParse("0"),
	}
	fmt.Println(slices.ContainsFunc(s, decimal.Decimal.IsZero))
	fmt.Println(slices.IndexFunc(s, decimal.Decimal.IsZero))
	fmt.Println(slices.DeleteFunc(s, decimal.Decimal.IsZero))
}
Output:

true
2
[-5.67 23]

Less compares decimals and returns:

 true if d < e
false otherwise

See also method Decimal.Cmp.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-23")
	e := decimal.MustParse("5.67")
	fmt.Println(d.Less(e))
	fmt.Println(e.Less(d))
}
Output:

true
false

Log returns the (possibly rounded) natural logarithm of a decimal.

Log returns an error if the decimal is zero or negative.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("1")
	e := decimal.MustParse("2")
	f := decimal.MustParse("2.718281828459045236")
	g := decimal.MustParse("10")
	fmt.Println(d.Log())
	fmt.Println(e.Log())
	fmt.Println(f.Log())
	fmt.Println(g.Log())
}
Output:

0 <nil>
0.6931471805599453094 <nil>
1.000000000000000000 <nil>
2.302585092994045684 <nil>

Log1p returns the (possibly rounded) shifted natural logarithm of a decimal.

Log1p returns an error if the decimal is equal to or less than negative one.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("1")
	e := decimal.MustParse("2")
	f := decimal.MustParse("2.718281828459045236")
	g := decimal.MustParse("10")
	fmt.Println(d.Log1p())
	fmt.Println(e.Log1p())
	fmt.Println(f.Log1p())
	fmt.Println(g.Log1p())
}
Output:

0.6931471805599453094 <nil>
1.098612288668109691 <nil>
1.313261687518222834 <nil>
2.397895272798370544 <nil>

Log2 returns the (possibly rounded) binary logarithm of a decimal.

Log2 returns an error if the decimal is zero or negative.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("1")
	e := decimal.MustParse("2")
	f := decimal.MustParse("2.718281828459045236")
	g := decimal.MustParse("10")
	fmt.Println(d.Log2())
	fmt.Println(e.Log2())
	fmt.Println(f.Log2())
	fmt.Println(g.Log2())
}
Output:

0 <nil>
1 <nil>
1.442695040888963408 <nil>
3.321928094887362348 <nil>

Log10 returns the (possibly rounded) decimal logarithm of a decimal.

Log10 returns an error if the decimal is zero or negative.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("1")
	e := decimal.MustParse("2")
	f := decimal.MustParse("2.718281828459045236")
	g := decimal.MustParse("10")
	fmt.Println(d.Log10())
	fmt.Println(e.Log10())
	fmt.Println(f.Log10())
	fmt.Println(g.Log10())
}
Output:

0 <nil>
0.3010299956639811952 <nil>
0.4342944819032518278 <nil>
1 <nil>

MarshalBSONValue implements the v2/bson.ValueMarshaler interface. MarshalBSONValue always returns Decimal128.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.67")
	t, data, err := d.MarshalBSONValue()
	fmt.Printf("%v [% x] %v\n", t, data, err)
}
Output:

19 [37 02 00 00 00 00 00 00 00 00 00 00 00 00 3c 30] <nil>

MarshalBinary implements the encoding.BinaryMarshaler interface. MarshalBinary always returns a numeric string. See also method Decimal.String.

package main

import (
	"bytes"
	"encoding/gob"
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	data, err := marshalGOB("5.67")
	fmt.Printf("[% x] %v\n", data, err)
}

func marshalGOB(s string) ([]byte, error) {
	d, err := decimal.Parse(s)
	if err != nil {
		return nil, err
	}
	var data bytes.Buffer
	enc := gob.NewEncoder(&data)
	err = enc.Encode(d)
	if err != nil {
		return nil, err
	}
	return data.Bytes(), nil
}
Output:

[12 7f 06 01 01 07 44 65 63 69 6d 61 6c 01 ff 80 00 00 00 08 ff 80 00 04 35 2e 36 37] <nil>

MarshalJSON implements the json.Marshaler interface. MarshalJSON always returns a numeric string. See also method Decimal.String.

package main

import (
	"encoding/json"
	"fmt"

	"github.com/govalues/decimal"
)

type Account struct {
	Balance decimal.Decimal `json:"balance"`
}

func main() {
	fmt.Println(marshalJSON("5.67"))
	fmt.Println(marshalJSON("-5.67"))
}

func marshalJSON(s string) (string, error) {
	d, err := decimal.Parse(s)
	if err != nil {
		return "", err
	}
	data, err := json.Marshal(Account{Balance: d})
	if err != nil {
		return "", err
	}
	return string(data), nil
}
Output:

{"balance":"5.67"} <nil>
{"balance":"-5.67"} <nil>

MarshalText implements the encoding.TextMarshaler interface. MarshalText always returns a numeric string. See also method Decimal.String.

package main

import (
	"encoding/xml"
	"fmt"

	"github.com/govalues/decimal"
)

type Transaction struct {
	Amount decimal.Decimal `xml:"Amount"`
}

func main() {
	fmt.Println(marshalXML("5.67"))
	fmt.Println(marshalXML("-5.67"))
	fmt.Println(marshalXML("5.67e-5"))
	fmt.Println(marshalXML("5.67e5"))
}

func marshalXML(s string) (string, error) {
	d, err := decimal.Parse(s)
	if err != nil {
		return "", err
	}
	data, err := xml.Marshal(Transaction{Amount: d})
	if err != nil {
		return "", err
	}
	return string(data), nil
}
Output:

<Transaction><Amount>5.67</Amount></Transaction> <nil>
<Transaction><Amount>-5.67</Amount></Transaction> <nil>
<Transaction><Amount>0.0000567</Amount></Transaction> <nil>
<Transaction><Amount>567000</Amount></Transaction> <nil>
func (d Decimal) Max(e Decimal) Decimal

Max returns the larger decimal. See also method Decimal.CmpTotal.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("23")
	e := decimal.MustParse("-5.67")
	fmt.Println(d.Max(e))
}
Output:

23
func (d Decimal) Min(e Decimal) Decimal

Min returns the smaller decimal. See also method Decimal.CmpTotal.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("23")
	e := decimal.MustParse("-5.67")
	fmt.Println(d.Min(e))
}
Output:

-5.67
func (d Decimal) MinScale() int

MinScale returns the smallest scale that the decimal can be rescaled to without rounding. See also method Decimal.Trim.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("23.0000")
	e := decimal.MustParse("-5.6700")
	fmt.Println(d.MinScale())
	fmt.Println(e.MinScale())
}
Output:

0
2

Mul returns the (possibly rounded) product of decimals d and e.

Mul returns an overflow error if the integer part of the result has more than MaxPrec digits.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.7")
	e := decimal.MustParse("3")
	fmt.Println(d.Mul(e))
}
Output:

17.1 <nil>

MulExact is similar to Decimal.Mul, but it allows you to specify the number of digits after the decimal point that should be considered significant. If any of the significant digits are lost during rounding, the method will return an overflow error. This method is useful for financial calculations where the scale should be equal to or greater than the currency's scale.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.7")
	e := decimal.MustParse("3")
	fmt.Println(d.MulExact(e, 0))
	fmt.Println(d.MulExact(e, 1))
	fmt.Println(d.MulExact(e, 2))
	fmt.Println(d.MulExact(e, 3))
	fmt.Println(d.MulExact(e, 4))
}
Output:

17.1 <nil>
17.1 <nil>
17.10 <nil>
17.100 <nil>
17.1000 <nil>
func (d Decimal) Neg() Decimal

Neg returns a decimal with the opposite sign.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.67")
	fmt.Println(d.Neg())
}
Output:

-5.67
func (d Decimal) One() Decimal

One returns a decimal with a value of 1, having the same scale as decimal d. See also methods Decimal.Zero, Decimal.ULP.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5")
	e := decimal.MustParse("5.6")
	f := decimal.MustParse("5.67")
	fmt.Println(d.One())
	fmt.Println(e.One())
	fmt.Println(f.One())
}
Output:

1
1.0
1.00
func (d Decimal) Pad(scale int) Decimal

Pad returns a decimal zero-padded to the specified number of digits after the decimal point. The total number of digits in the result is limited by MaxPrec. See also method Decimal.Trim.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.67")
	fmt.Println(d.Pad(0))
	fmt.Println(d.Pad(1))
	fmt.Println(d.Pad(2))
	fmt.Println(d.Pad(3))
	fmt.Println(d.Pad(4))
}
Output:

5.67
5.67
5.67
5.670
5.6700

Pow returns the (possibly rounded) decimal raised to the given decimal power. If zero is raised to zero power then the result is one.

Pow returns an error if:

  • the integer part of the result has more than MaxPrec digits;
  • zero is raised to a negative power;
  • negative is raised to a fractional power.
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("4")
	e := decimal.MustParse("0.5")
	f := decimal.MustParse("-0.5")
	fmt.Println(d.Pow(e))
	fmt.Println(d.Pow(f))
}
Output:

2.000000000000000000 <nil>
0.5000000000000000000 <nil>

PowInt returns the (possibly rounded) decimal raised to the given integer power. If zero is raised to zero power then the result is one.

PowInt returns an error if:

  • the integer part of the result has more than MaxPrec digits;
  • zero is raised to a negative power.
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("2")
	fmt.Println(d.PowInt(-2))
	fmt.Println(d.PowInt(-1))
	fmt.Println(d.PowInt(0))
	fmt.Println(d.PowInt(1))
	fmt.Println(d.PowInt(2))
}
Output:

0.25 <nil>
0.5 <nil>
1 <nil>
2 <nil>
4 <nil>
func (d Decimal) Prec() int

Prec returns the number of digits in the coefficient. See also method Decimal.Coef.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-123")
	e := decimal.MustParse("5.7")
	f := decimal.MustParse("0.4")
	fmt.Println(d.Prec())
	fmt.Println(e.Prec())
	fmt.Println(f.Prec())
}
Output:

3
2
1
func (d Decimal) Quantize(e Decimal) Decimal

Quantize returns a decimal rescaled to the same scale as decimal e. The sign and the coefficient of decimal e are ignored. See also methods Decimal.SameScale and Decimal.Rescale.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.678")
	x := decimal.MustParse("1")
	y := decimal.MustParse("0.1")
	z := decimal.MustParse("0.01")
	fmt.Println(d.Quantize(x))
	fmt.Println(d.Quantize(y))
	fmt.Println(d.Quantize(z))
}
Output:

6
5.7
5.68

Quo returns the (possibly rounded) quotient of decimals d and e.

Quo returns an error if:

  • the divisor is 0;
  • the integer part of the result has more than MaxPrec digits.
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.67")
	e := decimal.MustParse("2")
	fmt.Println(d.Quo(e))
}
Output:

2.835 <nil>

QuoExact is similar to Decimal.Quo, but it allows you to specify the number of digits after the decimal point that should be considered significant. If any of the significant digits are lost during rounding, the method will return an error. This method is useful for financial calculations where the scale should be equal to or greater than the currency's scale.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.66")
	e := decimal.MustParse("2")
	fmt.Println(d.QuoExact(e, 0))
	fmt.Println(d.QuoExact(e, 1))
	fmt.Println(d.QuoExact(e, 2))
	fmt.Println(d.QuoExact(e, 3))
	fmt.Println(d.QuoExact(e, 4))
}
Output:

2.83 <nil>
2.83 <nil>
2.83 <nil>
2.830 <nil>
2.8300 <nil>
func (d Decimal) QuoRem(e Decimal) (q, r Decimal, err error)

QuoRem returns the quotient q and remainder r of decimals d and e such that d = e * q + r, where q is an integer and the sign of the reminder r is the same as the sign of the dividend d.

QuoRem returns an error if:

  • the divisor is 0;
  • the integer part of the quotient has more than MaxPrec digits.
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.67")
	e := decimal.MustParse("2")
	fmt.Println(d.QuoRem(e))
}
Output:

2 1.67 <nil>
func (d Decimal) Rescale(scale int) Decimal

Rescale returns a decimal rounded or zero-padded to the given number of digits after the decimal point. If the given scale is negative, it is redefined to zero. For financial calculations, the scale should be equal to or greater than the scale of the currency. See also methods Decimal.Round, Decimal.Pad.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.678")
	fmt.Println(d.Rescale(0))
	fmt.Println(d.Rescale(1))
	fmt.Println(d.Rescale(2))
	fmt.Println(d.Rescale(3))
	fmt.Println(d.Rescale(4))
}
Output:

6
5.7
5.68
5.678
5.6780
func (d Decimal) Round(scale int) Decimal

Round returns a decimal rounded to the specified number of digits after the decimal point using rounding half to even (banker's rounding). If the given scale is negative, it is redefined to zero. For financial calculations, the scale should be equal to or greater than the scale of the currency. See also method Decimal.Rescale.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.678")
	fmt.Println(d.Round(0))
	fmt.Println(d.Round(1))
	fmt.Println(d.Round(2))
	fmt.Println(d.Round(3))
	fmt.Println(d.Round(4))
}
Output:

6
5.7
5.68
5.678
5.678
func (d Decimal) SameScale(e Decimal) bool

SameScale returns true if decimals have the same scale. See also methods Decimal.Scale, Decimal.Quantize.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	a := decimal.MustParse("23")
	b := decimal.MustParse("5.67")
	c := decimal.MustParse("1.23")
	fmt.Println(a.SameScale(b))
	fmt.Println(b.SameScale(c))
}
Output:

false
true
func (d Decimal) Scale() int

Scale returns the number of digits after the decimal point. See also methods Decimal.Prec, Decimal.MinScale.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("23")
	e := decimal.MustParse("5.67")
	fmt.Println(d.Scale())
	fmt.Println(e.Scale())
}
Output:

0
2

Scan implements the sql.Scanner interface.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	var d decimal.Decimal
	_ = d.Scan("5.67")
	fmt.Println(d)
}
Output:

5.67
func (d Decimal) Sign() int

Sign returns:

-1 if d < 0
 0 if d = 0
+1 if d > 0

See also methods Decimal.IsPos, Decimal.IsNeg, Decimal.IsZero.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-5.67")
	e := decimal.MustParse("23")
	f := decimal.MustParse("0")
	fmt.Println(d.Sign())
	fmt.Println(e.Sign())
	fmt.Println(f.Sign())
}
Output:

-1
1
0

Sqrt computes the (possibly rounded) square root of a decimal. d.Sqrt() is significantly faster than d.Pow(0.5).

Sqrt returns an error if the decimal is negative.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("1")
	e := decimal.MustParse("2")
	f := decimal.MustParse("3")
	g := decimal.MustParse("4")
	fmt.Println(d.Sqrt())
	fmt.Println(e.Sqrt())
	fmt.Println(f.Sqrt())
	fmt.Println(g.Sqrt())
}
Output:

1 <nil>
1.414213562373095049 <nil>
1.732050807568877294 <nil>
2 <nil>

String implements the fmt.Stringer interface and returns a string representation of the decimal. The returned string does not use scientific or engineering notation and is formatted according to the following formal EBNF grammar:

sign           ::= '-'
digits         ::= { '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' }
significand    ::= digits '.' digits | digits
numeric-string ::= [sign] significand

See also method Decimal.Format.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("1234567890.123456789")
	fmt.Println(d.String())
}
Output:

1234567890.123456789

Sub returns the (possibly rounded) difference between decimals d and e.

Sub returns an error if the integer part of the result has more than MaxPrec digits.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-5.67")
	e := decimal.MustParse("8")
	fmt.Println(d.Sub(e))
	fmt.Println(e.Sub(d))
}
Output:

-13.67 <nil>
13.67 <nil>

SubAbs returns the (possibly rounded) absolute difference between decimals d and e.

SubAbs returns an error if the integer part of the result has more than MaxPrec digits.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("-5.67")
	e := decimal.MustParse("8")
	fmt.Println(d.SubAbs(e))
	fmt.Println(e.SubAbs(d))
}
Output:

13.67 <nil>
13.67 <nil>

SubExact is similar to Decimal.Sub, but it allows you to specify the number of digits after the decimal point that should be considered significant. If any of the significant digits are lost during rounding, the method will return an error. This method is useful for financial calculations where the scale should be equal to or greater than the currency's scale.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("8")
	e := decimal.MustParse("5.67")
	fmt.Println(d.SubExact(e, 0))
	fmt.Println(d.SubExact(e, 1))
	fmt.Println(d.SubExact(e, 2))
	fmt.Println(d.SubExact(e, 3))
	fmt.Println(d.SubExact(e, 4))
}
Output:

2.33 <nil>
2.33 <nil>
2.33 <nil>
2.330 <nil>
2.3300 <nil>

SubMul returns the (possibly rounded) fused multiply-subtraction of decimals d, e, and f. It computes d - e * f without any intermediate rounding. This method is useful for improving the accuracy and performance of algorithms that involve the accumulation of products, such as daily interest accrual.

SubMul returns an error if the integer part of the result has more than MaxPrec digits.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("2")
	e := decimal.MustParse("3")
	f := decimal.MustParse("4")
	fmt.Println(d.SubMul(e, f))
}
Output:

-10 <nil>

SubMulExact is similar to Decimal.SubMul, but it allows you to specify the number of digits after the decimal point that should be considered significant. If any of the significant digits are lost during rounding, the method will return an error. This method is useful for financial calculations where the scale should be equal to or greater than the currency's scale.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("2")
	e := decimal.MustParse("3")
	f := decimal.MustParse("4")
	fmt.Println(d.SubMulExact(e, f, 0))
	fmt.Println(d.SubMulExact(e, f, 1))
	fmt.Println(d.SubMulExact(e, f, 2))
	fmt.Println(d.SubMulExact(e, f, 3))
	fmt.Println(d.SubMulExact(e, f, 4))
}
Output:

-10 <nil>
-10.0 <nil>
-10.00 <nil>
-10.000 <nil>
-10.0000 <nil>

SubQuo returns the (possibly rounded) fused quotient-subtraction of decimals d, e, and f. It computes d - e / f with at least double precision during intermediate rounding. This method is useful for improving the accuracy and performance of algorithms that involve the accumulation of quotients, such as internal rate of return.

AddQuo returns an error if:

  • the divisor is 0;
  • the integer part of the result has more than MaxPrec digits.
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("2")
	e := decimal.MustParse("3")
	f := decimal.MustParse("4")
	fmt.Println(d.SubQuo(e, f))
}
Output:

1.25 <nil>

SubQuoExact is similar to Decimal.SubQuo, but it allows you to specify the number of digits after the decimal point that should be considered significant. If any of the significant digits are lost during rounding, the method will return an error. This method is useful for financial calculations where the scale should be equal to or greater than the currency's scale.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("2")
	e := decimal.MustParse("3")
	f := decimal.MustParse("4")
	fmt.Println(d.SubQuoExact(e, f, 0))
	fmt.Println(d.SubQuoExact(e, f, 1))
	fmt.Println(d.SubQuoExact(e, f, 2))
	fmt.Println(d.SubQuoExact(e, f, 3))
	fmt.Println(d.SubQuoExact(e, f, 4))
}
Output:

1.25 <nil>
1.25 <nil>
1.25 <nil>
1.250 <nil>
1.2500 <nil>
func (d Decimal) Trim(scale int) Decimal

Trim returns a decimal with trailing zeros removed up to the given number of digits after the decimal point. If the given scale is negative, it is redefined to zero. See also method Decimal.Pad.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("23.400")
	fmt.Println(d.Trim(0))
	fmt.Println(d.Trim(1))
	fmt.Println(d.Trim(2))
	fmt.Println(d.Trim(3))
	fmt.Println(d.Trim(4))
}
Output:

23.4
23.4
23.40
23.400
23.400
func (d Decimal) Trunc(scale int) Decimal

Trunc returns a decimal truncated to the specified number of digits after the decimal point using rounding toward zero. If the given scale is negative, it is redefined to zero. For financial calculations, the scale should be equal to or greater than the scale of the currency.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.678")
	fmt.Println(d.Trunc(0))
	fmt.Println(d.Trunc(1))
	fmt.Println(d.Trunc(2))
	fmt.Println(d.Trunc(3))
	fmt.Println(d.Trunc(4))
}
Output:

5
5.6
5.67
5.678
5.678
func (d Decimal) ULP() Decimal

ULP (Unit in the Last Place) returns the smallest representable positive difference between two decimals with the same scale as decimal d. It can be useful for implementing rounding and comparison algorithms. See also methods Decimal.Zero, Decimal.One.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5")
	e := decimal.MustParse("5.6")
	f := decimal.MustParse("5.67")
	fmt.Println(d.ULP())
	fmt.Println(e.ULP())
	fmt.Println(f.ULP())
}
Output:

1
0.1
0.01

UnmarshalBSONValue implements the v2/bson.ValueUnmarshaler interface. UnmarshalBSONValue supports the following types: Double, String, 32-bit Integer, 64-bit Integer, and Decimal128.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	data := []byte{
		0x37, 0x02, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x3c, 0x30,
	}

	var d decimal.Decimal
	err := d.UnmarshalBSONValue(19, data)
	fmt.Println(d, err)
}
Output:

5.67 <nil>

UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. UnmarshalBinary supports only numeric strings. See also constructor Parse.

package main

import (
	"bytes"
	"encoding/gob"
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	data := []byte{
		0x12, 0x7f, 0x06, 0x01,
		0x01, 0x07, 0x44, 0x65,
		0x63, 0x69, 0x6d, 0x61,
		0x6c, 0x01, 0xff, 0x80,
		0x00, 0x00, 0x00, 0x08,
		0xff, 0x80, 0x00, 0x04,
		0x35, 0x2e, 0x36, 0x37,
	}
	fmt.Println(unmarshalGOB(data))
}

func unmarshalGOB(data []byte) (decimal.Decimal, error) {
	var d decimal.Decimal
	dec := gob.NewDecoder(bytes.NewReader(data))
	err := dec.Decode(&d)
	if err != nil {
		return decimal.Decimal{}, err
	}
	return d, nil
}
Output:

5.67 <nil>

UnmarshalJSON implements the json.Unmarshaler interface. UnmarshalJSON supports the following types: number and numeric string. See also constructor Parse.

package main

import (
	"encoding/json"
	"fmt"

	"github.com/govalues/decimal"
)

type Account struct {
	Balance decimal.Decimal `json:"balance"`
}

func main() {
	fmt.Println(unmarshalJSON(`{"balance":"5.67"}`))
	fmt.Println(unmarshalJSON(`{"balance":"-5.67"}`))
	fmt.Println(unmarshalJSON(`{"balance":5.67e-5}`))
	fmt.Println(unmarshalJSON(`{"balance":5.67e5}`))
}

func unmarshalJSON(s string) (Account, error) {
	var a Account
	err := json.Unmarshal([]byte(s), &a)
	if err != nil {
		return Account{}, err
	}
	return a, nil
}
Output:

{5.67} <nil>
{-5.67} <nil>
{0.0000567} <nil>
{567000} <nil>

UnmarshalText implements the encoding.TextUnmarshaler interface. UnmarshalText supports only numeric strings. See also constructor Parse.

package main

import (
	"encoding/xml"
	"fmt"

	"github.com/govalues/decimal"
)

type Transaction struct {
	Amount decimal.Decimal `xml:"Amount"`
}

func main() {
	fmt.Println(unmarshalXML(`<Transaction><Amount>5.67</Amount></Transaction>`))
	fmt.Println(unmarshalXML(`<Transaction><Amount>-5.67</Amount></Transaction>`))
	fmt.Println(unmarshalXML(`<Transaction><Amount>5.67e-5</Amount></Transaction>`))
	fmt.Println(unmarshalXML(`<Transaction><Amount>5.67e5</Amount></Transaction>`))
}

func unmarshalXML(s string) (Transaction, error) {
	var t Transaction
	err := xml.Unmarshal([]byte(s), &t)
	return t, err
}
Output:

{5.67} <nil>
{-5.67} <nil>
{0.0000567} <nil>
{567000} <nil>

Value implements the driver.Valuer interface.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5.67")
	fmt.Println(d.Value())
}
Output:

5.67 <nil>
func (d Decimal) WithinOne() bool

WithinOne returns:

true  if -1 < d < 1
false otherwise
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("1")
	e := decimal.MustParse("0.9")
	f := decimal.MustParse("-0.9")
	g := decimal.MustParse("-1")
	fmt.Println(d.WithinOne())
	fmt.Println(e.WithinOne())
	fmt.Println(f.WithinOne())
	fmt.Println(g.WithinOne())
}
Output:

false
true
true
false
package main

import (
	"fmt"
	"slices"

	"github.com/govalues/decimal"
)

func main() {
	s := []decimal.Decimal{
		decimal.MustParse("-5.67"),
		decimal.MustParse("23"),
		decimal.MustParse("0.1"),
	}
	fmt.Println(slices.ContainsFunc(s, decimal.Decimal.WithinOne))
	fmt.Println(slices.IndexFunc(s, decimal.Decimal.WithinOne))
	fmt.Println(slices.DeleteFunc(s, decimal.Decimal.WithinOne))
}
Output:

true
2
[-5.67 23]
func (d Decimal) Zero() Decimal

Zero returns a decimal with a value of 0, having the same scale as decimal d. See also methods Decimal.One, Decimal.ULP.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("5")
	e := decimal.MustParse("5.6")
	f := decimal.MustParse("5.67")
	fmt.Println(d.Zero())
	fmt.Println(e.Zero())
	fmt.Println(f.Zero())
}
Output:

0
0.0
0.00
type NullDecimal struct {
	Decimal Decimal
	Valid   bool
}

NullDecimal represents a decimal that can be null. Its zero value is null. NullDecimal is not thread-safe.

MarshalBSONValue implements the v2/bson.ValueMarshaler interface. MarshalBSONValue returns Null or Decimal128. See also method Decimal.MarshalBSONValue.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	n := decimal.NullDecimal{
		Valid: false,
	}
	t, data, _ := n.MarshalBSONValue()
	fmt.Printf("%v [% x]\n", t, data)

	m := decimal.NullDecimal{
		Decimal: decimal.MustParse("5.67"),
		Valid:   true,
	}
	t, data, _ = m.MarshalBSONValue()
	fmt.Printf("%v [% x]\n", t, data)
}
Output:

10 []
19 [37 02 00 00 00 00 00 00 00 00 00 00 00 00 3c 30]

MarshalJSON implements the json.Marshaler interface. See also method Decimal.MarshalJSON.

package main

import (
	"encoding/json"
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	n := decimal.NullDecimal{
		Valid: false,
	}
	data, _ := json.Marshal(n)
	fmt.Println(string(data))

	m := decimal.NullDecimal{
		Decimal: decimal.MustParse("5.67"),
		Valid:   true,
	}
	data, _ = json.Marshal(m)
	fmt.Println(string(data))
}
Output:

null
"5.67"

Scan implements the sql.Scanner interface. See also method Decimal.Scan.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	var n decimal.NullDecimal
	_ = n.Scan(nil)
	fmt.Println(n)

	var m decimal.NullDecimal
	_ = m.Scan("5.67")
	fmt.Println(m)
}
Output:

{0 false}
{5.67 true}

UnmarshalBSONValue implements the v2/bson.ValueUnmarshaler interface. UnmarshalBSONValue supports the following types: Null, Double, String, 32-bit Integer, 64-bit Integer, and Decimal128. See also method Decimal.UnmarshalBSONValue.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	var n decimal.NullDecimal
	_ = n.UnmarshalBSONValue(10, nil)
	fmt.Println(n)

	data := []byte{
		0x37, 0x02, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x3c, 0x30,
	}
	var m decimal.NullDecimal
	_ = m.UnmarshalBSONValue(19, data)
	fmt.Println(m)
}
Output:

{0 false}
{5.67 true}

UnmarshalJSON implements the json.Unmarshaler interface. See also method Decimal.UnmarshalJSON.

package main

import (
	"encoding/json"
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	var n decimal.NullDecimal
	_ = json.Unmarshal([]byte(`null`), &n)
	fmt.Println(n)

	var m decimal.NullDecimal
	_ = json.Unmarshal([]byte(`"5.67"`), &m)
	fmt.Println(m)
}
Output:

{0 false}
{5.67 true}

Value implements the driver.Valuer interface. See also method Decimal.Value.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	n := decimal.NullDecimal{
		Valid: false,
	}
	fmt.Println(n.Value())

	m := decimal.NullDecimal{
		Decimal: decimal.MustParse("5.67"),
		Valid:   true,
	}
	fmt.Println(m.Value())
}
Output:

<nil> <nil>
5.67 <nil>