Decimal v1.5.0 Decimal 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). The other kind of NaN is signalling which is the value that can be reached in result field on Decimal.Error when the result is NaN. Any operation given a signalling NaN return will signal :invalid_operation.

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 implementation follows the above standards as closely as possible. But at some places the implementation diverges from the specification. The reasons are different for each case but may be that the specification doesn’t map to this environment, ease of implementation or that API will be nicer. Still, the implementation is close enough that the specifications can be seen as additional documentation that can be used when things are unclear.

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 “underflow” 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

  • 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

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

Compares two numbers numerically. If the first number is greater than the second #Decimal<1> is returned, if less than #Decimal<-1> is returned. Otherwise, if both numbers are equal #Decimal<0> is returned. If either number is a quiet NaN, then that number is returned

Returns true if argument is a decimal number, otherwise false

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

Creates a new decimal number from a floating point number

Gets the process’ context

Returns true if number is ±Infinity, otherwise 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

Negates the given number

Multiplies two numbers

Returns true if number is NaN, otherwise false

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

Parses a binary into a decimal

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

Check if given number is positive

Reduces the given number. Removes trailing zeros from coefficient while keeping the number numerically equivalent by increasing the exponent

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

Set the process’ context

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

Update the process’ context

Runs function with given context

Link to this section Types

Link to this type coefficient() View Source
coefficient() :: non_neg_integer() | :qNaN | :sNaN | :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.
  • :qNaN - a quiet NaN was produced by a previous operation. Quiet NaNs propagate quietly, unlike signaling NaNs that return errors (based on the Decimal.Context).
  • :sNaN - signalling NaN that indicated an error occurred that should stop the next operation with an error (based on the Decimal.Context).
  • :inf - Infinity.
Link to this type decimal() View Source
decimal() :: t() | integer() | String.t()
Link to this type exponent() View Source
exponent() :: integer()

The exponent to which 10 is raised.

Link to this type rounding() View Source
rounding() ::
  :down | :half_up | :half_even | :ceiling | :floor | :half_down | :up
Link to this type sign() View Source
sign() :: 1 | -1
  • 1 for positive
  • -1 for negative
Link to this type signal() View Source
signal() :: :invalid_operation | :division_by_zero | :rounded | :inexact
Link to this type t() View Source
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

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

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 cmp(num1, num2) View Source
cmp(decimal(), decimal()) :: :lt | :eq | :gt

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. If you need to handle quiet NaNs, use compare/2.

Examples

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

iex> Decimal.cmp("Inf", -1)
:gt
Link to this function compare(num1, num2) View Source
compare(decimal(), decimal()) :: t()

Compares two numbers numerically. If the first number is greater than the second #Decimal<1> is returned, if less than #Decimal<-1> is returned. Otherwise, if both numbers are equal #Decimal<0> is returned. If either number is a quiet NaN, then that number is returned.

Examples

iex> Decimal.compare("1.0", 1)
#Decimal<0>

iex> Decimal.compare("Inf", -1)
#Decimal<1>
Link to this function decimal?(arg1) View Source
decimal?(any()) :: boolean()

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

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>
Link to this function div_int(num1, num2) View Source
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>
Link to this function div_rem(num1, num2) View Source
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 equal?(num1, num2) View Source
equal?(decimal(), decimal()) :: boolean()

Compares two numbers numerically and returns true if they are equal, otherwise false.

Examples

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

iex> Decimal.equal?(1, -1)
false
Link to this function from_float(float) View Source
from_float(float()) :: t()

Creates a new decimal number from a floating point number.

Floating point numbers will be converted to decimal numbers with :io_lib_format.fwrite_g/1. Since this conversion is not exact it is recommended to give an integer or a string via new/1 instead.

Examples

iex> Decimal.from_float(3.14)
#Decimal<3.14>

Gets the process’ context.

Returns true if number is ±Infinity, otherwise 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.

Examples

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

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

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

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>

Negates the given number.

Examples

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

iex> Decimal.minus("-Inf")
#Decimal<Infinity>
Link to this function mult(num1, num2) View Source
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>

Returns true if number is NaN, otherwise false.

Link to this function negative?(num) View Source
negative?(t()) :: t()

Check if given number is negative

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] | "sNaN" [digits]
numeric-value  ::=  decimal-part [exponent-part] | infinity
numeric-string ::=  [sign] numeric-value | [sign] nan

Examples

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

iex> Decimal.new("3.14")
#Decimal<3.14>
Link to this function new(sign, coefficient, exponent) View Source
new(1 | -1, non_neg_integer() | :qNaN | :sNaN | :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 parse(binary) View Source
parse(String.t()) :: {:ok, t()} | :error

Parses a binary into a decimal.

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

Examples

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

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

iex> Decimal.parse("bad")
:error

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

Link to this function positive?(num) View Source
positive?(t()) :: t()

Check if given number is positive

Link to this function reduce(num) View Source
reduce(t()) :: t()

Reduces the given number. Removes trailing zeros from coefficient while keeping the number numerically equivalent by increasing the exponent.

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

Examples

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

iex> Decimal.round("1.234", 1)
#Decimal<1.2>
Link to this function set_context(context) View Source
set_context(Decimal.Context.t()) :: :ok

Set the process’ context.

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>
Link to this function to_float(decimal) View Source
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.

Link to this function to_integer(decimal) View Source
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
to_string(t(), :scientific | :normal | :raw) :: String.t()

Converts given number to its string representation.

Options

  • :scientific - number converted to scientific notation.
  • :normal - number converted without a exponent.
  • :raw - number converted to its raw, internal format.
Link to this function update_context(fun) View Source
update_context((Decimal.Context.t() -> Decimal.Context.t())) :: :ok

Update the process’ context.

Link to this function with_context(context, fun) View Source
with_context(Decimal.Context.t(), (() -> x)) :: x when x: var

Runs function with given context.