decimal

package module
v0.1.35 Latest Latest
Warning

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

Go to latest
Published: Jan 11, 2025 License: MIT Imports: 7 Imported by: 41

README

decimal

githubb codecovb goreportb godocb licenseb versionb awesomeb

Package decimal implements immutable decimal floating-point numbers for Go. This package is designed specifically for use in transactional financial systems.

Key Features

  • Immutability - Once set, a decimal remains constant, ensuring safe concurrent access across goroutines.
  • Banker's Rounding - Uses half-to-even rounding, also known as "banker's rounding", to minimize cumulative rounding errors commonly seen in financial calculations.
  • Accurate Arithmetic - For all methods, the result is the one that would be obtained if the true mathematical value were rounded to 19 digits of precision using the half-to-even rounding.
  • No Panics - All methods are panic-free, returning errors instead of crashing your application in cases such as overflow or division by zero.
  • No Heap Allocations - Optimized to avoid heap allocations, reducing garbage collector impact during arithmetic operations.
  • Simple String Representation - Decimals are represented in a straightforward format avoiding the complexities of scientific or engineering notations.
  • Rigorous Testing - All methods are cross-validated against the cockroachdb/apd and shopspring/decimal packages through extensive fuzz testing.

Getting Started

Installation

To add the decimal package to your Go workspace:

go get github.com/govalues/decimal
Basic Usage

Create decimal values using one of the constructors. After creating a decimal, you can perform various operations as shown below:

package main

import (
    "fmt"
    "github.com/govalues/decimal"
)

func main() {
    // Constructors
    d, _ := decimal.New(8, 0)               // d = 8
    e, _ := decimal.Parse("12.5")           // e = 12.5
    f, _ := decimal.NewFromFloat64(2.567)   // f = 2.567
    g, _ := decimal.NewFromInt64(7, 896, 3) // g = 7.896

    // Arithmetic operations
    fmt.Println(d.Add(e))              // 8 + 12.5
    fmt.Println(d.Sub(e))              // 8 - 12.5
    fmt.Println(d.SubAbs(e))           // abs(8 - 12.5)

    fmt.Println(d.Mul(e))              // 8 * 12.5
    fmt.Println(d.AddMul(e, f))        // 8 + 12.5 * 2.567
    fmt.Println(d.SubMul(e, f))        // 8 - 12.5 * 2.567
    fmt.Println(d.PowInt(2))           // 8²

    fmt.Println(d.Quo(e))              // 8 / 12.5
    fmt.Println(d.AddQuo(e, f))        // 8 + 12.5 / 2.567
    fmt.Println(d.SubQuo(e, f))        // 8 - 12.5 / 2.567
    fmt.Println(d.QuoRem(e))           // 8 div 12.5, 8 mod 12.5
    fmt.Println(d.Inv())               // 1 / 8

    fmt.Println(decimal.Sum(d, e, f))  // 8 + 12.5 + 2.567
    fmt.Println(decimal.Mean(d, e, f)) // (8 + 12.5 + 2.567) / 3
    fmt.Println(decimal.Prod(d, e, f)) // 8 * 12.5 * 2.567

    // Transcendental functions
    fmt.Println(e.Sqrt())              // √12.5
    fmt.Println(e.Exp())               // exp(12.5)
    fmt.Println(e.Log())               // ln(12.5)
    fmt.Println(e.Log2())              // log₂(12.5)
    fmt.Println(e.Log10())             // log₁₀(12.5)
    fmt.Println(e.Pow(d))              // 12.5⁸

    // Rounding to 2 decimal places
    fmt.Println(g.Round(2))            // 7.90
    fmt.Println(g.Ceil(2))             // 7.90
    fmt.Println(g.Floor(2))            // 7.89
    fmt.Println(g.Trunc(2))            // 7.89

    // Conversions
    fmt.Println(f.Int64(9))            // 2 567000000
    fmt.Println(f.Float64())           // 2.567
    fmt.Println(f.String())            // 2.567

    // Formatting
    fmt.Printf("%.2f", f)              // 2.57
    fmt.Printf("%.2k", f)              // 256.70%
}

Documentation

For detailed documentation and additional examples, visit the package documentation. For examples related to financial calculations, see the money package documentation.

Comparison

Comparison with other popular packages:

Feature govalues cockroachdb/apd v3.2.1 shopspring/decimal v1.4.0
Speed High Medium Low[^reason]
Mutability Immutable Mutable[^reason] Immutable
Heap Allocations No Medium High
Panic Free Yes Yes No[^divzero]
Precision 19 digits Arbitrary Arbitrary
Correctly Rounded Yes No No
Mathematical Context Implicit Explicit Implicit

[^reason]: decimal package was created simply because shopspring/decimal was too slow and cockroachdb/apd was mutable.

[^divzero]: shopspring/decimal panics on division by zero.

Benchmarks
goos: linux
goarch: amd64
pkg: github.com/govalues/decimal-tests
cpu: AMD Ryzen 7 3700C  with Radeon Vega Mobile Gfx 
Test Case Expression govalues cockroachdb/apd v3.2.1 shopspring/decimal v1.4.0 govalues vs cockroachdb govalues vs shopspring
Add 5 + 6 16.06n 74.88n 140.90n +366.22% +777.33%
Mul 2 * 3 16.93n 62.20n 146.00n +267.40% +762.37%
Quo 2 / 4 (exact) 59.52n 176.95n 657.40n +197.30% +1004.50%
Quo 2 / 3 (inexact) 391.60n 976.80n 2962.50n +149.39% +656.42%
PowInt 1.1^60 950.90n 3302.50n 4599.50n +247.32% +383.73%
PowInt 1.01^600 3.45µ 10.67µ 18.67µ +209.04% +440.89%
PowInt 1.001^6000 5.94µ 20.50µ 722.22µ +244.88% +12052.44%
Sqrt √2 3.40µ 4.96µ 2101.86µ +46.00% +61755.71%
Exp exp(0.5) 8.35µ 39.28µ 20.06µ +370.58% +140.32%
Log ln(0.5) 54.89µ 129.01µ 151.55µ +135.03% +176.10%
Parse 1 16.52n 76.30n 136.55n +362.00% +726.82%
Parse 123.456 47.37n 176.90n 242.60n +273.44% +412.14%
Parse 123456789.1234567890 85.49n 224.15n 497.95n +162.19% +482.47%
String 1 5.11n 19.57n 198.25n +283.21% +3783.07%
String 123.456 35.78n 77.12n 228.85n +115.52% +539.51%
String 123456789.1234567890 70.72n 239.10n 337.25n +238.12% +376.91%
Telco (see specification) 137.00n 969.40n 3981.00n +607.33% +2804.78%

The benchmark results shown in the table are provided for informational purposes only and may vary depending on your specific use case.

Documentation

Overview

Package decimal implements immutable decimal floating-point numbers. 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:

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.

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.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 encoding.TextMarshaller and encoding.TextUnmarshaler 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/v2/bson via the implementation of bson.ValueMarshaler and bson.ValueUnmarshaler interfaces. 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.

Example (FloatInaccuracy)

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
Example (PiApproximation)

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
Example (PostfixCalculator)

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>

Index

Examples

Constants

View Source
const (
	MaxPrec  = 19 // MaxPrec is the maximum length of the coefficient in decimal digits.
	MinScale = 0  // MinScale is the minimum number of digits after the decimal point.
	MaxScale = 19 // MaxScale is the maximum number of digits after the decimal point.

)

Variables

View Source
var (
	NegOne   = MustNew(-1, 0)                         // NegOne represents the decimal value of -1.
	Zero     = MustNew(0, 0)                          // Zero represents the decimal value of 0. For comparison purposes, use the IsZero method.
	One      = MustNew(1, 0)                          // One represents the decimal value of 1.
	Two      = MustNew(2, 0)                          // Two represents the decimal value of 2.
	Ten      = MustNew(10, 0)                         // Ten represents the decimal value of 10.
	Hundred  = MustNew(100, 0)                        // Hundred represents the decimal value of 100.
	Thousand = MustNew(1_000, 0)                      // Thousand represents the decimal value of 1,000.
	E        = MustNew(2_718_281_828_459_045_235, 18) // E represents Euler’s number rounded to 18 digits.
	Pi       = MustNew(3_141_592_653_589_793_238, 18) // Pi represents the value of π rounded to 18 digits.

)

Functions

This section is empty.

Types

type Decimal

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

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.

func Mean added in v0.1.34

func Mean(d ...Decimal) (Decimal, error)

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.
Example
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>

func MustNew added in v0.1.0

func MustNew(value int64, scale int) Decimal

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

Example
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

func MustParse

func MustParse(s string) Decimal

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

Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

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

-1.23

func New

func New(value int64, scale int) (Decimal, error)

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.

Example
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>

func NewFromFloat64 added in v0.1.5

func NewFromFloat64(f float64) (Decimal, error)

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.
Example
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>

func NewFromInt64 added in v0.1.4

func NewFromInt64(whole, frac int64, scale int) (Decimal, error)

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).
Example
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>

func Parse

func Parse(s string) (Decimal, error)

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.
Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

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

5.67 <nil>

func ParseExact

func ParseExact(s string, scale int) (Decimal, error)

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.

Example
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>

func Prod added in v0.1.33

func Prod(d ...Decimal) (Decimal, error)

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.
Example
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>

func Sum added in v0.1.33

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

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.
Example
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 (Decimal) Abs

func (d Decimal) Abs() Decimal

Abs returns the absolute value of the decimal.

Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

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

5.67

func (Decimal) Add

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

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.

Example
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>

func (Decimal) AddExact

func (d Decimal) AddExact(e Decimal, scale int) (Decimal, error)

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.

Example
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>

func (Decimal) AddMul added in v0.1.30

func (d Decimal) AddMul(e, f Decimal) (Decimal, error)

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.

Example
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>

func (Decimal) AddMulExact added in v0.1.30

func (d Decimal) AddMulExact(e, f Decimal, scale int) (Decimal, error)

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.

Example
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>

func (Decimal) AddQuo added in v0.1.30

func (d Decimal) AddQuo(e, f Decimal) (Decimal, error)

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.
Example
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>

func (Decimal) AddQuoExact added in v0.1.30

func (d Decimal) AddQuoExact(e, f Decimal, scale int) (Decimal, error)

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.

Example
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>

func (Decimal) Ceil

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.

Example
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 (Decimal) Clamp added in v0.1.11

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.

Example
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>

func (Decimal) Cmp

func (d Decimal) Cmp(e Decimal) int

Cmp compares decimals and returns:

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

See also methods Decimal.CmpAbs, Decimal.CmpTotal.

Example
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
Example (Slices)
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 (Decimal) CmpAbs added in v0.1.10

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.

Example
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
Example (Slices)
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 (Decimal) CmpTotal

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.

Example
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
Example (Slices)
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

func (Decimal) Coef

func (d Decimal) Coef() uint64

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

Example
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 (Decimal) CopySign added in v0.0.7

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.

Example
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

func (Decimal) Equal added in v0.1.31

func (d Decimal) Equal(e Decimal) bool

Equal compares decimals and returns:

 true if d = e
false otherwise

See also method Decimal.Cmp.

Example
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
Example (Slices)
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]

func (Decimal) Exp added in v0.1.30

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

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.

Example
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>

func (Decimal) Float64 added in v0.0.11

func (d Decimal) Float64() (f float64, ok bool)

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.

Example
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 (Decimal) Floor

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.

Example
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

func (Decimal) Format

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

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.

Example
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%

func (Decimal) Int64 added in v0.0.11

func (d Decimal) Int64(scale int) (whole, frac int64, ok bool)

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.

Example
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

func (Decimal) Inv added in v0.1.10

func (d Decimal) Inv() (Decimal, error)

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.
Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

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

0.5 <nil>

func (Decimal) IsInt

func (d Decimal) IsInt() bool

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

Example
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
Example (Slices)
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]

func (Decimal) IsNeg

func (d Decimal) IsNeg() bool

IsNeg returns:

true  if d < 0
false otherwise
Example
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
Example (Slices)
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]

func (Decimal) IsOne

func (d Decimal) IsOne() bool

IsOne returns:

true  if d = -1 or d = 1
false otherwise
Example
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
Example (Slices)
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]

func (Decimal) IsPos

func (d Decimal) IsPos() bool

IsPos returns:

true  if d > 0
false otherwise
Example
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
Example (Slices)
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]

func (Decimal) IsZero

func (d Decimal) IsZero() bool

IsZero returns:

true  if d = 0
false otherwise
Example
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
Example (Slices)
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]

func (Decimal) Less added in v0.1.31

func (d Decimal) Less(e Decimal) bool

Less compares decimals and returns:

 true if d < e
false otherwise

See also method Decimal.Cmp.

Example
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

func (Decimal) Log added in v0.1.32

func (d Decimal) Log() (Decimal, error)

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

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

Example
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>

func (Decimal) Log10 added in v0.1.34

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

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

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

Example
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>

func (Decimal) Log2 added in v0.1.34

func (d Decimal) Log2() (Decimal, error)

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

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

Example
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>

func (Decimal) MarshalBSONValue added in v0.1.35

func (d Decimal) MarshalBSONValue() (typ byte, data []byte, err error)

MarshalBSONValue implements the v2 bson.ValueMarshaler interface. MarshalBSONValue always returns decimal128.

Example (Bson)
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>

func (Decimal) MarshalBinary added in v0.1.25

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

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

Example (Gob)
package main

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

	"github.com/govalues/decimal"
)

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
}

func main() {
	data, err := marshalGOB("5.67")
	fmt.Printf("[% x] %v\n", data, err)
}
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>

func (Decimal) MarshalJSON added in v0.1.35

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

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

Example (Json)
package main

import (
	"encoding/json"
	"fmt"

	"github.com/govalues/decimal"
)

type Object struct {
	Number decimal.Decimal `json:"number"`
}

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

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

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

func (Decimal) MarshalText

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

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

Example (Xml)
package main

import (
	"encoding/xml"
	"fmt"

	"github.com/govalues/decimal"
)

type Entity struct {
	Number decimal.Decimal `xml:"Number"`
}

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

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

<Entity><Number>5.67</Number></Entity> <nil>
<Entity><Number>-5.67</Number></Entity> <nil>
<Entity><Number>0.0000567</Number></Entity> <nil>
<Entity><Number>567000</Number></Entity> <nil>

func (Decimal) Max

func (d Decimal) Max(e Decimal) Decimal

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

Example
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 (Decimal) Min

func (d Decimal) Min(e Decimal) Decimal

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

Example
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 (Decimal) MinScale

func (d Decimal) MinScale() int

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

Example
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

func (Decimal) Mul

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

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.

Example
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>

func (Decimal) MulExact

func (d Decimal) MulExact(e Decimal, scale int) (Decimal, error)

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.

Example
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 (Decimal) Neg

func (d Decimal) Neg() Decimal

Neg returns a decimal with the opposite sign.

Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

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

-5.67

func (Decimal) One added in v0.0.9

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.

Example
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 (Decimal) Pad added in v0.1.0

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.

Example
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

func (Decimal) Pow

func (d Decimal) Pow(e Decimal) (Decimal, error)

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.
Example
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>

func (Decimal) PowInt added in v0.1.32

func (d Decimal) PowInt(power int) (Decimal, error)

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.
Example
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 (Decimal) Prec

func (d Decimal) Prec() int

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

Example
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 (Decimal) Quantize

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.

Example
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

func (Decimal) Quo

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

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.
Example
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>

func (Decimal) QuoExact

func (d Decimal) QuoExact(e Decimal, scale int) (Decimal, error)

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.

Example
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 (Decimal) QuoRem

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.
Example
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 (Decimal) Rescale added in v0.1.0

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.

Example
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 (Decimal) Round

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.

Example
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 (Decimal) SameScale added in v0.1.17

func (d Decimal) SameScale(e Decimal) bool

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

Example
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 (Decimal) Scale

func (d Decimal) Scale() int

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

Example
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

func (*Decimal) Scan added in v0.1.6

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

Scan implements the sql.Scanner interface.

Example
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 (Decimal) Sign

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.

Example
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

func (Decimal) Sqrt added in v0.1.28

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

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.

Example
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>

func (Decimal) String

func (d Decimal) String() string

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.

Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

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

1234567890.123456789

func (Decimal) Sub

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

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.

Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

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

-13.67 <nil>

func (Decimal) SubAbs added in v0.1.10

func (d Decimal) SubAbs(e Decimal) (Decimal, error)

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.

Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

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

13.67 <nil>

func (Decimal) SubExact

func (d Decimal) SubExact(e Decimal, scale int) (Decimal, error)

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.

Example
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>

func (Decimal) SubMul added in v0.1.31

func (d Decimal) SubMul(e, f Decimal) (Decimal, error)

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.

Example
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>

func (Decimal) SubMulExact added in v0.1.31

func (d Decimal) SubMulExact(e, f Decimal, scale int) (Decimal, error)

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.

Example
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>

func (Decimal) SubQuo added in v0.1.31

func (d Decimal) SubQuo(e, f Decimal) (Decimal, error)

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.
Example
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>

func (Decimal) SubQuoExact added in v0.1.31

func (d Decimal) SubQuoExact(e, f Decimal, scale int) (Decimal, error)

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.

Example
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 (Decimal) Trim added in v0.1.0

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.

Example
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 (Decimal) Trunc

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.

Example
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 (Decimal) ULP added in v0.0.6

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.

Example
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

func (*Decimal) UnmarshalBSONValue added in v0.1.35

func (d *Decimal) UnmarshalBSONValue(typ byte, data []byte) error

UnmarshalBSONValue implements the v2 bson.ValueUnmarshaler interface. UnmarshalBSONValue supports the following BSON types: double, string, int32, int64, and decimal128.

Example (Bson)
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>

func (*Decimal) UnmarshalBinary added in v0.1.25

func (d *Decimal) UnmarshalBinary(data []byte) error

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

Example (Gob)
package main

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

	"github.com/govalues/decimal"
)

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
}

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))
}
Output:

5.67 <nil>

func (*Decimal) UnmarshalJSON added in v0.1.35

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

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

Example (Json)
package main

import (
	"encoding/json"
	"fmt"

	"github.com/govalues/decimal"
)

type Object struct {
	Number decimal.Decimal `json:"number"`
}

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

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

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

func (*Decimal) UnmarshalText

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

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

Example (Xml)
package main

import (
	"encoding/xml"
	"fmt"

	"github.com/govalues/decimal"
)

type Entity struct {
	Number decimal.Decimal `xml:"Number"`
}

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

func main() {
	fmt.Println(unmarshalXML(`<Entity><Number>5.67</Number></Entity>`))
	fmt.Println(unmarshalXML(`<Entity><Number>-5.67</Number></Entity>`))
	fmt.Println(unmarshalXML(`<Entity><Number>5.67e-5</Number></Entity>`))
	fmt.Println(unmarshalXML(`<Entity><Number>5.67e5</Number></Entity>`))
}
Output:

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

func (Decimal) Value added in v0.1.6

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

Value implements the driver.Valuer interface.

Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

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

5.67 <nil>

func (Decimal) WithinOne added in v0.0.9

func (d Decimal) WithinOne() bool

WithinOne returns:

true  if -1 < d < 1
false otherwise
Example
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
Example (Slices)
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 (Decimal) Zero added in v0.0.9

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.

Example
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 added in v0.1.13

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.

func (NullDecimal) MarshalBSONValue added in v0.1.35

func (n NullDecimal) MarshalBSONValue() (typ byte, data []byte, err error)

MarshalBSONValue implements the v2 bson.ValueMarshaler interface. MarshalBSONValue always returns the following BSON types: decimal128 or null. See also method Decimal.MarshalBSONValue.

Example (Bson)
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]

func (NullDecimal) MarshalJSON added in v0.1.35

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

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

Example (Json)
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"

func (*NullDecimal) Scan added in v0.1.13

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

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

Example
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}

func (*NullDecimal) UnmarshalBSONValue added in v0.1.35

func (n *NullDecimal) UnmarshalBSONValue(typ byte, data []byte) error

UnmarshalBSONValue implements the v2 bson.ValueUnmarshaler interface. UnmarshalBSONValue supports the following BSON types: double, string, null, int32, int64, and decimal128. See also method Decimal.UnmarshalBSONValue.

Example (Bson)
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}

func (*NullDecimal) UnmarshalJSON added in v0.1.35

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

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

Example (Json)
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}

func (NullDecimal) Value added in v0.1.13

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

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

Example
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>

Jump to

Keyboard shortcuts

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