decimal

package module
v0.1.23 Latest Latest
Warning

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

Go to latest
Published: Mar 4, 2024 License: MIT Imports: 7 Imported by: 2

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.

Features

  • Immutability - Once a decimal is set, it remains unchanged. This immutability ensures safe concurrent access across goroutines.
  • Banker's Rounding - Methods use half-to-even rounding, also known as "banker's rounding", which minimizes cumulative rounding errors commonly seen in financial calculations.
  • No Panics - All methods are designed to be panic-free. Instead of potentially crashing your application, they return errors for issues such as overflow or division by zero.
  • Zero Heap Allocation - Methods are optimized to avoid heap allocations, reducing the impact on the garbage collector during arithmetic operations.
  • Simple String Representation - Decimals are represented in a strightforward format avoiding the complexities of scientific or engineering notations.
  • Correctness - Fuzz testing is used to cross-validate arithmetic operations against the cockroachdb/apd and shopspring/decimal packages.

Getting Started

Installation

To add the decimal package to your Go workspace:

go get github.com/govalues/decimal
Usage

Create decimal values using one of the constructors. After creating a decimal value, various operations can be performed:

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

    // Operations
    fmt.Println(d.Add(e))          // 8 + 12.5
    fmt.Println(d.Sub(e))          // 8 - 12.5

    fmt.Println(d.Mul(e))          // 8 * 12.5
    fmt.Println(d.FMA(e, f))       // 8 * 12.5 + 2.567
    fmt.Println(d.Pow(2))          // 8 ^ 2

    fmt.Println(d.Quo(e))          // 8 ÷ 12.5
    fmt.Println(d.QuoRem(e))       // 8 div 12.5, 8 mod 12.5
    fmt.Println(d.Inv())           // 1 ÷ 8

    // 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\n", f)        // 2.57
    fmt.Printf("%.2k\n", 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.3.1
Speed High Medium Low[^reason]
Mutability Immutable Mutable[^reason] Immutable
Memory Footprint Low Medium High
Panic Free Yes Yes No[^divzero]
Precision 19 digits Arbitrary Arbitrary
Default Rounding Half to even Half up Half away from 0
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.3.1 govalues vs cockroachdb govalues vs shopspring
Add 5 + 6 16.89n 80.96n 140.50n +379.48% +732.10%
Mul 2 * 3 16.85n 58.14n 145.30n +245.15% +762.57%
QuoExact 2 ÷ 4 66.00n 193.25n 619.15n +192.78% +838.03%
QuoInfinite 2 ÷ 3 453.30n 961.00n 2767.00n +112.01% +510.41%
Pow 1.1^60 1.04µ 3.42µ 15.76µ +227.72% +1408.43%
Pow 1.01^600 3.57µ 10.70µ 35.70µ +200.11% +901.23%
Pow 1.001^6000 6.19µ 20.72µ 634.41µ +234.65% +10148.95%
Parse 1 16.98n 80.98n 132.40n +376.91% +679.74%
Parse 123.456 50.80n 195.05n 246.10n +283.92% +384.40%
Parse 123456789.1234567890 96.36n 239.60n 516.20n +148.64% +435.67%
String 1 5.70n 20.89n 203.25n +266.24% +3464.23%
String 123.456 42.74n 75.71n 235.65n +77.14% +451.36%
String 123456789.1234567890 72.34n 215.90n 331.20n +198.47% +357.87%
Telco see specification 148.00n 1075.00n 4010.50n +626.35% +2609.80%

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

Contributing

Interested in contributing? Here's how to get started:

  1. Fork and clone the repository.
  2. Implement your changes.
  3. Write tests to cover your changes.
  4. Ensure all tests pass with go test.
  5. Commit and push to your fork.
  6. Open a pull request detailing your changes.

Note: If you're considering significant changes, please open an issue first to discuss with the maintainers. This ensures alignment with the project's objectives and roadmap.

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.

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

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.

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 increased 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 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:

Context

Unlike many other decimal libraries, this package does not provide an explicit 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

Implicit rounding is applied when a result exceeds 19 digits, rounding it to 19 digits using half-to-even rounding. This method ensures that rounding errors are evenly distributed between rounding up and down.

For all arithmetic operations, except for Decimal.Pow and Decimal.PowExact, the result is the one that would be obtained by computing the exact mathematical result with infinite precision and then rounding it to 19 digits. Decimal.Pow and Decimal.PowExact may occasionally produce a result that is off by 1 unit in the last place.

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

See the documentation for each method for more details.

Errors

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

  • Division by Zero. Unlike the standard library, Decimal.Quo, Decimal.QuoRem, and Decimal.Inv do not panic when dividing by 0. Instead, they return an error.

  • Invalid Operation. Decimal.Pow and Decimal.PowExact return an error if 0 is raised to a negative power.

  • Overflow. Unlike standard integers, there is no "wrap around" for decimals at certain sizes. For out-of-range values, arithmetic operations return an error.

Errors are not returned in the following cases:

  • Underflow. Arithmetic operations do not return an error in case of decimal underflow. If the result is a decimal between -0.00000000000000000005 and 0.00000000000000000005 inclusive, it will be rounded to 0.

Conversions

JSON.

The package integrates seamlessly with standard encoding/json through the implementation of encoding.TextMarshaller and encoding.TextUnmarshaler interfaces. Here is an example structure:

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

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

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

XML.

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

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

"xs:decimal" type can be used to 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>

Protocol Buffers.

Protocol Buffers can represent decimals as numerical strings, preserving trailing zeros. To convert between numerical strings and decimals, use Parse and Decimal.String. Here is an example proto definition:

message Decimal {
  string value = 1;
}

Alternatively, decimals can be represented as two integers: one for the integer part and another for the fractional part. For conversion between this format and decimals, use NewFromInt64 and Decimal.Int64 with a scale argument equal to "9". Here is an example proto definition:

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

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

Here are the reasons:

  • For PostgreSQL, always use DECIMAL without precision or scale specifications (avoid DECIMAL(p) or DECIMAL(p, s)). DECIMAL accurately preserves the scale of decimals.

  • In SQLite, prefer TEXT, since DECIMAL is just an alias for floating-point numbers. TEXT preserves the scale of decimals.

  • In MySQL, use DECIMAL(19, d), as DECIMAL is just an alias for DECIMAL(10, 0). The disadvantage of this format is that MySQL automatically rescales all decimals: values with a scale exceeding "d" are rounded (using half away from zero), while those with a lower scale are padded with trailing zeros. To avoid automatic rescaling, consider using VARCHAR(22).

Example (FloatInaccuracy)

This example demonstrates the advantage of decimals for financial calculations. It computes the sum 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1. In decimal arithmetic, the result is exactly 1.0. In float64 arithmetic, the result slightly deviates from 1.0 due to binary floating-point representation.

package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	d := decimal.MustParse("0.0")
	e := decimal.MustParse("0.1")
	for i := 0; i < 10; i++ {
		d, _ = d.Add(e)
	}
	fmt.Println(d)

	f := 0.0
	for i := 0; i < 10; i++ {
		f += 0.1
	}
	fmt.Println(f)
}
Output:

1.0
0.9999999999999999
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 approximate(terms int) (decimal.Decimal, error) {
	pi := decimal.Zero
	denominator := decimal.One
	increment := decimal.Two
	multiplier := decimal.MustParse("4")

	for i := 0; i < terms; i++ {
		term, err := multiplier.Quo(denominator)
		if err != nil {
			return decimal.Decimal{}, err
		}
		pi, err = pi.Add(term)
		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
}

func main() {
	pi, err := approximate(500000)
	if err != nil {
		panic(err)
	}
	fmt.Println(pi)
	fmt.Println(decimal.Pi)
}
Output:

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

func main() {
	d, err := evaluate("1.23 4.56 + 10 *")
	if err != nil {
		panic(err)
	}
	fmt.Println(d)
}
Output:

57.90

Index

Examples

Constants

View Source
const (
	MaxPrec  = 19 // MaxPrec is a maximum length of the coefficient in decimal digits.
	MinScale = 0  // MinScale is a minimum number of digits after the decimal point.
	MaxScale = 19 // MaxScale is a 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.
	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 MustNew added in v0.1.0

func MustNew(coef 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(coef int64, scale int) (Decimal, error)

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

New returns an error if 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 (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) 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

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

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

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) FMA added in v0.0.3

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

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

FMA 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("2")
	e := decimal.MustParse("3")
	f := decimal.MustParse("4")
	fmt.Println(d.FMA(e, f))
}
Output:

10 <nil>

func (Decimal) FMAExact added in v0.0.3

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

FMAExact is similar to Decimal.FMA, 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.FMAExact(e, f, 0))
	fmt.Println(d.FMAExact(e, f, 1))
	fmt.Println(d.FMAExact(e, f, 2))
	fmt.Println(d.FMAExact(e, f, 3))
	fmt.Println(d.FMAExact(e, f, 4))
}
Output:

10 <nil>
10.0 <nil>
10.00 <nil>
10.000 <nil>
10.0000 <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

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

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

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

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

func (Decimal) MarshalText

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

MarshalText implements the encoding.TextMarshaler interface. 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
	}
	v := Object{Number: d}
	b, err := json.Marshal(v)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

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

{"number":"5.67"} <nil>
{"number":"-5.67"} <nil>
{"number":"0.0000567"} <nil>
{"number":"567000"} <nil>
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
	}
	v := Entity{Number: d}
	b, err := xml.Marshal(v)
	if err != nil {
		return "", err
	}
	return string(b), 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, error)

Pad returns a decimal zero-padded to the specified number of digits after the decimal point. See also method Decimal.Trim.

Pad returns an error if the integer part of the result has more than (MaxPrec - scale) digits.

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 <nil>
5.67 <nil>
5.67 <nil>
5.670 <nil>
5.6700 <nil>

func (Decimal) Pow

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

Pow returns the (possibly rounded) decimal raised to the given power.

Pow 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.Pow(-2))
	fmt.Println(d.Pow(-1))
	fmt.Println(d.Pow(0))
	fmt.Println(d.Pow(1))
	fmt.Println(d.Pow(2))
}
Output:

0.25 <nil>
0.5 <nil>
1 <nil>
2 <nil>
4 <nil>

func (Decimal) PowExact added in v0.1.0

func (d Decimal) PowExact(power, scale int) (Decimal, error)

PowExact is similar to Decimal.Pow, 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("2")
	fmt.Println(d.PowExact(3, 0))
	fmt.Println(d.PowExact(3, 1))
	fmt.Println(d.PowExact(3, 2))
	fmt.Println(d.PowExact(3, 3))
	fmt.Println(d.PowExact(3, 4))
}
Output:

8 <nil>
8.0 <nil>
8.00 <nil>
8.000 <nil>
8.0000 <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, error)

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.Scale, Decimal.SameScale, Decimal.Rescale.

Qunatize returns an overflow error if the integer part of result has more than (MaxPrec - e.Scale()) digits.

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 <nil>
5.7 <nil>
5.68 <nil>

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, error)

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

Rescale returns an overflow error if the integer part of the result has more than (MaxPrec - scale) digits.

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 <nil>
5.7 <nil>
5.68 <nil>
5.678 <nil>
5.6780 <nil>

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. See also constructor Parse.

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
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) 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) 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) UnmarshalText

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

UnmarshalText implements the encoding.TextUnmarshaler interface. 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 v Object
	err := json.Unmarshal([]byte(s), &v)
	return v, err
}

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>
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 v Entity
	err := xml.Unmarshal([]byte(s), &v)
	return v, 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. See also method Decimal.String.

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

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

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

Scan implements the sql.Scanner interface. See also constructor Parse.

Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

func main() {
	var n, m decimal.NullDecimal
	_ = n.Scan("5.67")
	_ = m.Scan(nil)
	fmt.Println(n)
	fmt.Println(m)
}
Output:

{5.67 true}
{0 false}

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

Example
package main

import (
	"fmt"

	"github.com/govalues/decimal"
)

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

5.67 <nil>
<nil> <nil>

Jump to

Keyboard shortcuts

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