decimal

package module
v0.0.6 Latest Latest
Warning

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

Go to latest
Published: Mar 21, 2023 License: MIT Imports: 3 Imported by: 2

README

godocb versionb goreportb githubb codecovb licenseb

Decimal

Package decimal implements immutable decimal floating-point numbers for Go.

Getting started

To install the decimal package into your Go workspace, you can use the go get command:

go get github.com/govalues/decimal

To use the decimal package in your Go project, you can import it as follows:

import "github.com/govalues/decimal"

Using Decimal

To create a new Decimal value, you can use one of the provided constructors, such as New, Parse or MustParse.

x := decimal.New(12345, 2) // x = 123,45
y := decimal.MustParse("123.45")

Once you have a Decimal value, you can perform arithmetic operations such as addition, subtraction, multiplication, division, and exponentiation, as well as rounding operations such as ceiling, floor, truncation, and rounding.

sum := x.Add(y)
difference := x.Sub(y)
product := x.Mul(y)
quotient := x.Quo(y)
power := x.Pow(5)
ceil := x.Ceil(0)
floor := x.Floor(0)
trunc := x.Trunc(0)
rounded := x.Round(0)

For more details on these and other methods, see the package documentation at pkg.go.dev.

Benchmarks

goos: linux
goarch: amd64
pkg: github.com/govalues/benchmarks
cpu: AMD Ryzen 7 3700C  with Radeon Vega Mobile Gfx 
Expression govalues cockroachdb v3.1.2 cockroachdb vs govalues shopspring v1.3.1 shopspring vs govalues
Parse("1234567890.123456789") 108.5n 260.6n +140.30% 556.8n +413.42%
"1234567890.123456789".String() 140.9n 221.7n +57.37% 373.6n +165.21%
2 * 3 18.77n 77.20n +311.43% 165.30n +780.90%
2 + 3 17.09n 58.68n +243.46% 158.05n +825.08%
2 / 4 40.62n 366.90n +803.25% 663.45n +1533.31%
2 / 3 747.6n 970.5n +29.81% 2923.0n +290.96%
1.1^60 1.093µ 3.078µ +181.61% 14.949µ +1267.70%

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

Contributing to the project

The Decimal package is hosted on GitHub. To contribute to the project, follow these steps:

  1. Fork the repository and clone it to your local machine.
  2. Make the desired changes to the code.
  3. Write tests for the changes you made.
  4. Ensure that all tests pass by running go test.
  5. Commit the changes and push them to your fork.
  6. Submit a pull request with a clear description of the changes you made.
  7. Wait for the maintainers to review and merge your changes.

Note: Before making any significant changes to the code, it is recommended to open an issue to discuss the proposed changes with the maintainers. This will help to ensure that the changes align with the project's goals and roadmap.

Documentation

Overview

Package decimal implements immutable decimal floating-point numbers.

This packages is designed specifically for use in transactional financial systems. The amounts involved in financial transactions typically do not exceed 99,999,999,999,999,999.99, so uint64 is used to store decimal coefficients, which reduces heap allocations, lowers memory consumption, and improves performance.

Features

  • Decimal values are immutable, making them safe to use in multiple goroutines.
  • Supports simple, straightforward string representation without scientific or engineering notation.
  • Uses half-even rounding for arithmetic operations, with the ability to panic if significant digits are lost.
  • Does not support special values such as NaN, Infinity, or signed zeros, ensuring that arithmetic operations always produce well-defined results.

Representation

A Decimal value is represented as a struct with three parameters:

  1. Sign: a boolean indicating whether the decimal is negative.
  2. Coefficient: an uint64 value.
  3. Scale: an integer indicating the position of the floating decimal point.

The scale field determines the position of the decimal point in the coefficient. For example, a decimal value with a scale of 2 represents a value that has two digits after the decimal point. The coefficient field is the integer value of the decimal without the decimal point. For example, a decimal with a coefficient of 12345 and a scale of 2 represents the value 123.45. Such approach allows for multiple representations of the same numerical value. For example, 1, 1.0, and 1.00 all represent the same value, but they have different scales and coefficients.

One important aspect of the Decimal is that it does not support special values such as NaN, Infinity, or signed zeros. This makes the representation simpler and more efficient, and it ensures that arithmetic operations always produce well-defined results.

Supported Ranges

The range of a decimal value depends on its scale and the size of its coefficient. Since the coefficient is stored as an uint64, a Decimal can have a maximum of 19 digits. Additionally, the range of the Decimal depends on its scale, which determines the number of decimal places. Here are some examples of ranges supported for frequently used scales:

| Scale | Minimum                              | Maximum                             | Example                    |
| ----- | ------------------------------------ | ----------------------------------- | -------------------------- |
|     0 | -9,999,999,999,999,999,999           | 9,999,999,999,999,999,999           | Japanese Yen               |
|     2 |    -99,999,999,999,999,999.99        |    99,999,999,999,999,999.99        | US Dollar                  |
|     3 |     -9,999,999,999,999,999.999       |     9,999,999,999,999,999.999       | Omani Rial                 |
|     8 |            -99,999,999,999.99999999  |            99,999,999,999.99999999  | Bitcoin                    |
|     9 |             -9,999,999,999.999999999 |             9,999,999,999.999999999 | US Dollar (high-precision) |
|       |                                      |                                     | or Etherium                |

Operations

Arithmetic operations in this package are based on General Decimal Arithmetic and generally involve two steps:

  1. The operation is first performed using only uint64 variables. If no overflow occurs, the result is returned. If an overflow occurs, the operation proceeds to step 2.

  2. The operation is performed again using big.Int variables. The result is rounded to fit into 19 digits. If no significant digits are lost during rounding, the result is returned. If significant digits are lost, a panic is raised.

The purpose of the first step is to optimize the performance of arithmetic operations and reduce memory consumption. Since the coefficient is stored as an uint64, arithmetic operations using only uint64 variables can be performed quickly and efficiently. It is expected that most of the arithmetic operations will be successfully completed during the first step.

The following rules are used to determine the significance of digits:

Rounding

To fit the results of arithmetic operations into 19 digits, the package uses half-to-even rounding, which ensures that rounding errors are evenly distributed between rounding up and rounding down.

In addition to implicit half-to-even rounding, the Decimal package provides several methods for explicit rounding:

  • Decimal.Ceil: rounds towards positive infinity. For example, the ceil of 1.5 is 2.
  • Decimal.Floor: rounds towards negative infinity. For example, the floor of 1.5 is 1.
  • Decimal.Trunc: rounds towards zero. For example, the trunc of 1.5 is 1.
  • Decimal.Round: uses half-to-even rounding.

Errors

Arithmetic operations panic in the following cases:

  1. Out-of-range scale. This error is expected to be very rare as the scale usually comes from a global constant or an established standard, such as ISO 4217. If this error occurs, it suggests a significant bug.

  2. Coefficient overflow. This error occurs when significant digits are lost during rounding to fit 19 digits. This typically happens when dealing with large numbers or when you requested large number of digits after the decimal point to be considered signigicant. Refer to the supported ranges section, if your application needs to handle numbers that are close to the minimum or maximum values, this package may not be suitable. Consider using packages that store coefficients using big.Int type, such as ShopSpring Decimal or CockroachDB Decimal.

  3. Division by zero. This package follows the convention of the standard library and will panic in case of division by zero.

Example (LeibnizPi)

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

package main

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

func main() {
	pi := decimal.New(0, 0)
	dividend := decimal.New(4, 0)
	divisor := decimal.New(1, 0)
	sign := decimal.New(1, 0)
	step := decimal.New(2, 0)
	for i := 0; i < 5000; i++ {
		pi = pi.Add(dividend.Quo(divisor).Mul(sign))
		divisor = divisor.Add(step)
		sign = sign.Neg()
	}
	fmt.Println(pi)
}
Output:

3.141392653591793247
Example (PolishNotation)

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

package main

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

func evaluate(input string) (decimal.Decimal, error) {
	tokens := strings.Fields(input)
	stack := make([]decimal.Decimal, 0, len(tokens))
	for i := len(tokens) - 1; i >= 0; i-- {
		token := tokens[i]
		switch token {
		default:
			d, err := decimal.Parse(token)
			if err != nil {
				return decimal.Decimal{}, fmt.Errorf("invalid decimal: %s", token)
			}
			stack = append(stack, d)
		case "+", "-", "*", "/":
			if len(stack) < 2 {
				return decimal.Decimal{}, fmt.Errorf("invalid input")
			}
			d := stack[len(stack)-2]
			e := stack[len(stack)-1]
			stack = stack[:len(stack)-2]
			var f decimal.Decimal
			switch token {
			case "+":
				f = d.Add(e)
			case "-":
				f = d.Sub(e)
			case "*":
				f = d.Mul(e)
			case "/":
				f = d.Quo(e)
			}
			stack = append(stack, f)
		}
	}
	if len(stack) != 1 {
		return decimal.Decimal{}, fmt.Errorf("invalid input")
	}
	return stack[0], nil
}

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

46.0

Index

Examples

Constants

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

)

Variables

This section is empty.

Functions

This section is empty.

Types

type Decimal

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

Decimal type is a representation of a finite floating-point decimal. It is designed to be safe for concurrent use by multiple goroutines. The zero value for Decimal represents the value 0.

func MustParse

func MustParse(num 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() {
	d := decimal.MustParse("-1.230")
	fmt.Println(d)
}
Output:

-1.230

func New

func New(coef int64, scale int) Decimal

New returns a decimal equal to coef / 10^scale. New panics if scale is less than 0 or greater than MaxScale.

Example
package main

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

func main() {
	d := decimal.New(-1230, 3)
	fmt.Println(d)
}
Output:

-1.230

func Parse

func Parse(num 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 error:

  • if string does not represent a valid decimal number.
  • if integer part of the result has more than MaxPrec digits.
  • if exponent is less than -2 * MaxScale or greater than 2 * MaxScale.
Example
package main

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

func main() {
	d, err := decimal.Parse("-1.230")
	if err != nil {
		panic(err)
	}
	fmt.Println(d)
}
Output:

-1.230

func ParseExact

func ParseExact(num 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 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, err := decimal.ParseExact("-1.2", 5)
	if err != nil {
		panic(err)
	}
	fmt.Println(d)
}
Output:

-1.20000

func (Decimal) Abs

func (d Decimal) Abs() Decimal

Abs returns absolute value of d.

Example
package main

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

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

15.67

func (Decimal) Add

func (d Decimal) Add(e Decimal) Decimal

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

Add panics if the integer part of the sum has more than MaxPrec digits.

Example
package main

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

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

23.6

func (Decimal) AddExact

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

AddExact is similar to Decimal.Add, 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 panic. 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("15.6")
	e := decimal.MustParse("8")
	fmt.Println(d.AddExact(e, 2))
}
Output:

23.60

func (Decimal) Ceil

func (d Decimal) Ceil(scale int) Decimal

Ceil returns d that is rounded up to the specified number of digits after the decimal point. If the scale of d is less than the specified scale, the result will be zero-padded to the right. Also see method Decimal.Floor.

Ceil panics if:

  • the integer part of the result has more than (MaxPrec - scale) digits;
  • the scale is less than 0 or greater than MaxScale.
Example
package main

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

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

15.679000
15.67900
15.6790
15.679
15.68
15.7
16

func (Decimal) Cmp

func (d Decimal) Cmp(e Decimal) int

Cmp compares d and e numerically and returns:

-1 if d < e
 0 if d == e
+1 if d > e
Example
package main

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

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

1
0
-1

func (Decimal) CmpTotal

func (d Decimal) CmpTotal(e Decimal) int

CmpTotal compares representation of d and e and returns:

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

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

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

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

Example
package main

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

func main() {
	d := decimal.MustParse("5.7")
	e := decimal.MustParse("3")
	f := decimal.MustParse("2.8")
	fmt.Println(d.FMA(e, f))
}
Output:

19.9

func (Decimal) FMAExact added in v0.0.3

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

FMAExact is similar to Decimal.FMA, 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 panic. 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")
	f := decimal.MustParse("2.8")
	fmt.Println(d.FMAExact(e, f, 2))
}
Output:

19.90

func (Decimal) Floor

func (d Decimal) Floor(scale int) Decimal

Floor returns d that is rounded down to the specified number of digits after the decimal point. If the scale of d is less than the specified scale, the result will be zero-padded to the right. Also see method Decimal.Ceil.

Floor panics if:

  • the integer part of the result has more than (MaxPrec - scale) digits;
  • the scale is less than 0 or greater than MaxScale.
Example
package main

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

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

15.679000
15.67900
15.6790
15.679
15.67
15.6
15

func (Decimal) Format

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

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

%f, %s, %v: -123.456
%q:        "-123.456"
%k:         -12345.6%

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("-15.679")
	fmt.Printf("%k\n", d)
	fmt.Printf("%f\n", d)
	fmt.Printf("%.2f\n", d)
}
Output:

-1567.9%
-15.679
-15.68

func (Decimal) IsInt

func (d Decimal) IsInt() bool

IsInt returns true if fractional part of d is zero.

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 is less than zero.

Example
package main

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

func main() {
	d := decimal.MustParse("-15.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 is positive one or negative one.

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 is greater than zero.

Example
package main

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

func main() {
	d := decimal.MustParse("-15.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 is zero.

Example
package main

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

func main() {
	d := decimal.MustParse("-15.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) LessThanOne

func (d Decimal) LessThanOne() bool

LessThanOne returns true if d greater than negative one and less than positive one.

Example
package main

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

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

false
true
false

func (Decimal) MarshalText

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

MarshalText implements encoding.TextMarshaler interface. Also see method Decimal.String.

Example
package main

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

func main() {
	d := decimal.MustParse("-15.67")
	b, err := d.MarshalText()
	if err != nil {
		panic(err)
	}
	fmt.Println(string(b))
}
Output:

-15.67

func (Decimal) Max

func (d Decimal) Max(e Decimal) Decimal

Max returns maximum of d and e. Also see method Decimal.CmpTotal

Example
package main

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

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

23

func (Decimal) Min

func (d Decimal) Min(e Decimal) Decimal

Min returns minimum of d and e. Also see method Decimal.CmpTotal

Example
package main

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

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

-15.67

func (Decimal) MinScale

func (d Decimal) MinScale() int

MinScale returns the smallest scale that d can be rescaled to without rounding. Also see method Decimal.Reduce.

Example
package main

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

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

0
2

func (Decimal) Mul

func (d Decimal) Mul(e Decimal) Decimal

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

Mul panics if the integer part of the product 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

func (Decimal) MulExact

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

MulExact is similar to Decimal.Mul, 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 panic. 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, 2))
}
Output:

17.10

func (Decimal) Neg

func (d Decimal) Neg() Decimal

Neg returns d with opposite sign.

Example
package main

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

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

-15.67

func (Decimal) Pow

func (d Decimal) Pow(exp int) Decimal

Pow returns (possibly rounded) d raised to the exp.

Pow panics if the integer part of the power has more than MaxPrec digits.

Example
package main

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

func main() {
	d := decimal.MustParse("2")
	fmt.Println(d.Pow(-3))
	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))
	fmt.Println(d.Pow(3))
}
Output:

0.125
0.25
0.5
1
2
4
8

func (Decimal) Prec

func (d Decimal) Prec() int

Prec returns number of digits in the coefficient.

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 d that is rounded to the same scale as e. The sign and coefficient of y are ignored. Also see method Decimal.Round.

Qunatize panics if the integer part of d has more than (MaxPrec - e.Scale()) digits.

Example
package main

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

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

15.68
15.7
16

func (Decimal) Quo

func (d Decimal) Quo(e Decimal) Decimal

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

Quo panics if:

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

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

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

-7.835

func (Decimal) QuoExact

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

QuoExact is similar to Decimal.Quo, 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 panic. 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("-15.67")
	e := decimal.MustParse("2")
	fmt.Println(d.QuoExact(e, 6))
}
Output:

-7.835000

func (Decimal) QuoRem

func (d Decimal) QuoRem(e Decimal) (Decimal, Decimal)

QuoRem returns the quotient and remainder of d and e such that d = q * e + r.

QuoRem panics if:

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

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

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

-7 -1.67

func (Decimal) Reduce

func (d Decimal) Reduce() Decimal

Reduce returns d with all trailing zeros removed.

Example
package main

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

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

23
-15.67

func (Decimal) Round

func (d Decimal) Round(scale int) Decimal

Round returns d that is rounded to the specified number of digits after the decimal point. If the scale of d is less than the specified scale, the result will be zero-padded to the right. For financial calculations, the scale should be equal to or greater than the scale of the currency.

Round panics if:

  • the integer part of the result has more than (MaxPrec - scale) digits;
  • the scale is less than 0 or greater than MaxScale.
Example
package main

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

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

15.679000
15.67900
15.6790
15.679
15.68
15.7
16

func (Decimal) Scale

func (d Decimal) Scale() int

Scale returns number of digits after the decimal point.

Example
package main

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

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

4
3

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("-15.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 method implements the fmt.Stringer interface and returns a string representation of a decimal value. 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
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

Sub returns (possibly rounded) difference of d and e.

Sub panics if the integer part of the difference has more than MaxPrec digits.

Example
package main

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

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

7.6

func (Decimal) SubExact

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

SubExact is similar to Decimal.Sub, 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 panic. 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("15.6")
	e := decimal.MustParse("8")
	fmt.Println(d.SubExact(e, 2))
}
Output:

7.60

func (Decimal) Trunc

func (d Decimal) Trunc(scale int) Decimal

Trunc returns d that is truncated to the specified number of digits after the decimal point. If the scale of d is less than the specified scale, the result will be zero-padded to the right. Also see method Decimal.Reduce.

Trunc panics if:

  • the integer part of the result has more than (MaxPrec - scale) digits;
  • the scale is less than 0 or greater than MaxScale.
Example
package main

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

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

15.679000
15.67900
15.6790
15.679
15.67
15.6
15

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 d and the next larger decimal value with the same number of digits.

Example
package main

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

func main() {
	d := decimal.MustParse("-1.23")
	e := decimal.MustParse("0.0")
	f := decimal.MustParse("15")
	fmt.Println(d.ULP())
	fmt.Println(e.ULP())
	fmt.Println(f.ULP())
}
Output:

0.01
0.1
1

func (*Decimal) UnmarshalText

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

UnmarshalText implements encoding.TextUnmarshaler interface. Also see method Parse.

Example
package main

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

func main() {
	d := &decimal.Decimal{}
	b := []byte("-15.67")
	err := d.UnmarshalText(b)
	if err != nil {
		panic(err)
	}
	fmt.Println(d)
}
Output:

-15.67

func (Decimal) WithScale

func (d Decimal) WithScale(scale int) Decimal

WithScale returns d with specified scale. Also see method Decimal.Round.

WithScale panics if the scale is less than 0 or greater than MaxScale.

Example
package main

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

func main() {
	d := decimal.MustParse("15.679")
	fmt.Println(d.WithScale(6))
	fmt.Println(d.WithScale(5))
	fmt.Println(d.WithScale(4))
	fmt.Println(d.WithScale(3))
	fmt.Println(d.WithScale(2))
	fmt.Println(d.WithScale(1))
	fmt.Println(d.WithScale(0))
}
Output:

0.015679
0.15679
1.5679
15.679
156.79
1567.9
15679

Jump to

Keyboard shortcuts

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