Decimal (Decimal v2.0.0) View Source

Decimal arithmetic on arbitrary precision floating-point numbers.

A number is represented by a signed coefficient and exponent such that: sign * coefficient * 10 ^ exponent. All numbers are represented and calculated exactly, but the result of an operation may be rounded depending on the context the operation is performed with, see: Decimal.Context. Trailing zeros in the coefficient are never truncated to preserve the number of significant digits unless explicitly done so.

There are also special values such as NaN (not a number) and ±Infinity. -0 and +0 are two distinct values. Some operation results are not defined and will return NaN. This kind of NaN is quiet, any operation returning a number will return NaN when given a quiet NaN (the NaN value will flow through all operations).

Exceptional conditions are grouped into signals, each signal has a flag and a trap enabler in the context. Whenever a signal is triggered it's flag is set in the context and will be set until explicitly cleared. If the signal is trap enabled Decimal.Error will be raised.

Specifications

This library follows the above specifications for reference of arithmetic operation implementations, but the public APIs may differ to provide a more idiomatic Elixir interface.

The specification models the sign of the number as 1, for a negative number, and 0 for a positive number. Internally this implementation models the sign as 1 or -1 such that the complete number will be sign * coefficient * 10 ^ exponent and will refer to the sign in documentation as either positive or negative.

There is currently no maximum or minimum values for the exponent. Because of that all numbers are "normal". This means that when an operation should, according to the specification, return a number that "underflows" 0 is returned instead of Etiny. This may happen when dividing a number with infinity. Additionally, overflow, underflow and clamped may never be signalled.

Link to this section Summary

Types

The coefficient of the power of 10. Non-negative because the sign is stored separately in sign.

The exponent to which 10 is raised.

Rounding algorithm.

  • 1 for positive
  • -1 for negative
t()

This implementation models the sign as 1 or -1 such that the complete number will be: sign * coef * 10 ^ exp.

Functions

The absolute value of given number. Sets the number's sign to positive.

Adds two numbers together.

Applies the context to the given number rounding it to specified precision.

Creates a new decimal number from an integer, string, float, or existing decimal number.

cmp(num1, num2) deprecated

Compares two numbers numerically. If the first number is greater than the second :gt is returned, if less than :lt is returned, if both numbers are equal :eq is returned.

Divides two numbers.

Divides two numbers and returns the integer part.

Integer division of two numbers and the remainder. Should be used when both div_int/2 and rem/2 is needed. Equivalent to: {Decimal.div_int(x, y), Decimal.rem(x, y)}.

Compares two numbers numerically and returns true if they are equal, otherwise false. If one of the operands is a quiet NaN this operation will always return false.

Compares two numbers numerically and returns true if they are equal, otherwise false. If one of the operands is a quiet NaN this operation will always return false.

Creates a new decimal number from a floating point number.

Compares two numbers numerically and returns true if the the first argument is greater than the second, otherwise false. If one the operands is a quiet NaN this operation will always return false.

Returns true if number is ±Infinity, otherwise false.

Returns true when the given decimal has no significant digits after the decimal point.

Returns true if argument is a decimal number, otherwise false.

Compares two numbers numerically and returns true if the the first number is less than the second number, otherwise false. If one of the operands is a quiet NaN this operation will always return false.

Compares two values numerically and returns the maximum. Unlike most other functions in Decimal if a number is NaN the result will be the other number. Only if both numbers are NaN will NaN be returned.

Compares two values numerically and returns the minimum. Unlike most other functions in Decimal if a number is NaN the result will be the other number. Only if both numbers are NaN will NaN be returned.

Multiplies two numbers.

Returns true if number is NaN, otherwise false.

Negates the given number.

Check if given number is negative

Creates a new decimal number from an integer or a string representation.

Creates a new decimal number from the sign, coefficient and exponent such that the number will be: sign * coefficient * 10 ^ exponent.

Normalizes the given decimal: removes trailing zeros from coefficient while keeping the number numerically equivalent by increasing the exponent.

Parses a binary into a decimal.

Check if given number is positive

Remainder of integer division of two numbers. The result will have the sign of the first number.

Rounds the given number to specified decimal places with the given strategy (default is to round to nearest one). If places is negative, at least that many digits to the left of the decimal point will be zero.

Finds the square root.

Subtracts second number from the first. Equivalent to Decimal.add/2 when the second number's sign is negated.

Returns the decimal converted to a float.

Returns the decimal represented as an integer.

Converts given number to its string representation.

Link to this section Types

Specs

coefficient() :: non_neg_integer() | :NaN | :inf

The coefficient of the power of 10. Non-negative because the sign is stored separately in sign.

  • non_neg_integer - when the t represents a number, instead of one of the special values below.
  • :NaN - Not a Number.
  • :inf - Infinity.

Specs

decimal() :: t() | integer() | String.t()

Specs

exponent() :: integer()

The exponent to which 10 is raised.

Specs

rounding() ::
  :down | :half_up | :half_even | :ceiling | :floor | :half_down | :up

Rounding algorithm.

See Decimal.Context for more information.

Specs

sign() :: 1 | -1
  • 1 for positive
  • -1 for negative

Specs

signal() :: :invalid_operation | :division_by_zero | :rounded | :inexact

Specs

t() :: %Decimal{coef: coefficient(), exp: exponent(), sign: sign()}

This implementation models the sign as 1 or -1 such that the complete number will be: sign * coef * 10 ^ exp.

  • coef - the coefficient of the power of 10.
  • exp - the exponent of the power of 10.
  • sign - 1 for positive, -1 for negative.

Link to this section Functions

Specs

abs(t()) :: t()

The absolute value of given number. Sets the number's sign to positive.

Specs

add(decimal(), decimal()) :: t()

Adds two numbers together.

Exceptional conditions

  • If one number is -Infinity and the other +Infinity, :invalid_operation will be signalled.

Examples

iex> Decimal.add(1, "1.1")
#Decimal<2.1>

iex> Decimal.add(1, "Inf")
#Decimal<Infinity>
Link to this function

apply_context(num)

View Source (since 1.9.0)

Specs

apply_context(t()) :: t()

Applies the context to the given number rounding it to specified precision.

Specs

cast(term()) :: {:ok, t()} | :error

Creates a new decimal number from an integer, string, float, or existing decimal number.

Because conversion from a floating point number is not exact, it's recommended to instead use new/1 or from_float/1 when the argument's type is certain. See from_float/1.

Examples

iex> {:ok, decimal} = Decimal.cast(3)
iex> decimal
#Decimal<3>

iex> Decimal.cast("bad")
:error
This function is deprecated. Use compare/2 instead.

Specs

cmp(decimal(), decimal()) :: :lt | :eq | :gt

Specs

compare(decimal(), decimal()) :: :lt | :gt | :eq

Compares two numbers numerically. If the first number is greater than the second :gt is returned, if less than :lt is returned, if both numbers are equal :eq is returned.

Neither number can be a NaN.

Examples

iex> Decimal.compare("1.0", 1)
:eq

iex> Decimal.compare("Inf", -1)
:gt

Specs

div(decimal(), decimal()) :: t()

Divides two numbers.

Exceptional conditions

  • If both numbers are ±Infinity :invalid_operation is signalled.
  • If both numbers are ±0 :invalid_operation is signalled.
  • If second number (denominator) is ±0 :division_by_zero is signalled.

Examples

iex> Decimal.div(3, 4)
#Decimal<0.75>

iex> Decimal.div("Inf", -1)
#Decimal<-Infinity>

Specs

div_int(decimal(), decimal()) :: t()

Divides two numbers and returns the integer part.

Exceptional conditions

  • If both numbers are ±Infinity :invalid_operation is signalled.
  • If both numbers are ±0 :invalid_operation is signalled.
  • If second number (denominator) is ±0 :division_by_zero is signalled.

Examples

iex> Decimal.div_int(5, 2)
#Decimal<2>

iex> Decimal.div_int("Inf", -1)
#Decimal<-Infinity>

Specs

div_rem(decimal(), decimal()) :: {t(), t()}

Integer division of two numbers and the remainder. Should be used when both div_int/2 and rem/2 is needed. Equivalent to: {Decimal.div_int(x, y), Decimal.rem(x, y)}.

Exceptional conditions

  • If both numbers are ±Infinity :invalid_operation is signalled.
  • If both numbers are ±0 :invalid_operation is signalled.
  • If second number (denominator) is ±0 :division_by_zero is signalled.

Examples

iex> Decimal.div_rem(5, 2)
{Decimal.new(2), Decimal.new(1)}
Link to this function

eq?(num1, num2)

View Source (since 1.8.0)

Specs

eq?(decimal(), decimal()) :: boolean()

Compares two numbers numerically and returns true if they are equal, otherwise false. If one of the operands is a quiet NaN this operation will always return false.

Examples

iex> Decimal.eq?("1.0", 1)
true

iex> Decimal.eq?(1, -1)
false

Specs

equal?(decimal(), decimal()) :: boolean()

Compares two numbers numerically and returns true if they are equal, otherwise false. If one of the operands is a quiet NaN this operation will always return false.

Examples

iex> Decimal.equal?("1.0", 1)
true

iex> Decimal.equal?(1, -1)
false
Link to this function

from_float(float)

View Source (since 1.5.0)

Specs

from_float(float()) :: t()

Creates a new decimal number from a floating point number.

Floating point numbers use a fixed number of binary digits to represent a decimal number which has inherent inaccuracy as some decimal numbers cannot be represented exactly in limited precision binary.

Floating point numbers will be converted to decimal numbers with :io_lib_format.fwrite_g/1. Since this conversion is not exact and because of inherent inaccuracy mentioned above, we may run into counter-intuitive results:

iex> Enum.reduce([0.1, 0.1, 0.1], &+/2)
0.30000000000000004

iex> Enum.reduce([Decimal.new("0.1"), Decimal.new("0.1"), Decimal.new("0.1")], &Decimal.add/2)
#Decimal<0.3>

For this reason, it's recommended to build decimals with new/1, which is always precise, instead.

Examples

iex> Decimal.from_float(3.14)
#Decimal<3.14>
Link to this function

gt?(num1, num2)

View Source (since 1.8.0)

Specs

gt?(decimal(), decimal()) :: boolean()

Compares two numbers numerically and returns true if the the first argument is greater than the second, otherwise false. If one the operands is a quiet NaN this operation will always return false.

Examples

iex> Decimal.gt?("1.3", "1.2")
true

iex> Decimal.gt?("1.2", "1.3")
false

Specs

inf?(t()) :: boolean()

Returns true if number is ±Infinity, otherwise false.

Link to this function

integer?(num)

View Source (since 2.0.0)

Specs

integer?(t()) :: boolean()

Returns true when the given decimal has no significant digits after the decimal point.

Examples

iex> Decimal.integer?("1.00")
true

iex> Decimal.integer?("1.10")
false
Link to this macro

is_decimal(term)

View Source (macro) (since 1.9.0)

Returns true if argument is a decimal number, otherwise false.

Examples

iex> Decimal.is_decimal(Decimal.new(42))
true

iex> Decimal.is_decimal(42)
false

Allowed in guard tests on OTP 21+.

Link to this function

lt?(num1, num2)

View Source (since 1.8.0)

Specs

lt?(decimal(), decimal()) :: boolean()

Compares two numbers numerically and returns true if the the first number is less than the second number, otherwise false. If one of the operands is a quiet NaN this operation will always return false.

Examples

iex> Decimal.lt?("1.1", "1.2")
true

iex> Decimal.lt?("1.4", "1.2")
false

Specs

max(decimal(), decimal()) :: t()

Compares two values numerically and returns the maximum. Unlike most other functions in Decimal if a number is NaN the result will be the other number. Only if both numbers are NaN will NaN be returned.

Examples

iex> Decimal.max(1, "2.0")
#Decimal<2.0>

iex> Decimal.max(1, "NaN")
#Decimal<1>

iex> Decimal.max("NaN", "NaN")
#Decimal<NaN>

Specs

min(decimal(), decimal()) :: t()

Compares two values numerically and returns the minimum. Unlike most other functions in Decimal if a number is NaN the result will be the other number. Only if both numbers are NaN will NaN be returned.

Examples

iex> Decimal.min(1, "2.0")
#Decimal<1>

iex> Decimal.min(1, "NaN")
#Decimal<1>

iex> Decimal.min("NaN", "NaN")
#Decimal<NaN>

Specs

mult(decimal(), decimal()) :: t()

Multiplies two numbers.

Exceptional conditions

  • If one number is ±0 and the other is ±Infinity :invalid_operation is signalled.

Examples

iex> Decimal.mult("0.5", 3)
#Decimal<1.5>

iex> Decimal.mult("Inf", -1)
#Decimal<-Infinity>

Specs

nan?(t()) :: boolean()

Returns true if number is NaN, otherwise false.

Link to this function

negate(num)

View Source (since 1.9.0)

Specs

negate(decimal()) :: t()

Negates the given number.

Examples

iex> Decimal.negate(1)
#Decimal<-1>

iex> Decimal.negate("-Inf")
#Decimal<Infinity>
Link to this function

negative?(decimal)

View Source (since 1.5.0)

Specs

negative?(t()) :: boolean()

Check if given number is negative

Specs

new(decimal()) :: t()

Creates a new decimal number from an integer or a string representation.

A decimal number will always be created exactly as specified with all digits kept - it will not be rounded with the context.

Backus–Naur form

sign           ::=  "+" | "-"
digit          ::=  "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
indicator      ::=  "e" | "E"
digits         ::=  digit [digit]...
decimal-part   ::=  digits "." [digits] | ["."] digits
exponent-part  ::=  indicator [sign] digits
infinity       ::=  "Infinity" | "Inf"
nan            ::=  "NaN" [digits]
numeric-value  ::=  decimal-part [exponent-part] | infinity
numeric-string ::=  [sign] numeric-value | [sign] nan

Floats

See also from_float/1.

Examples

iex> Decimal.new(1)
#Decimal<1>

iex> Decimal.new("3.14")
#Decimal<3.14>

Specs

new(1 | -1, non_neg_integer() | :NaN | :inf, integer()) :: t()

Creates a new decimal number from the sign, coefficient and exponent such that the number will be: sign * coefficient * 10 ^ exponent.

A decimal number will always be created exactly as specified with all digits kept - it will not be rounded with the context.

Link to this function

normalize(num)

View Source (since 1.9.0)

Specs

normalize(t()) :: t()

Normalizes the given decimal: removes trailing zeros from coefficient while keeping the number numerically equivalent by increasing the exponent.

Examples

iex> Decimal.normalize(Decimal.new("1.00"))
#Decimal<1>

iex> Decimal.normalize(Decimal.new("1.01"))
#Decimal<1.01>

Specs

parse(binary()) :: {t(), binary()} | :error

Parses a binary into a decimal.

If successful, returns a tuple in the form of {decimal, remainder_of_binary}, otherwise :error.

Examples

iex> Decimal.parse("3.14")
{%Decimal{coef: 314, exp: -2, sign: 1}, ""}

iex> Decimal.parse("3.14.15")
{%Decimal{coef: 314, exp: -2, sign: 1}, ".15"}

iex> Decimal.parse("-1.1e3")
{%Decimal{coef: 11, exp: 2, sign: -1}, ""}

iex> Decimal.parse("bad")
:error
Link to this function

positive?(decimal)

View Source (since 1.5.0)

Specs

positive?(t()) :: boolean()

Check if given number is positive

Specs

rem(decimal(), decimal()) :: t()

Remainder of integer division of two numbers. The result will have the sign of the first number.

Exceptional conditions

  • If both numbers are ±Infinity :invalid_operation is signalled.
  • If both numbers are ±0 :invalid_operation is signalled.
  • If second number (denominator) is ±0 :division_by_zero is signalled.

Examples

iex> Decimal.rem(5, 2)
#Decimal<1>
Link to this function

round(num, places \\ 0, mode \\ :half_up)

View Source

Specs

round(decimal(), integer(), rounding()) :: t()

Rounds the given number to specified decimal places with the given strategy (default is to round to nearest one). If places is negative, at least that many digits to the left of the decimal point will be zero.

See Decimal.Context for more information about rounding algorithms.

Examples

iex> Decimal.round("1.234")
#Decimal<1>

iex> Decimal.round("1.234", 1)
#Decimal<1.2>

Specs

sqrt(decimal()) :: t()

Finds the square root.

Examples

iex> Decimal.sqrt("100")
#Decimal<10>

Specs

sub(decimal(), decimal()) :: t()

Subtracts second number from the first. Equivalent to Decimal.add/2 when the second number's sign is negated.

Exceptional conditions

  • If one number is -Infinity and the other +Infinity :invalid_operation will be signalled.

Examples

iex> Decimal.sub(1, "0.1")
#Decimal<0.9>

iex> Decimal.sub(1, "Inf")
#Decimal<-Infinity>

Specs

to_float(t()) :: float()

Returns the decimal converted to a float.

The returned float may have lower precision than the decimal. Fails if the decimal cannot be converted to a float.

Specs

to_integer(t()) :: integer()

Returns the decimal represented as an integer.

Fails when loss of precision will occur.

Link to this function

to_string(num, type \\ :scientific)

View Source

Specs

to_string(t(), :scientific | :normal | :xsd | :raw) :: String.t()

Converts given number to its string representation.

Options

  • :scientific - number converted to scientific notation.
  • :normal - number converted without a exponent.
  • :xsd - number converted to the canonical XSD representation.
  • :raw - number converted to its raw, internal format.