Decimal

Decimal arithmetic on arbitrary precision floating-point numbers.

A number is represented by a signed coefficient and exponent such that: `sign

There are also special values such as NaN and (+-)Infinity. -0 and +0 are two distinct values. Some operations 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 Error.result/1 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.

Source

Summary

abs(num)

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

add(num1, decimal)

Adds two numbers together

compare(num1, num2)

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

decimal?(decimal)

Returns true if argument is a decimal number; otherwise false

div(num1, decimal)

Divides two numbers

div_int(num1, num2)

Divides two numbers and returns the integer part

div_rem(num1, decimal)

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

equal?(num1, num2)

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

get_context()

Gets the process’ context

inf?(decimal)

Returns true if number is (+-)Infinity; otherwise false

max(decimal, num2)

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

min(decimal, num2)

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

minus(num)

Negates the given number

mult(num1, decimal)

Multiplies two numbers

nan?(decimal)

Returns true if number is NaN; otherwise false

new(num)

Creates a new decimal number from a string representation, an integer or 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 when possible

new(sign, coefficient, exponent)

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

plus(num)

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

reduce(num)

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

rem(num1, num2)

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

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

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_context(context)

Set the process’ context

sub(num1, num2)

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

to_string(num, type \\ :scientific)

Converts given number to its string representation

update_context(fun)

Update the process’ context

with_context(context, fun)

Runs function with given context

Types

signal :: :invalid_operation | :division_by_zero | :rounded | :inexact

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

t :: %Decimal{sign: 1 | -1, coef: non_neg_integer | :qNaN | :sNaN | :inf, exp: integer}

Functions

abs(num)

Specs:

  • abs(t) :: t

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

Source
add(num1, decimal)

Specs:

  • add(t, t) :: t

Adds two numbers together.

Exceptional conditions

  • If one number is -Infinity and the other +Infinity :invalid_operation will be signalled.
Source
compare(num1, num2)

Specs:

  • compare(t, t) :: 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.

Source
decimal?(decimal)

Specs:

  • decimal?(any) :: boolean

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

Source
div(num1, decimal)

Specs:

  • div(t, t) :: 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.
Source
div_int(num1, num2)

Specs:

  • div_int(t, t) :: 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.
Source
div_rem(num1, decimal)

Specs:

  • div_rem(t, t) :: {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.
Source
equal?(num1, num2)

Specs:

  • equal?(t, t) :: boolean

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

Source
get_context()

Specs:

Gets the process’ context.

Source
inf?(decimal)

Specs:

  • inf?(t) :: boolean

Returns true if number is (+-)Infinity; otherwise false.

Source
max(decimal, num2)

Specs:

  • max(t, t) :: 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.

Source
min(decimal, num2)

Specs:

  • min(t, t) :: 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.

Source
minus(num)

Specs:

  • minus(t) :: t

Negates the given number.

Source
mult(num1, decimal)

Specs:

  • mult(t, t) :: t

Multiplies two numbers.

Exceptional conditions

  • If one number is (+-0) and the other is (+-)Infinity :invalid_operation is signalled.
Source
nan?(decimal)

Specs:

  • nan?(t) :: boolean

Returns true if number is NaN; otherwise false.

Source
new(num)

Specs:

Creates a new decimal number from a string representation, an integer or 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 when possible.

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

BNFC

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
Source
new(sign, coefficient, exponent)

Specs:

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

Source
plus(num)

Specs:

  • plus(t) :: t

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

Source
reduce(num)

Specs:

  • reduce(t) :: t

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

Source
rem(num1, num2)

Specs:

  • rem(t, t) :: 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.
Source
round(num, places \\ 0, mode \\ :half_up)

Specs:

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.

Source
set_context(context)

Specs:

Set the process’ context.

Source
sub(num1, num2)

Specs:

  • sub(t, t) :: 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.
Source
to_string(num, type \\ :scientific)

Specs:

  • 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 it’s raw, internal format.
Source
update_context(fun)

Specs:

Update the process’ context.

Source
with_context(context, fun)

Specs:

Runs function with given context.

Source